diff options
-rw-r--r-- | include/ipmitool/Makefile.am | 2 | ||||
-rw-r--r-- | include/ipmitool/ipmi_intf.h | 1 | ||||
-rw-r--r-- | include/ipmitool/ipmi_vita.h | 49 | ||||
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/ipmi_main.c | 32 | ||||
-rw-r--r-- | lib/ipmi_picmg.c | 64 | ||||
-rw-r--r-- | lib/ipmi_vita.c | 1006 | ||||
-rw-r--r-- | src/ipmitool.c | 2 |
8 files changed, 1119 insertions, 39 deletions
diff --git a/include/ipmitool/Makefile.am b/include/ipmitool/Makefile.am index 925881e..5a9062c 100644 --- a/include/ipmitool/Makefile.am +++ b/include/ipmitool/Makefile.am @@ -38,5 +38,5 @@ noinst_HEADERS = log.h bswap.h hpm2.h helper.h ipmi.h ipmi_cc.h ipmi_intf.h \ ipmi_oem.h ipmi_sdradd.h ipmi_isol.h ipmi_sunoem.h ipmi_picmg.h \ ipmi_fwum.h ipmi_main.h ipmi_tsol.h ipmi_firewall.h \ ipmi_kontronoem.h ipmi_ekanalyzer.h ipmi_gendev.h ipmi_ime.h \ - ipmi_delloem.h ipmi_dcmi.h + ipmi_delloem.h ipmi_dcmi.h ipmi_vita.h diff --git a/include/ipmitool/ipmi_intf.h b/include/ipmitool/ipmi_intf.h index f9f6592..6b6e247 100644 --- a/include/ipmitool/ipmi_intf.h +++ b/include/ipmitool/ipmi_intf.h @@ -168,6 +168,7 @@ struct ipmi_intf { int abort; int noanswer; int picmg_avail; + int vita_avail; IPMI_OEM manufacturer_id; struct ipmi_session * session; diff --git a/include/ipmitool/ipmi_vita.h b/include/ipmitool/ipmi_vita.h new file mode 100644 index 0000000..71d471a --- /dev/null +++ b/include/ipmitool/ipmi_vita.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) Pigeon Point Systems. All right reserved + */ + +#ifndef _IPMI_VITA_H_ +#define _IPMI_VITA_H_ + +/* VITA 46.11 commands */ +#define VITA_GET_VSO_CAPABILITIES_CMD 0x00 +#define VITA_FRU_CONTROL_CMD 0x04 +#define VITA_GET_FRU_LED_PROPERTIES_CMD 0x05 +#define VITA_GET_LED_COLOR_CAPABILITIES_CMD 0x06 +#define VITA_SET_FRU_LED_STATE_CMD 0x07 +#define VITA_GET_FRU_LED_STATE_CMD 0x08 +#define VITA_SET_FRU_STATE_POLICY_BITS_CMD 0x0A +#define VITA_GET_FRU_STATE_POLICY_BITS_CMD 0x0B +#define VITA_SET_FRU_ACTIVATION_CMD 0x0C +#define VITA_GET_FRU_ADDRESS_INFO_CMD 0x40 + +/* VITA 46.11 site types */ +#define VITA_FRONT_VPX_MODULE 0x00 +#define VITA_POWER_ENTRY 0x01 +#define VITA_CHASSIS_FRU 0x02 +#define VITA_DEDICATED_CHMC 0x03 +#define VITA_FAN_TRAY 0x04 +#define VITA_FAN_TRAY_FILTER 0x05 +#define VITA_ALARM_PANEL 0x06 +#define VITA_XMC 0x07 +#define VITA_VPX_RTM 0x09 +#define VITA_FRONT_VME_MODULE 0x0A +#define VITA_FRONT_VXS_MODULE 0x0B +#define VITA_POWER_SUPPLY 0x0C +#define VITA_FRONT_VITA62_MODULE 0x0D +#define VITA_71_MODULE 0x0E +#define VITA_FMC 0x0F + + +#define GROUP_EXT_VITA 0x03 + +extern uint8_t +vita_discover(struct ipmi_intf *intf); + +extern uint8_t +ipmi_vita_ipmb_address(struct ipmi_intf *intf); + +extern int +ipmi_vita_main(struct ipmi_intf * intf, int argc, char ** argv); + +#endif /* _IPMI_VITA_H_ */ diff --git a/lib/Makefile.am b/lib/Makefile.am index d878b11..2a316db 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -39,7 +39,7 @@ libipmitool_la_SOURCES = helper.c ipmi_sdr.c ipmi_sel.c ipmi_sol.c ipmi_pef.c \ ipmi_oem.c ipmi_isol.c ipmi_sunoem.c ipmi_fwum.c ipmi_picmg.c \ ipmi_main.c ipmi_tsol.c ipmi_firewall.c ipmi_kontronoem.c \ ipmi_hpmfwupg.c ipmi_sdradd.c ipmi_ekanalyzer.c ipmi_gendev.c \ - ipmi_ime.c ipmi_delloem.c ipmi_dcmi.c hpm2.c \ + ipmi_ime.c ipmi_delloem.c ipmi_dcmi.c hpm2.c ipmi_vita.c \ ../src/plugins/lan/md5.c ../src/plugins/lan/md5.h libipmitool_la_LDFLAGS = -export-dynamic diff --git a/lib/ipmi_main.c b/lib/ipmi_main.c index 26f3457..0f01001 100644 --- a/lib/ipmi_main.c +++ b/lib/ipmi_main.c @@ -344,6 +344,18 @@ ipmi_parse_hex(const char *str) return out; } +static uint8_t +ipmi_acquire_ipmb_address(struct ipmi_intf * intf) +{ + if (intf->picmg_avail) { + return ipmi_picmg_ipmb_address(intf); + } else if (intf->vita_avail) { + return ipmi_vita_ipmb_address(intf); + } else { + return 0; + } +} + /* ipmi_parse_options - helper function to handle parsing command line options * * @argc: count of options @@ -907,14 +919,22 @@ ipmi_main(int argc, char ** argv, } } /* - * Attempt picmg discovery of the actual interface address unless + * Attempt picmg/vita discovery of the actual interface address unless * the users specified an address. * Address specification always overrides discovery */ - if (picmg_discover(ipmi_main_intf) && !arg_addr) { - lprintf(LOG_DEBUG, "Running PICMG Get Address Info"); - addr = ipmi_picmg_ipmb_address(ipmi_main_intf); - lprintf(LOG_INFO, "Discovered IPMB-0 address 0x%x", addr); + if (picmg_discover(ipmi_main_intf)) { + ipmi_main_intf->picmg_avail = 1; + } else if (vita_discover(ipmi_main_intf)) { + ipmi_main_intf->vita_avail = 1; + } + + if (arg_addr) { + addr = arg_addr; + } else { + lprintf(LOG_DEBUG, "Acquire IPMB address"); + addr = ipmi_acquire_ipmb_address(ipmi_main_intf); + lprintf(LOG_INFO, "Discovered IPMB address 0x%x", addr); } /* @@ -956,7 +976,7 @@ ipmi_main(int argc, char ** argv, ipmi_intf_session_set_privlvl(ipmi_main_intf, IPMI_SESSION_PRIV_ADMIN); /* Get the ipmb address of the targeted entity */ ipmi_main_intf->target_ipmb_addr = - ipmi_picmg_ipmb_address(ipmi_main_intf); + ipmi_acquire_ipmb_address(ipmi_main_intf); lprintf(LOG_DEBUG, "Specified addressing Target %#x:%#x Transit %#x:%#x", ipmi_main_intf->target_addr, ipmi_main_intf->target_channel, diff --git a/lib/ipmi_picmg.c b/lib/ipmi_picmg.c index 914d11d..9dfa0d1 100644 --- a/lib/ipmi_picmg.c +++ b/lib/ipmi_picmg.c @@ -2325,37 +2325,39 @@ picmg_discover(struct ipmi_intf *intf) { struct ipmi_rq req; struct ipmi_rs *rsp; char msg_data; + uint8_t picmg_avail = 0; - if (intf->picmg_avail == 0) { - memset(&req, 0, sizeof(req)); - req.msg.netfn = IPMI_NETFN_PICMG; - req.msg.cmd = PICMG_GET_PICMG_PROPERTIES_CMD; - msg_data = 0x00; - req.msg.data = &msg_data; - req.msg.data_len = 1; - msg_data = 0; - - lprintf(LOG_DEBUG, "Running Get PICMG Properties my_addr %#x, transit %#x, target %#x", - intf->my_addr, intf->transit_addr, intf->target_addr); - rsp = intf->sendrecv(intf, &req); - if (rsp && !rsp->ccode) { - if ( (rsp->data[0] == 0) && - ((rsp->data[1] & 0x0F) == PICMG_ATCA_MAJOR_VERSION - || (rsp->data[1] & 0x0F) == PICMG_AMC_MAJOR_VERSION) ) { - intf->picmg_avail = 1; - lprintf(LOG_DEBUG, "Discovered PICMG Extension %d.%d", - (rsp->data[1] & 0x0f), (rsp->data[1] >> 4)); - } - } else { - if (rsp == NULL) { - lprintf(LOG_DEBUG,"No Response from Get PICMG Properties"); - } else { - lprintf(LOG_DEBUG,"Error Response %#x from Get PICMG Properities", rsp->ccode); - } - } - } - if (intf->picmg_avail == 0) { - lprintf(LOG_DEBUG, "No PICMG Extenstion discovered"); + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_PICMG_PROPERTIES_CMD; + msg_data = 0x00; + req.msg.data = &msg_data; + req.msg.data_len = 1; + msg_data = 0; + + lprintf(LOG_INFO, "Running Get PICMG Properties my_addr %#x, transit %#x, target %#x", + intf->my_addr, intf->transit_addr, intf->target_addr); + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_INFO,"No response from Get PICMG Properties"); + } else if (rsp->ccode != 0) { + lprintf(LOG_INFO,"Error response %#x from Get PICMG Properities", + rsp->ccode); + } else if (rsp->data_len < 4) { + lprintf(LOG_INFO,"Invalid Get PICMG Properties response length %d", + rsp->data_len); + } else if (rsp->data[0] != 0) { + lprintf(LOG_INFO,"Invalid Get PICMG Properties group extension %#x", + rsp->data[0]); + } else if ((rsp->data[1] & 0x0F) != PICMG_ATCA_MAJOR_VERSION + && (rsp->data[1] & 0x0F) != PICMG_AMC_MAJOR_VERSION) { + lprintf(LOG_INFO,"Unknown PICMG Extension Version %d.%d", + (rsp->data[1] & 0x0F), (rsp->data[1] >> 4)); + } else { + picmg_avail = 1; + lprintf(LOG_INFO, "Discovered PICMG Extension Version %d.%d", + (rsp->data[1] & 0x0f), (rsp->data[1] >> 4)); } - return intf->picmg_avail; + + return picmg_avail; } diff --git a/lib/ipmi_vita.c b/lib/ipmi_vita.c new file mode 100644 index 0000000..4f8b522 --- /dev/null +++ b/lib/ipmi_vita.c @@ -0,0 +1,1006 @@ +/* + * Copyright (c) 2014 Pigeon Point Systems. All right 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 Pigeon Point Systems, 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. + * PIGEON POINT SYSTEMS ("PPS") 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 + * PPS 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 PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi_picmg.h> +#include <ipmitool/ipmi_vita.h> +#include <ipmitool/ipmi_fru.h> +#include <ipmitool/ipmi_strings.h> +#include <ipmitool/log.h> + +/* Handled VITA 46.11 commands */ +#define VITA_CMD_HELP 0 +#define VITA_CMD_PROPERTIES 1 +#define VITA_CMD_FRUCONTROL 2 +#define VITA_CMD_ADDRINFO 3 +#define VITA_CMD_ACTIVATE 4 +#define VITA_CMD_DEACTIVATE 5 +#define VITA_CMD_POLICY_GET 6 +#define VITA_CMD_POLICY_SET 7 +#define VITA_CMD_LED_PROP 8 +#define VITA_CMD_LED_CAP 9 +#define VITA_CMD_LED_GET 10 +#define VITA_CMD_LED_SET 11 +#define VITA_CMD_UNKNOWN 255 + +/* VITA 46.11 Site Type strings */ +static struct valstr vita_site_types[] = { + { VITA_FRONT_VPX_MODULE, "Front Loading VPX Plug-In Module" }, + { VITA_POWER_ENTRY, "Power Entry Module" }, + { VITA_CHASSIS_FRU, "Chassic FRU Information Module" }, + { VITA_DEDICATED_CHMC, "Dedicated Chassis Manager" }, + { VITA_FAN_TRAY, "Fan Tray" }, + { VITA_FAN_TRAY_FILTER, "Fan Tray Filter" }, + { VITA_ALARM_PANEL, "Alarm Panel" }, + { VITA_XMC, "XMC" }, + { VITA_VPX_RTM, "VPX Rear Transition Module" }, + { VITA_FRONT_VME_MODULE, "Front Loading VME Plug-In Module" }, + { VITA_FRONT_VXS_MODULE, "Front Loading VXS Plug-In Module" }, + { VITA_POWER_SUPPLY, "Power Supply" }, + { VITA_FRONT_VITA62_MODULE, "Front Loading VITA 62 Module\n" }, + { VITA_71_MODULE, "VITA 71 Module\n" }, + { VITA_FMC, "FMC\n" }, + { 0, NULL } +}; + +/* VITA 46.11 command help strings */ +static struct valstr vita_help_strings[] = { + { + VITA_CMD_HELP, + "VITA commands:\n" + " properties - get VSO properties\n" + " frucontrol - FRU control\n" + " addrinfo - get address information\n" + " activate - activate a FRU\n" + " deactivate - deactivate a FRU\n" + " policy get - get the FRU activation policy\n" + " policy set - set the FRU activation policy\n" + " led prop - get led properties\n" + " led cap - get led color capabilities\n" + " led get - get led state\n" + " led set - set led state" + }, + { + VITA_CMD_FRUCONTROL, + "usage: frucontrol <FRU-ID> <OPTION>\n" + " OPTION: 0 - Cold Reset\n" + " 1 - Warm Reset\n" + " 2 - Graceful Reboot\n" + " 3 - Issue Diagnostic Interrupt" + }, + { + VITA_CMD_ADDRINFO, + "usage: addrinfo [<FRU-ID>]" + }, + { + VITA_CMD_ACTIVATE, + "usage: activate <FRU-ID>" + }, + { + VITA_CMD_DEACTIVATE, + "usage: deactivate <FRU-ID>" + }, + { + VITA_CMD_POLICY_GET, + "usage: policy get <FRU-ID>" + }, + { + VITA_CMD_POLICY_SET, + "usage: policy set <FRU-ID> <MASK> <VALUE>\n" + " MASK: [3] affect the Default-Activation-Locked Policy Bit\n" + " [2] affect the Commanded-Deactivation-Ignored Policy Bit\n" + " [1] affect the Deactivation-Locked Policy Bit\n" + " [0] affect the Activation-Locked Policy Bit\n" + " VALUE: [3] value for the Default-Activation-Locked Policy Bit\n" + " [2] value for the Commanded-Deactivation-Ignored Policy Bit\n" + " [1] value for the Deactivation-Locked Policy Bit\n" + " [0] value for the Activation-Locked Policy Bit" + }, + { + VITA_CMD_LED_PROP, + "usage: led prop <FRU-ID>" + }, + { + VITA_CMD_LED_CAP, + "usage: led cap <FRU-ID> <LED-ID" + }, + { + VITA_CMD_LED_GET, + "usage: led get <FRU-ID> <LED-ID", + }, + { + VITA_CMD_LED_SET, + "usage: led set <FRU-ID> <LED-ID> <FUNCTION> <DURATION> <COLOR>\n" + " <FRU-ID>\n" + " <LED-ID> 0-0xFE: Specified LED\n" + " 0xFF: All LEDs under management control\n" + " <FUNCTION> 0: LED OFF override\n" + " 1 - 250: LED blinking override (off duration)\n" + " 251: LED Lamp Test\n" + " 252: LED restore to local control\n" + " 255: LED ON override\n" + " <DURATION> 1 - 127: LED Lamp Test / on duration\n" + " <COLOR> 1: BLUE\n" + " 2: RED\n" + " 3: GREEN\n" + " 4: AMBER\n" + " 5: ORANGE\n" + " 6: WHITE\n" + " 0xE: do not change\n" + " 0xF: use default color" + }, + { + VITA_CMD_UNKNOWN, + "Unknown command" + }, + { 0, NULL } +}; + +/* check if VITA 46.11 is supported */ +uint8_t +vita_discover(struct ipmi_intf *intf) +{ + struct ipmi_rq req; + struct ipmi_rs *rsp; + unsigned char msg_data; + int vita_avail = 0; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = VITA_GET_VSO_CAPABILITIES_CMD; + req.msg.data = &msg_data; + req.msg.data_len = 1; + + msg_data = GROUP_EXT_VITA; + + lprintf(LOG_INFO, "Running Get VSO Capabilities my_addr %#x, " + "transit %#x, target %#x", + intf->my_addr, intf->transit_addr, intf->target_addr); + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_ERR, "No valid response received"); + } else if (rsp->ccode != 0) { + lprintf(LOG_ERR, "Invalid completion code received: %s", + val2str(rsp->ccode, completion_code_vals)); + } else if (rsp->data_len < 5) { + lprintf(LOG_ERR, "Invalid response length %d", + rsp->data_len); + } else if (rsp->data[0] != GROUP_EXT_VITA) { + lprintf(LOG_ERR, "Invalid group extension %#x", + rsp->data[0]); + } else if ((rsp->data[3] & 0x03) != 0) { + lprintf(LOG_ERR, "Unknown VSO Standard %d", + (rsp->data[3] & 0x03)); + } else if ((rsp->data[4] & 0x0F) != 1) { + lprintf(LOG_ERR, "Unknown VSO Specification Revision %d.%d", + (rsp->data[4] & 0x0F), (rsp->data[4] >> 4)); + } else { + vita_avail = 1; + lprintf(LOG_INFO, "Discovered VITA 46.11 Revision %d.%d", + (rsp->data[4] & 0x0F), (rsp->data[4] >> 4)); + } + + return vita_avail; +} + +uint8_t +ipmi_vita_ipmb_address(struct ipmi_intf *intf) +{ + struct ipmi_rq req; + struct ipmi_rs *rsp; + unsigned char msg_data; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = VITA_GET_FRU_ADDRESS_INFO_CMD; + req.msg.data = &msg_data; + req.msg.data_len = 1; + + msg_data = GROUP_EXT_VITA; + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_ERR, "No valid response received"); + } else if (rsp->ccode != 0) { + lprintf(LOG_ERR, "Invalid completion code received: %s", + val2str(rsp->ccode, completion_code_vals)); + } else if (rsp->data_len < 7) { + lprintf(LOG_ERR, "Invalid response length %d", + rsp->data_len); + } else if (rsp->data[0] != GROUP_EXT_VITA) { + lprintf(LOG_ERR, "Invalid group extension %#x", + rsp->data[0]); + } else { + return rsp->data[2]; + } + + return 0; +} + +static int +ipmi_vita_getaddr(struct ipmi_intf *intf, int argc, char **argv) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char msg_data[2]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = VITA_GET_FRU_ADDRESS_INFO_CMD; + req.msg.data = msg_data; + req.msg.data_len = 2; + + msg_data[0] = GROUP_EXT_VITA; /* VITA identifier */ + msg_data[1] = 0; /* default FRU ID */ + + if (argc > 0) { + /* validate and get FRU Device ID */ + if (is_fru_id(argv[0], &msg_data[1]) != 0) { + return -1; + } + } + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_ERR, "No valid response received"); + return -1; + } else if (rsp->ccode != 0) { + lprintf(LOG_ERR, "Invalid completion code received: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } else if (rsp->data_len < 7) { + lprintf(LOG_ERR, "Invalid response length %d", + rsp->data_len); + return -1; + } else if (rsp->data[0] != GROUP_EXT_VITA) { + lprintf(LOG_ERR, "Invalid group extension %#x", + rsp->data[0]); + return -1; + } + + printf("Hardware Address : 0x%02x\n", rsp->data[1]); + printf("IPMB-0 Address : 0x%02x\n", rsp->data[2]); + printf("FRU ID : 0x%02x\n", rsp->data[4]); + printf("Site ID : 0x%02x\n", rsp->data[5]); + printf("Site Type : %s\n", val2str(rsp->data[6], + vita_site_types)); + if (rsp->data_len > 8) { + printf("Channel 7 Address: 0x%02x\n", rsp->data[8]); + } + + return 0; +} + +static int +ipmi_vita_get_vso_capabilities(struct ipmi_intf *intf) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char msg_data, tmp; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = VITA_GET_VSO_CAPABILITIES_CMD; + req.msg.data = &msg_data; + req.msg.data_len = 1; + + msg_data = GROUP_EXT_VITA; /* VITA identifier */ + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_ERR, "No valid response received."); + return -1; + } else if (rsp->ccode != 0) { + lprintf(LOG_ERR, "Invalid completion code received: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } else if (rsp->data_len < 5) { + lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len); + return -1; + } else if (rsp->data[0] != GROUP_EXT_VITA) { + lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]); + return -1; + } + + printf("VSO Identifier : 0x%02x\n", rsp->data[0]); + printf("IPMC Identifier : 0x%02x\n", rsp->data[1]); + printf(" Tier %d\n", (rsp->data[1] & 0x03) + 1); + printf(" Layer %d\n", ((rsp->data[1] & 0x30) >> 4) + 1); + + printf("IPMB Capabilities : 0x%02x\n", rsp->data[2]); + + tmp = (rsp->data[2] & 0x30) >> 4; + + printf(" Frequency %skHz\n", + tmp == 0 ? "100" : tmp == 1 ? "400" : "RESERVED"); + + tmp = rsp->data[2] & 3; + + if (tmp == 1) { + printf(" 2 IPMB interfaces supported\n"); + } else if (tmp == 0) { + printf(" 1 IPMB interface supported\n"); + } + + printf("VSO Standard : %s\n", + (rsp->data[3] & 0x3) == 0 ? "VITA 46.11" : "RESERVED"); + + printf("VSO Spec Revision : %d.%d\n", rsp->data[4] & 0xf, + rsp->data[4] >> 4); + + printf("Max FRU Device ID : 0x%02x\n", rsp->data[5]); + printf("FRU Device ID : 0x%02x\n", rsp->data[6]); + + return 0; +} + +static int +ipmi_vita_set_fru_activation(struct ipmi_intf *intf, + char **argv, unsigned char command) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char msg_data[3]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = VITA_SET_FRU_ACTIVATION_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + msg_data[0] = GROUP_EXT_VITA; /* VITA identifier */ + if (is_fru_id(argv[0], &msg_data[1]) != 0) { /* FRU ID */ + return -1; + } + msg_data[2] = command; /* command */ + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_ERR, "No valid response received."); + return -1; + } else if (rsp->ccode != 0) { + lprintf(LOG_ERR, "Invalid completion code received: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } else if (rsp->data_len < 1) { + lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len); + return -1; + } else if (rsp->data[0] != GROUP_EXT_VITA) { + lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]); + return -1; + } + + printf("FRU has been successfully %s\n", + command ? "activated" : "deactivated"); + + return 0; +} + +static int +ipmi_vita_get_fru_state_policy_bits(struct ipmi_intf *intf, char **argv) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char msg_data[2]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = VITA_GET_FRU_STATE_POLICY_BITS_CMD; + req.msg.data = msg_data; + req.msg.data_len = 2; + + msg_data[0] = GROUP_EXT_VITA; /* VITA identifier */ + if (is_fru_id(argv[0], &msg_data[1]) != 0) { /* FRU ID */ + return -1; + } + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_ERR, "No valid response received."); + return -1; + } else if (rsp->ccode != 0) { + lprintf(LOG_ERR, "Invalid completion code received: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } else if (rsp->data_len < 2) { + lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len); + return -1; + } else if (rsp->data[0] != GROUP_EXT_VITA) { + lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]); + return -1; + } + + printf("FRU State Policy Bits: %xh\n", rsp->data[1]); + printf(" Default-Activation-Locked Policy Bit is %d\n", + rsp->data[1] & 0x08 ? 1 : 0); + printf(" Commanded-Deactivation-Ignored Policy Bit is %d\n", + rsp->data[1] & 0x04 ? 1 : 0); + printf(" Deactivation-Locked Policy Bit is %d\n", + rsp->data[1] & 0x02 ? 1 : 0); + printf(" Activation-Locked Policy Bit is %d\n", + rsp->data[1] & 0x01); + + return 0; +} + +static int +ipmi_vita_set_fru_state_policy_bits(struct ipmi_intf *intf, char **argv) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char msg_data[4]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = VITA_SET_FRU_STATE_POLICY_BITS_CMD; + req.msg.data = msg_data; + req.msg.data_len = 4; + + msg_data[0] = GROUP_EXT_VITA; /* VITA identifier */ + if (is_fru_id(argv[0], &msg_data[1]) != 0) { /* FRU ID */ + return -1; + } + if (str2uchar(argv[1], &msg_data[2]) != 0) { /* bits mask */ + return -1; + } + if (str2uchar(argv[2], &msg_data[3]) != 0) { /* bits */ + return -1; + } + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_ERR, "No valid response received."); + return -1; + } else if (rsp->ccode != 0) { + lprintf(LOG_ERR, "Invalid completion code received: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } else if (rsp->data_len < 1) { + lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len); + return -1; + } else if (rsp->data[0] != GROUP_EXT_VITA) { + lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]); + return -1; + } + + printf("FRU state policy bits have been updated\n"); + + return 0; +} + +static int +ipmi_vita_get_led_properties(struct ipmi_intf *intf, char **argv) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char msg_data[2]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = VITA_GET_FRU_LED_PROPERTIES_CMD; + req.msg.data = msg_data; + req.msg.data_len = 2; + + msg_data[0] = GROUP_EXT_VITA; /* VITA identifier */ + if (is_fru_id(argv[0], &msg_data[1]) != 0) { /* FRU ID */ + return -1; + } + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_ERR, "No valid response received."); + return -1; + } else if (rsp->ccode != 0) { + lprintf(LOG_ERR, "Invalid completion code received: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } else if (rsp->data_len < 3) { + lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len); + return -1; + } else if (rsp->data[0] != GROUP_EXT_VITA) { + lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]); + return -1; + } + + printf("LED Count: %#x\n", rsp->data[2]); + + return 0; +} + +static int +ipmi_vita_get_led_color_capabilities(struct ipmi_intf *intf, char **argv) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char msg_data[3]; + int i; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = VITA_GET_LED_COLOR_CAPABILITIES_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + msg_data[0] = GROUP_EXT_VITA; /* VITA identifier */ + if (is_fru_id(argv[0], &msg_data[1]) != 0) { /* FRU ID */ + return -1; + } + if (str2uchar(argv[1], &msg_data[2]) != 0) { /* LED-ID */ + return -1; + } + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_ERR, "No valid response received."); + return -1; + } else if (rsp->ccode != 0) { + lprintf(LOG_ERR, "Invalid completion code received: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } else if (rsp->data_len < 5) { + lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len); + return -1; + } else if (rsp->data[0] != GROUP_EXT_VITA) { + lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]); + return -1; + } + + printf("LED Color Capabilities: "); + for (i = 0; i < 8; i++) { + if (rsp->data[1] & (0x01 << i)) { + printf("%s, ", led_color_str[i]); + } + } + putchar('\n'); + + printf("Default LED Color in\n"); + printf(" LOCAL control: %s\n", led_color_str[rsp->data[2]]); + printf(" OVERRIDE state: %s\n", led_color_str[rsp->data[3]]); + + if (rsp->data_len == 5) { + printf("LED flags:\n"); + if (rsp->data[4] & 2) { + printf(" [HW RESTRICT]\n"); + } + if (rsp->data[4] & 1) { + printf(" [PAYLOAD PWR]\n"); + } + } + + return 0; +} + +static int +ipmi_vita_get_led_state(struct ipmi_intf *intf, char **argv) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char msg_data[3]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = VITA_GET_FRU_LED_STATE_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + msg_data[0] = GROUP_EXT_VITA; /* VITA identifier */ + if (is_fru_id(argv[0], &msg_data[1]) != 0) { /* FRU ID */ + return -1; + } + if (str2uchar(argv[1], &msg_data[2]) != 0) { /* LED-ID */ + return -1; + } + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_ERR, "No valid response received."); + return -1; + } else if (rsp->ccode != 0) { + lprintf(LOG_ERR, "Invalid completion code received: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } else if (rsp->data_len < 5 + || ((rsp->data[1] & 0x2) && rsp->data_len < 8) + || ((rsp->data[1] & 0x4) && rsp->data_len < 9)) { + lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len); + return -1; + } else if (rsp->data[0] != GROUP_EXT_VITA) { + lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]); + return -1; + } + + printf("LED states: %x\t", rsp->data[1]); + if (rsp->data[1] & 0x1) { + printf("[LOCAL CONTROL] "); + } + if (rsp->data[1] & 0x2) { + printf("[OVERRIDE] "); + } + if (rsp->data[1] & 0x4) { + printf("[LAMPTEST] "); + } + if (rsp->data[1] & 0x8) { + printf("[HW RESTRICT] "); + } + putchar('\n'); + + if (rsp->data[1] & 1) { + printf(" Local Control function: %x\t", rsp->data[2]); + if (rsp->data[2] == 0x0) { + printf("[OFF]\n"); + } else if (rsp->data[2] == 0xff) { + printf("[ON]\n"); + } else { + printf("[BLINKING]\n"); + } + printf(" Local Control On-Duration: %x\n", rsp->data[3]); + printf(" Local Control Color: %x\t[%s]\n", + rsp->data[4], led_color_str[rsp->data[4] & 7]); + } + + /* override state or lamp test */ + if (rsp->data[1] & 0x06) { + printf(" Override function: %x\t", rsp->data[5]); + if (rsp->data[5] == 0x0) { + printf("[OFF]\n"); + } else if (rsp->data[5] == 0xff) { + printf("[ON]\n"); + } else { + printf("[BLINKING]\n"); + } + printf(" Override On-Duration: %x\n", rsp->data[6]); + printf(" Override Color: %x\t[%s]\n", + rsp->data[7], led_color_str[rsp->data[7] & 7]); + if (rsp->data[1] == 0x04) { + printf(" Lamp test duration: %x\n", rsp->data[8]); + } + } + + return 0; +} + +static int +ipmi_vita_set_led_state(struct ipmi_intf *intf, char **argv) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = VITA_SET_FRU_LED_STATE_CMD; + req.msg.data = msg_data; + req.msg.data_len = 6; + + msg_data[0] = GROUP_EXT_VITA; /* VITA identifier */ + if (is_fru_id(argv[0], &msg_data[1]) != 0) { /* FRU ID */ + return -1; + } + if (str2uchar(argv[1], &msg_data[2]) != 0) { /* LED-ID */ + return -1; + } + if (str2uchar(argv[2], &msg_data[3]) != 0) { /* LED function */ + return -1; + } + if (str2uchar(argv[3], &msg_data[4]) != 0) { /* LED on duration */ + return -1; + } + if (str2uchar(argv[4], &msg_data[5]) != 0) { /* LED color */ + return -1; + } + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_ERR, "No valid response received."); + return -1; + } else if (rsp->ccode != 0) { + lprintf(LOG_ERR, "Invalid completion code received: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } else if (rsp->data_len < 1) { + lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len); + return -1; + } else if (rsp->data[0] != GROUP_EXT_VITA) { + lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]); + return -1; + } + + printf("LED state has been updated\n"); + + return 0; +} + +static int +ipmi_vita_fru_control(struct ipmi_intf *intf, char **argv) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char msg_data[3]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = VITA_FRU_CONTROL_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + msg_data[0] = GROUP_EXT_VITA; /* VITA identifier */ + if (is_fru_id(argv[0], &msg_data[1]) != 0) { /* FRU ID */ + return -1; + } + if (str2uchar(argv[1], &msg_data[2]) != 0) { /* control option */ + return -1; + } + + printf("FRU Device Id: %d FRU Control Option: %s\n", msg_data[1], + val2str(msg_data[2], picmg_frucontrol_vals)); + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_ERR, "No valid response received."); + return -1; + } else if (rsp->ccode != 0) { + lprintf(LOG_ERR, "Invalid completion code received: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } else if (rsp->data_len < 1) { + lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len); + return -1; + } else if (rsp->data[0] != GROUP_EXT_VITA) { + lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]); + return -1; + } + + printf("FRU Control: ok\n"); + + return 0; +} + +static int +ipmi_vita_get_cmd(int argc, char **argv) +{ + if (argc < 1 || !strncmp(argv[0], "help", 4)) { + return VITA_CMD_HELP; + } + + /* Get VSO Properties */ + if (!strncmp(argv[0], "properties", 10)) { + return VITA_CMD_PROPERTIES; + } + + /* FRU Control command */ + if (!strncmp(argv[0], "frucontrol", 10)) { + return VITA_CMD_FRUCONTROL; + } + + /* Get FRU Address Info command */ + if (!strncmp(argv[0], "addrinfo", 8)) { + return VITA_CMD_ADDRINFO; + } + + /* Set FRU Activation (activate) command */ + if (!strncmp(argv[0], "activate", 8)) { + return VITA_CMD_ACTIVATE; + } + + /* Set FRU Activation (deactivate) command */ + if (!strncmp(argv[0], "deactivate", 10)) { + return VITA_CMD_DEACTIVATE; + } + + /* FRU State Policy Bits commands */ + if (!strncmp(argv[0], "policy", 6)) { + if (argc < 2) { + return VITA_CMD_UNKNOWN; + } + + /* Get FRU State Policy Bits command */ + if (!strncmp(argv[1], "get", 3)) { + return VITA_CMD_POLICY_GET; + } + + /* Set FRU State Policy Bits command */ + if (!strncmp(argv[1], "set", 3)) { + return VITA_CMD_POLICY_SET; + } + + /* unknown command */ + return VITA_CMD_UNKNOWN; + } + + /* FRU LED commands */ + if (!strncmp(argv[0], "led", 3)) { + if (argc < 2) { + return VITA_CMD_UNKNOWN; + } + + /* FRU LED Get Properties */ + if (!strncmp(argv[1], "prop", 4)) { + return VITA_CMD_LED_PROP; + } + + /* FRU LED Get Capabilities */ + if (!strncmp(argv[1], "cap", 3)) { + return VITA_CMD_LED_CAP; + } + + /* FRU LED Get State */ + if (!strncmp(argv[1], "get", 3)) { + return VITA_CMD_LED_GET; + } + + /* FRU LED Set State */ + if (!strncmp(argv[1], "set", 3)) { + return VITA_CMD_LED_SET; + } + + /* unknown command */ + return VITA_CMD_UNKNOWN; + } + + /* unknown command */ + return VITA_CMD_UNKNOWN; +} + +int +ipmi_vita_main (struct ipmi_intf *intf, int argc, char **argv) +{ + int rc = -1, show_help = 0; + int cmd = ipmi_vita_get_cmd(argc, argv); + + switch (cmd) { + case VITA_CMD_HELP: + cmd = ipmi_vita_get_cmd(argc - 1, &argv[1]); + show_help = 1; + rc = 0; + break; + + case VITA_CMD_PROPERTIES: + rc = ipmi_vita_get_vso_capabilities(intf); + break; + + case VITA_CMD_FRUCONTROL: + if (argc > 2) { + rc = ipmi_vita_fru_control(intf, &argv[1]); + } else { + show_help = 1; + } + break; + + case VITA_CMD_ADDRINFO: + rc = ipmi_vita_getaddr(intf, argc - 1, &argv[1]); + break; + + case VITA_CMD_ACTIVATE: + if (argc > 1) { + rc = ipmi_vita_set_fru_activation(intf, &argv[1], 1); + } else { + show_help = 1; + } + break; + + case VITA_CMD_DEACTIVATE: + if (argc > 1) { + rc = ipmi_vita_set_fru_activation(intf, &argv[1], 0); + } else { + show_help = 1; + } + break; + + case VITA_CMD_POLICY_GET: + if (argc > 2) { + rc = ipmi_vita_get_fru_state_policy_bits(intf, + &argv[2]); + } else { + show_help = 1; + } + break; + + case VITA_CMD_POLICY_SET: + if (argc > 4) { + rc = ipmi_vita_set_fru_state_policy_bits(intf, + &argv[2]); + } else { + show_help = 1; + } + break; + + case VITA_CMD_LED_PROP: + if (argc > 2) { + rc = ipmi_vita_get_led_properties(intf, &argv[2]); + } else { + show_help = 1; + } + break; + + case VITA_CMD_LED_CAP: + if (argc > 3) { + rc = ipmi_vita_get_led_color_capabilities(intf, + &argv[2]); + } else { + show_help = 1; + } + break; + + case VITA_CMD_LED_GET: + if (argc > 3) { + rc = ipmi_vita_get_led_state(intf, &argv[2]); + } else { + show_help = 1; + } + break; + + case VITA_CMD_LED_SET: + if (argc > 6) { + rc = ipmi_vita_set_led_state(intf, &argv[2]); + } else { + show_help = 1; + } + break; + default: + lprintf(LOG_NOTICE, "Unknown command"); + cmd = VITA_CMD_HELP; + show_help = 1; + break; + } + + if (show_help) { + lprintf(LOG_NOTICE, "%s", val2str(cmd, vita_help_strings)); + } + + return rc; +} diff --git a/src/ipmitool.c b/src/ipmitool.c index e368cc7..164fd44 100644 --- a/src/ipmitool.c +++ b/src/ipmitool.c @@ -65,6 +65,7 @@ #include <ipmitool/ipmi_ekanalyzer.h> #include <ipmitool/ipmi_ime.h> #include <ipmitool/ipmi_dcmi.h> +#include <ipmitool/ipmi_vita.h> #ifdef HAVE_CONFIG_H # include <config.h> @@ -120,6 +121,7 @@ struct ipmi_cmd ipmitool_cmd_list[] = { { ipmi_hpmfwupg_main,"hpm", "Update HPM components using PICMG HPM.1 file"}, { ipmi_ekanalyzer_main,"ekanalyzer", "run FRU-Ekeying analyzer using FRU files"}, { ipmi_ime_main, "ime", "Update Intel Manageability Engine Firmware"}, + { ipmi_vita_main, "vita", "Run a VITA 46.11 extended cmd"}, { NULL }, }; |