summaryrefslogtreecommitdiff
path: root/lib/ipmi_dcmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ipmi_dcmi.c')
-rwxr-xr-xlib/ipmi_dcmi.c2193
1 files changed, 2193 insertions, 0 deletions
diff --git a/lib/ipmi_dcmi.c b/lib/ipmi_dcmi.c
new file mode 100755
index 0000000..6e030f9
--- /dev/null
+++ b/lib/ipmi_dcmi.c
@@ -0,0 +1,2193 @@
+/*
+ * Copyright (C) 2008 Intel Corporation.
+ * All rights reserved
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Theory of operation
+ *
+ * DCMI is the Data Center Management Interface which is a subset of IPMI v2.0.
+ * DCMI incorporates the ability to locate a system with DCMI functionality,
+ * its available temperature sensors, and power limiting control.
+ *
+ * All of the available DCMI commands are contained in a struct with a numeric
+ * value and a string. When the user specifies a command the string is
+ * compared to one of several structs and is then given a numeric value based
+ * on the matched string. A case statement is used to select the desired
+ * action from the user. If an invalid string is entered, or a string that is
+ * not a command option is entered, the available commands are printed to the
+ * screen. This allows the strings to be changed quickly with the DCMI spec.
+ *
+ * Each called function usually executes whichever command was requested to
+ * keep the main() from being overly complicated.
+ *
+ * This code conforms to the 1.0 DCMI Specification
+ * released by Hari Ramachandran of the Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <time.h>
+#include <netdb.h>
+
+#include <ipmitool/ipmi_dcmi.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/ipmi_mc.h>
+#include <ipmitool/ipmi_entity.h>
+#include <ipmitool/ipmi_constants.h>
+#include <ipmitool/ipmi_sensor.h>
+
+#include "../src/plugins/lanplus/lanplus.h"
+
+#define IPMI_LAN_PORT 0x26f
+
+extern int verbose;
+
+static int ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id);
+
+/*******************************************************************************
+ * The structs below are the DCMI command option strings. They are printed *
+ * when the user does not issue enough options or the wrong ones. The reason *
+ * that the DMCI command strings are in a struct is so that when the *
+ * specification changes, the strings can be changed quickly with out having *
+ * to change a lot of the code in the main(). *
+ ******************************************************************************/
+
+/* Main set of DCMI commands */
+const struct dcmi_cmd dcmi_cmd_vals[] = {
+ { 0x00, "discover", " Used to discover supported DCMI capabilities" },
+ { 0x01, "power", " Platform power limit command options" },
+ { 0x02, "sensors", " Prints the available DCMI sensors" },
+ { 0x03, "asset_tag", " Prints the platform's asset tag" },
+ { 0x04, "set_asset_tag", " Sets the platform's asset tag" },
+ { 0x05, "get_mc_id_string", " Get management controller ID string" },
+ { 0x06, "set_mc_id_string", " Set management controller ID string" },
+ { 0x07, "thermalpolicy", " Thermal policy get/set" },
+ { 0x08, "get_temp_reading", " Get Temperature Readings" },
+ { 0x09, "get_conf_param", " Get DCMI Config Parameters" },
+ { 0x0A, "set_conf_param", " Set DCMI Config Parameters" },
+ { 0x0B, "oob_discover", " Ping/Pong Message for DCMI Discovery" },
+ { 0xFF, NULL, NULL }
+};
+
+/* get capabilites */
+const struct dcmi_cmd dcmi_capable_vals[] = {
+ { 0x01, "platform", " Lists the system capabilities" },
+ { 0x02, "mandatory_attributes", "Lists SEL, identification and"
+ "temperature attributes" },
+ { 0x03, "optional_attributes", " Lists power capabilities" },
+ { 0x04, "managebility access", " Lists OOB channel information" },
+ { 0xFF, NULL, NULL }
+};
+
+/* platform capabilities
+ * Since they are actually in two bytes, we need three structs to make this
+ * human readable...
+ */
+const struct dcmi_cmd dcmi_mandatory_platform_capabilities[] = {
+ { 0x01, "Identification support available", "" },
+ { 0x02, "SEL logging available", "" },
+ { 0x03, "Chassis power available", "" },
+ { 0x04, "Temperature monitor available", "" },
+ { 0xFF, NULL, NULL }
+};
+
+/* optional capabilities */
+const struct dcmi_cmd dcmi_optional_platform_capabilities[] = {
+ { 0x01, "Power management available", "" },
+ { 0xFF, NULL, NULL }
+};
+
+/* access capabilties */
+const struct dcmi_cmd dcmi_management_access_capabilities[] = {
+ { 0x01, "In-band KCS channel available", "" },
+ { 0x02, "Out-of-band serial TMODE available", "" },
+ { 0x03, "Out-of-band secondary LAN channel available", "" },
+ { 0x04, "Out-of-band primary LAN channel available", "" },
+ { 0x05, "SOL enabled", "" },
+ { 0x06, "VLAN capable", "" },
+ { 0xFF, NULL, NULL }
+};
+
+/* identification capabilities */
+const struct dcmi_cmd dcmi_id_capabilities_vals[] = {
+ { 0x01, "GUID", "" },
+ { 0x02, "DHCP hostname", "" },
+ { 0x03, "Asset tag", "" },
+ { 0xFF, NULL, NULL }
+};
+
+/* Configuration parameters*/
+const struct dcmi_cmd dcmi_conf_param_vals[] = {
+ { 0x01, "activate_dhcp", "\tActivate DHCP"},
+ { 0x02, "dhcp_config", "\tDHCP Configuration" },
+ { 0x03, "init", "\t\tInitial timeout interval" },
+ { 0x04, "timeout", "\t\tServer contact timeout interval" },
+ { 0x05, "retry", "\t\tServer contact retry interval" },
+ { 0xFF, NULL, NULL }
+};
+
+
+/* temperature monitoring capabilities */
+const struct dcmi_cmd dcmi_temp_monitoring_vals[] = {
+ { 0x01, "inlet", " Inlet air temperature sensors" },
+ { 0x02, "cpu", " CPU temperature sensors" },
+ { 0x03, "baseboard", "Baseboard temperature sensors" },
+ { 0xff, NULL, NULL }
+};
+
+/* These are not comands. These are the DCMI temp sensors and their numbers
+ * If new sensors are added, they need to be added to this list with their
+ * sensor number
+ */
+const struct dcmi_cmd dcmi_discvry_snsr_vals[] = {
+ { 0x40, "Inlet", " Inlet air temperature sensors" },
+ { 0x41, "CPU", " CPU temperature sensors" },
+ { 0x42, "Baseboard", "Baseboard temperature sensors" },
+ { 0xff, NULL, NULL }
+};
+
+/* Temperature Readings */
+const struct dcmi_cmd dcmi_temp_read_vals[] = {
+ { 0x40, "Inlet", "Inlet air temperature(40h) " },
+ { 0x41, "CPU", "CPU temperature sensors(41h) " },
+ { 0x42, "Baseboard", "Baseboard temperature sensors(42h) " },
+ { 0xff, NULL, NULL }
+};
+
+/* power management/control commands */
+const struct dcmi_cmd dcmi_pwrmgmt_vals[] = {
+ { 0x00, "reading", " Get power related readings from the system" },
+ { 0x01, "get_limit", " Get the configured power limits" },
+ { 0x02, "set_limit", " Set a power limit option" },
+ { 0x03, "activate", " Activate the set power limit" },
+ { 0x04, "deactivate", "Deactivate the set power limit" },
+ { 0xFF, NULL, NULL }
+};
+
+/* set power limit commands */
+const struct dcmi_cmd dcmi_pwrmgmt_set_usage_vals[] = {
+ { 0x00, "action", " <no_action | sel_logging | power_off>" },
+ { 0x01, "limit", " <number in Watts>" },
+ { 0x02, "correction", "<number in milliseconds>" },
+ { 0x03, "sample", " <number in seconds>" },
+ { 0xFF, NULL, NULL }
+};
+
+/* power management/get action commands */
+const struct dcmi_cmd dcmi_pwrmgmt_get_action_vals[] = {
+ { 0x00, "No Action", ""},
+ { 0x01, "Hard Power Off & Log Event to SEL", ""},
+
+ { 0x02, "OEM reserved (02h)", ""},
+ { 0x03, "OEM reserved (03h)", ""},
+ { 0x04, "OEM reserved (04h)", ""},
+ { 0x05, "OEM reserved (05h)", ""},
+ { 0x06, "OEM reserved (06h)", ""},
+ { 0x07, "OEM reserved (07h)", ""},
+ { 0x08, "OEM reserved (08h)", ""},
+ { 0x09, "OEM reserved (09h)", ""},
+ { 0x0a, "OEM reserved (0ah)", ""},
+ { 0x0b, "OEM reserved (0bh)", ""},
+ { 0x0c, "OEM reserved (0ch)", ""},
+ { 0x0d, "OEM reserved (0dh)", ""},
+ { 0x0e, "OEM reserved (0eh)", ""},
+ { 0x0f, "OEM reserved (0fh)", ""},
+ { 0x10, "OEM reserved (10h)", ""},
+
+ { 0x11, "Log Event to SEL", ""},
+ { 0xFF, NULL, NULL }
+};
+
+/* power management/set action commands */
+const struct dcmi_cmd dcmi_pwrmgmt_action_vals[] = {
+ { 0x00, "no_action", "No Action"},
+ { 0x01, "power_off", "Hard Power Off & Log Event to SEL"},
+ { 0x11, "sel_logging", "Log Event to SEL"},
+
+ { 0x02, "oem_02", "OEM reserved (02h)"},
+ { 0x03, "oem_03", "OEM reserved (03h)"},
+ { 0x04, "oem_04", "OEM reserved (04h)"},
+ { 0x05, "oem_05", "OEM reserved (05h)"},
+ { 0x06, "oem_06", "OEM reserved (06h)"},
+ { 0x07, "oem_07", "OEM reserved (07h)"},
+ { 0x08, "oem_08", "OEM reserved (08h)"},
+ { 0x09, "oem_09", "OEM reserved (09h)"},
+ { 0x0a, "oem_0a", "OEM reserved (0ah)"},
+ { 0x0b, "oem_0b", "OEM reserved (0bh)"},
+ { 0x0c, "oem_0c", "OEM reserved (0ch)"},
+ { 0x0d, "oem_0d", "OEM reserved (0dh)"},
+ { 0x0e, "oem_0e", "OEM reserved (0eh)"},
+ { 0x0f, "oem_0f", "OEM reserved (0fh)"},
+ { 0x10, "oem_10", "OEM reserved (10h)"},
+
+ { 0xFF, NULL, NULL }
+};
+
+/* thermal policy action commands */
+const struct dcmi_cmd dcmi_thermalpolicy_vals[] = {
+ { 0x00, "get", "Get thermal policy" },
+ { 0x01, "set", "Set thermal policy" },
+ { 0xFF, NULL, NULL }
+};
+
+/* thermal policy action commands */
+const struct dcmi_cmd dcmi_confparameters_vals[] = {
+ { 0x00, "get", "Get configuration parameters" },
+ { 0x01, "set", "Set configuration parameters" },
+ { 0xFF, NULL, NULL }
+};
+
+/* entityIDs used in thermap policy */
+const struct dcmi_cmd dcmi_thermalpolicy_set_parameters_vals[] = {
+ { 0x00, "volatile", " Current Power Cycle" },
+ { 0x01, "nonvolatile", "Set across power cycles" },
+ { 0x01, "poweroff", " Hard Power Off system" },
+ { 0x00, "nopoweroff", " No 'Hard Power Off' action" },
+ { 0x01, "sel", " Log event to SEL" },
+ { 0x00, "nosel", " No 'Log event to SEL' action" },
+ { 0x00, "disabled", " Disabled" },
+ { 0x00, NULL, NULL }
+};
+
+
+/* DCMI command specific completion code results per 1.0 spec
+ * 80h - parameter not supported.
+ * 81h - attempt to set the ‘set in progress’ value (in parameter #0) when not
+ * in the ‘set complete’ state. (This completion code provides a way to
+ * recognize that another party has already ‘claimed’ the parameters)
+ * 82h - attempt to write read-only parameter
+ * 82h - set not supported on selected channel (e.g. channel is session-less.)
+ * 83h - access mode not supported
+ * 84h – Power Limit out of range
+ * 85h – Correction Time out of range
+ * 89h – Statistics Reporting Period out of range
+ */
+const struct valstr dcmi_ccode_vals[] = {
+ { 0x80, "Parameter not supported" },
+ { 0x81, "Something else has already claimed these parameters" },
+ { 0x82, "Not supported or failed to write a read-only parameter" },
+ { 0x83, "Access mode is not supported" },
+ { 0x84, "Power/Thermal limit out of range" },
+ { 0x85, "Correction/Exception time out of range" },
+ { 0x89, "Sample/Statistics Reporting period out of range" },
+ { 0x8A, "Power limit already active" },
+ { 0xFF, NULL }
+};
+
+/* End strings */
+
+/* This was taken from print_valstr() from helper.c. It serves the same
+ * purpose but with out the extra formatting. This function simply prints
+ * the dcmi_cmd struct provided. verthorz specifies to print vertically or
+ * horizontally. If the string is printed horizontally then a | will be
+ * printed between each instance of vs[i].str until it is NULL
+ *
+ * @vs: value string list to print
+ * @title: name of this value string list
+ * @loglevel: what log level to print, -1 for stdout
+ * @verthorz: printed vertically or horizontally, 0 or 1
+ */
+void
+print_strs(const struct dcmi_cmd * vs, const char * title, int loglevel,
+ int verthorz)
+{
+ int i;
+
+ if (vs == NULL)
+ return;
+
+ if (title != NULL) {
+ if (loglevel < 0)
+ printf("\n%s\n", title);
+ else
+ lprintf(loglevel, "\n%s", title);
+ }
+ for (i = 0; vs[i].str != NULL; i++) {
+ if (loglevel < 0) {
+ if (vs[i].val < 256)
+ if (verthorz == 0)
+ printf(" %s %s\n", vs[i].str, vs[i].desc);
+ else
+ printf("%s", vs[i].str);
+ else if (verthorz == 0)
+ printf(" %s %s\n", vs[i].str, vs[i].desc);
+ else
+ printf("%s", vs[i].str);
+ } else {
+ if (vs[i].val < 256)
+ lprintf(loglevel, " %s %s", vs[i].str, vs[i].desc);
+ else
+ lprintf(loglevel, " %s %s", vs[i].str, vs[i].desc);
+ }
+ /* Check to see if this is NOT the last element in vs.str if true
+ * print the | else don't print anything.
+ */
+ if ((verthorz == 1) && (vs[i+1].str != NULL))
+ printf(" | ");
+ }
+ if (verthorz == 0) {
+ if (loglevel < 0) {
+ printf("\n");
+ } else {
+ lprintf(loglevel, "");
+ }
+ }
+}
+
+/* This was taken from str2val() from helper.c. It serves the same
+ * purpose but with the addition of a desc field from the structure.
+ * This function converts the str from the dcmi_cmd struct provided to the
+ * value associated to the compared string in the struct.
+ *
+ * @str: string to compare against
+ * @vs: dcmi_cmd structure
+ */
+uint16_t
+str2val2(const char *str, const struct dcmi_cmd *vs)
+{
+ int i;
+ if (vs == NULL || str == NULL) {
+ return 0;
+ }
+ for (i = 0; vs[i].str != NULL; i++) {
+ if (strncasecmp(vs[i].str, str,
+ __maxlen(str, vs[i].str)) == 0) {
+ return vs[i].val;
+ }
+ }
+ return vs[i].val;
+}
+
+/* This was taken from val2str() from helper.c. It serves the same
+ * purpose but with the addition of a desc field from the structure.
+ * This function converts the val and returns a string from the dcmi_cmd
+ * struct provided in the struct.
+ *
+ * @val: value to compare against
+ * @vs: dcmi_cmd structure
+ */
+const char *
+val2str2(uint16_t val, const struct dcmi_cmd *vs)
+{
+ static char un_str[32];
+ int i;
+
+ if (vs == NULL)
+ return NULL;
+
+ for (i = 0; vs[i].str != NULL; i++) {
+ if (vs[i].val == val)
+ return vs[i].str;
+ }
+ memset(un_str, 0, 32);
+ snprintf(un_str, 32, "Unknown (0x%x)", val);
+ return un_str;
+}
+
+/* check the DCMI response from the BMC
+ * @rsp: Response data structure
+ */
+static int
+chk_rsp(struct ipmi_rs * rsp)
+{
+ /* if the response from the intf is NULL then the BMC is experiencing
+ * some issue and cannot complete the command
+ */
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "\n Unable to get DCMI information");
+ return 1;
+ }
+ /* if the completion code is greater than zero there was an error. We'll
+ * use val2str from helper.c to print the error from either the DCMI
+ * completion code struct or the generic IPMI completion_code_vals struct
+ */
+ if ((rsp->ccode >= 0x80) && (rsp->ccode <= 0x8F)) {
+ lprintf(LOG_ERR, "\n DCMI request failed because: %s (%x)",
+ val2str(rsp->ccode, dcmi_ccode_vals), rsp->ccode);
+ return 1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "\n DCMI request failed because: %s (%x)",
+ val2str(rsp->ccode, completion_code_vals), rsp->ccode);
+ return 1;
+ }
+ /* check to make sure this is a DCMI firmware */
+ if(rsp->data[0] != IPMI_DCMI) {
+ printf("\n A valid DCMI command was not returned! (%x)", rsp->data[0]);
+ return 1;
+ }
+ return 0;
+}
+
+/* Get capabilities ipmi response
+ *
+ * This function returns the available capabilities of the platform.
+ * The reason it returns in the rsp struct is so that it can be used for other
+ * purposes.
+ *
+ * returns ipmi response structure
+ *
+ * @intf: ipmi interface handler
+ * @selector: Parameter selector
+ */
+struct ipmi_rs *
+ipmi_dcmi_getcapabilities(struct ipmi_intf * intf, uint8_t selector)
+{
+ struct ipmi_rq req; /* request data to send to the BMC */
+ uint8_t msg_data[2]; /* 'raw' data to be sent to the BMC */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = selector;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.0 spec */
+ req.msg.cmd = IPMI_DCMI_COMPAT; /* 0x01 per 1.0 spec */
+ req.msg.data = msg_data; /* 0xDC 0x01 or the msg_data above */
+ req.msg.data_len = 2; /* How many times does req.msg.data need to read */
+
+ return intf->sendrecv(intf, &req);
+}
+/* end capabilities struct */
+
+/* Displays capabilities from structure
+ * returns void
+ *
+ * @cmd: dcmi_cmd structure
+ * @data_val: holds value of what to display
+ */
+void
+display_capabilities_attributes(const struct dcmi_cmd *cmd, uint8_t data_val)
+{
+ uint8_t i;
+ for (i = 0x01; cmd[i-1].val != 0xFF; i++) {
+ if (data_val & (1<<(i-1))) {
+ printf(" %s\n", val2str2(i, cmd));
+ }
+ }
+}
+
+static int
+ipmi_dcmi_prnt_oobDiscover(struct ipmi_intf * intf)
+{
+# ifndef IPMI_INTF_LANPLUS
+ lprintf(LOG_ERR,
+ "DCMI Discovery is available only when LANplus(IPMI v2.0) is enabled.");
+ return (-1);
+# else
+ int rc;
+ struct ipmi_session *s;
+
+ if (intf->opened == 0 && intf->open != NULL) {
+ if (intf->open(intf) < 0)
+ return (-1);
+ }
+ if (intf == NULL || intf->session == NULL)
+ return -1;
+
+ s = intf->session;
+
+ if (s->port == 0)
+ s->port = IPMI_LAN_PORT;
+ if (s->privlvl == 0)
+ s->privlvl = IPMI_SESSION_PRIV_ADMIN;
+ if (s->timeout == 0)
+ s->timeout = IPMI_LAN_TIMEOUT;
+ if (s->retry == 0)
+ s->retry = IPMI_LAN_RETRY;
+
+ if (s->hostname == NULL || strlen((const char *)s->hostname) == 0) {
+ lprintf(LOG_ERR, "No hostname specified!");
+ return -1;
+ }
+
+ intf->abort = 1;
+ intf->session->sol_data.sequence_number = 1;
+
+ if (ipmi_intf_socket_connect (intf) == -1) {
+ lprintf(LOG_ERR, "Could not open socket!");
+ return -1;
+ }
+
+ if (intf->fd < 0) {
+ lperror(LOG_ERR, "Connect to %s failed",
+ s->hostname);
+ intf->close(intf);
+ return -1;
+ }
+
+ intf->opened = 1;
+
+ /* Lets ping/pong */
+ return ipmiv2_lan_ping(intf);
+# endif
+}
+
+/* This is the get DCMI Capabilities function to see what the BMC supports.
+ *
+ * returns 0 with out error -1 with any errors
+ *
+ * @intf: ipmi interface handler
+ * @selector: selection parameter
+ */
+static int
+ipmi_dcmi_prnt_getcapabilities(struct ipmi_intf * intf, uint8_t selector)
+{
+ uint8_t i;
+ uint8_t bit_shifter = 0;
+ struct capabilities cape;
+ struct ipmi_rs * rsp;
+ rsp = ipmi_dcmi_getcapabilities(intf, selector);
+
+ if(chk_rsp(rsp))
+ return -1;
+
+ /* if there were no errors, the command worked! */
+ memcpy(&cape, rsp->data, sizeof (cape));
+ /* check to make sure that this is a 1.0/1.1/1.5 command */
+ if ((cape.conformance != IPMI_DCMI_CONFORM)
+ && (cape.conformance != IPMI_DCMI_1_1_CONFORM)
+ && (cape.conformance != IPMI_DCMI_1_5_CONFORM)) {
+ lprintf(LOG_ERR,
+ "ERROR! This command is not available on this platform");
+ return -1;
+ }
+ /* check to make sure that this is a rev .01 or .02 */
+ if (cape.revision != 0x01 && cape.revision != 0x02) {
+ lprintf(LOG_ERR,
+ "ERROR! This command is not compatible with this version");
+ return -1;
+ }
+ /* 0x01 - platform capabilities
+ * 0x02 - Manageability Access Capabilities
+ * 0x03 - SEL Capability
+ * 0x04 - Identification Capability
+ * 0x05 - LAN Out-Of-Band Capability
+ * 0x06 - Serial Out-Of-Band TMODE Capability
+ */
+ switch (selector) {
+ case 0x01:
+ printf(" Supported DCMI capabilities:\n");
+ /* loop through each of the entries in the first byte from the
+ * struct
+ */
+ printf("\n Mandatory platform capabilties\n");
+ display_capabilities_attributes(
+ dcmi_mandatory_platform_capabilities, cape.data_byte1);
+ /* loop through each of the entries in the second byte from the
+ * struct
+ */
+ printf("\n Optional platform capabilties\n");
+ display_capabilities_attributes(
+ dcmi_optional_platform_capabilities, cape.data_byte2);
+ /* loop through each of the entries in the third byte from the
+ * struct
+ */
+ printf("\n Managebility access capabilties\n");
+ display_capabilities_attributes(
+ dcmi_management_access_capabilities, cape.data_byte3);
+ break;
+ case 0x02:
+ printf("\n Mandatory platform attributes:\n");
+ /* byte 1 & 2 data */
+ printf("\n SEL Attributes: ");
+ printf("\n SEL automatic rollover is ");
+ /* mask the 2nd byte of the data response with 10000000b or 0x80
+ * because of the endian-ness the 15th bit is in the second byte
+ */
+ if ((cape.data_byte2 & 0x80))
+ printf("enabled");
+ else
+ printf("not present");
+ /* since the number of SEL entries is split across the two data
+ * bytes we will need to bit shift and append them together again
+ */
+ /* cast cape.data_byte1 as 16 bits */
+ uint16_t sel_entries = (uint16_t)cape.data_byte1;
+ /* or sel_entries with byte 2 and shift it 8 places */
+ sel_entries |= (uint16_t)cape.data_byte2 << 8;
+ printf("\n %d SEL entries\n", sel_entries & 0xFFF);
+ /* byte 3 data */
+ printf("\n Identification Attributes: \n");
+ display_capabilities_attributes(
+ dcmi_id_capabilities_vals, cape.data_byte3);
+ /* byte 4 data */
+ printf("\n Temperature Monitoring Attributes: \n");
+ display_capabilities_attributes(dcmi_temp_monitoring_vals,
+ cape.data_byte4);
+ break;
+ case 0x03:
+ printf("\n Optional Platform Attributes: \n");
+ /* Power Management */
+ printf("\n Power Management:\n");
+ if (cape.data_byte1 == 0x40) {
+ printf(" Slave address of device: 20h (BMC)\n" );
+ } else {
+ printf(" Slave address of device: %xh (8bits)"
+ "(Satellite/External controller)\n",
+ cape.data_byte1);
+ }
+ /* Controller channel number (4-7) bits */
+ if ((cape.data_byte2>>4) == 0x00) {
+ printf(" Channel number is 0h (Primary BMC)\n");
+ } else {
+ printf(" Channel number is %xh \n",
+ (cape.data_byte2>>4));
+ }
+ /* Device revision (0-3) */
+ printf(" Device revision is %d \n",
+ cape.data_byte2 &0xf);
+ break;
+ case 0x04:
+ /* LAN */
+ printf("\n Manageability Access Attributes: \n");
+ if (cape.data_byte1 == 0xFF) {
+ printf(" Primary LAN channel is not available for OOB\n");
+ } else {
+ printf(" Primary LAN channel number: %d is available\n",
+ cape.data_byte1);
+ }
+ if (cape.data_byte2 == 0xFF) {
+ printf(" Secondary LAN channel is not available for OOB\n");
+ } else {
+ printf(" Secondary LAN channel number: %d is available\n",
+ cape.data_byte2);
+ }
+ /* serial */
+ if (cape.data_byte3 == 0xFF) {
+ printf(" No serial channel is available\n");
+ } else {
+ printf(" Serial channel number: %d is available\n",
+ cape.data_byte3);
+ }
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+ /* return intf->sendrecv(intf, &req); */
+}
+
+/* This is the get asset tag command. This checks the length of the asset tag
+ * with the first read, then reads n number of bytes thereafter to get the
+ * complete asset tag.
+ *
+ * @intf: ipmi interface handler
+ * @offset: where to start reading the asset tag
+ * @length: how much to read
+ *
+ * returns ipmi_rs structure
+ */
+struct ipmi_rs *
+ipmi_dcmi_getassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length)
+{
+ struct ipmi_rq req; /* request data to send to the BMC */
+ uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = offset; /* offset 0 */
+ msg_data[2] = length; /* read one byte */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
+ req.msg.cmd = IPMI_DCMI_GETASSET; /* 0x01 per 1.1 spec */
+ req.msg.data = msg_data; /* msg_data above */
+ req.msg.data_len = 3; /* How many times does req.msg.data need to read */
+ return intf->sendrecv(intf, &req);
+}
+
+/* This is the get asset tag command. The function first checks to see if the
+ * platform is capable of getting the asset tag by calling the getcapabilities
+ * function and checking the response. Then it checks the length of the asset
+ * tag with the first read, then x number of reads thereafter to get the asset
+ * complete asset tag then print it.
+ *
+ * @intf: ipmi interface handler
+ *
+ * returns 0 if no failure, -1 with a failure
+ */
+static int
+ipmi_dcmi_prnt_getassettag(struct ipmi_intf * intf)
+{
+ uint8_t data_byte2;
+ struct ipmi_rs * rsp; /* ipmi response */
+ uint8_t taglength = 0;
+ uint8_t getlength = 0;
+ uint8_t offset = 0;
+ uint8_t i;
+ /* now let's get the asset tag length */
+ rsp = ipmi_dcmi_getassettag(intf, 0, 0);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ taglength = rsp->data[1];
+ printf("\n Asset tag: ");
+ while (taglength) {
+ getlength = taglength / DCMI_MAX_BYTE_SIZE ?
+ DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
+ rsp = ipmi_dcmi_getassettag(intf, offset, getlength);
+ /* macro has no effect here where can generate sig segv
+ * if rsp occurs with null
+ */
+ if (rsp != NULL) {
+ GOOD_ASSET_TAG_CCODE(rsp->ccode);
+ }
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ for (i=0; i<getlength; i++) {
+ printf("%c", rsp->data[i+2]);
+ }
+ offset += getlength;
+ taglength -= getlength;
+ }
+ printf("\n");
+ return 0;
+}
+
+/* This is the set asset tag command. This checks the length of the asset tag
+ * with the first read, then reads n number of bytes thereafter to set the
+ * complete asset tag.
+ *
+ * @intf: ipmi interface handler
+ * @offset: offset to write
+ * @length: number of bytes to write (16 bytes maximum)
+ * @data: data to write
+ *
+ * returns ipmi_rs structure
+ */
+struct ipmi_rs *
+ipmi_dcmi_setassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length,
+ uint8_t *data)
+{
+ struct ipmi_rq req; /* request data to send to the BMC */
+ uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = offset; /* offset 0 */
+ msg_data[2] = length; /* read one byte */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
+ req.msg.cmd = IPMI_DCMI_SETASSET; /* 0x08 per 1.1 spec */
+ req.msg.data = msg_data; /* msg_data above */
+ /* How many times does req.msg.data need to read */
+ req.msg.data_len = length + 3;
+ memcpy(req.msg.data + 3, data, length);
+
+ return intf->sendrecv(intf, &req);
+}
+
+static int
+ipmi_dcmi_prnt_setassettag(struct ipmi_intf * intf, uint8_t * data)
+{
+ uint8_t data_byte2;
+ struct ipmi_rs * rsp; /* ipmi response */
+ uint8_t tmpData[DCMI_MAX_BYTE_SIZE];
+ uint8_t taglength = 0;
+ uint8_t getlength = 0;
+ uint8_t offset = 0;
+ uint8_t i;
+
+ /* now let's get the asset tag length */
+ taglength = strlen(data);
+ if (taglength > 64){
+ lprintf(LOG_ERR, "\nValue is too long.");
+ return -1;
+ }
+ printf("\n Set Asset Tag: ");
+ while (taglength) {
+ getlength = taglength / DCMI_MAX_BYTE_SIZE ?
+ DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
+ memcpy(tmpData, data + offset, getlength);
+ rsp = ipmi_dcmi_setassettag(intf, offset, getlength, tmpData);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ for (i=0; i<getlength; i++) {
+ printf("%c", tmpData[i]);
+ }
+ offset += getlength;
+ taglength -= getlength;
+ }
+ printf("\n");
+ return 0;
+}
+
+/* Management Controller Identifier String is provided in order to accommodate
+ * the requirement for the management controllers to identify themselves.
+ *
+ * @intf: ipmi interface handler
+ * @offset: offset to read
+ * @length: number of bytes to read (16 bytes maximum)
+ *
+ * returns ipmi_rs structure
+ */
+struct ipmi_rs *
+ipmi_dcmi_getmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length)
+{
+ struct ipmi_rq req; /* request data to send to the BMC */
+ uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = offset; /* offset 0 */
+ msg_data[2] = length; /* read one byte */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
+ req.msg.cmd = IPMI_DCMI_GETMNGCTRLIDS; /* 0x09 per 1.1 spec */
+ req.msg.data = msg_data; /* msg_data above */
+ /* How many times does req.msg.data need to read */
+ req.msg.data_len = 3;
+ return intf->sendrecv(intf, &req);
+}
+
+static int
+ipmi_dcmi_prnt_getmngctrlids(struct ipmi_intf * intf)
+{
+ uint8_t data_byte2;
+ struct ipmi_rs * rsp; /* ipmi response */
+ uint8_t taglength = 0;
+ uint8_t getlength = 0;
+ uint8_t offset = 0;
+ uint8_t i;
+
+ /* now let's get the asset tag length */
+ rsp = ipmi_dcmi_getmngctrlids(intf, 0, 1);
+
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+
+ taglength = rsp->data[1];
+
+ printf("\n Get Management Controller Identifier String: ");
+ while (taglength) {
+ getlength = taglength / DCMI_MAX_BYTE_SIZE ?
+ DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
+ rsp = ipmi_dcmi_getmngctrlids(intf, offset, getlength);
+
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ for (i=0; i<getlength; i++) {
+ printf("%c", rsp->data[i+2]);
+ }
+ offset += getlength;
+ taglength -= getlength;
+ }
+ printf("\n");
+ return 0;
+}
+
+/* Management Controller Identifier String is provided in order to accommodate
+ * the requirement for the management controllers to identify themselves.
+ *
+ * @intf: ipmi interface handler
+ * @offset: offset to write
+ * @length: number of bytes to write (16 bytes maximum)
+ * @data: data to write
+ *
+ * returns ipmi_rs structure
+ */
+struct ipmi_rs *
+ipmi_dcmi_setmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length,
+ uint8_t *data)
+{
+ struct ipmi_rq req; /* request data to send to the BMC */
+ uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = offset; /* offset 0 */
+ msg_data[2] = length; /* read one byte */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
+ req.msg.cmd = IPMI_DCMI_SETMNGCTRLIDS; /* 0x0A per 1.1 spec */
+ req.msg.data = msg_data; /* msg_data above */
+ /* How many times does req.msg.data need to read */
+ req.msg.data_len = 3 + length;
+ memcpy(req.msg.data + 3, data, length);
+
+ return intf->sendrecv(intf, &req);
+}
+
+/* Set Asset Tag command provides ability for the management console to set the
+ * asset tag as appropriate. Management controller is not responsible for the
+ * data format used for the Asset Tag once modified by IPDC.
+ *
+ * @intf: ipmi interface handler
+ *
+ * returns 0 if no failure, -1 with a failure
+ */
+static int
+ipmi_dcmi_prnt_setmngctrlids(struct ipmi_intf * intf, uint8_t * data)
+{
+ uint8_t data_byte2;
+ struct ipmi_rs * rsp; /* ipmi response */
+ uint8_t tmpData[DCMI_MAX_BYTE_SIZE];
+ uint8_t taglength = 0;
+ uint8_t getlength = 0;
+ uint8_t offset = 0;
+ uint8_t i;
+
+ data += '\0';
+ taglength = strlen(data) +1;
+
+ if (taglength > 64) {
+ lprintf(LOG_ERR, "\nValue is too long.");
+ return -1;
+ }
+
+ printf("\n Set Management Controller Identifier String Command: ");
+ while (taglength) {
+ getlength = taglength / DCMI_MAX_BYTE_SIZE ?
+ DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
+ memcpy(tmpData, data + offset, getlength);
+ rsp = ipmi_dcmi_setmngctrlids(intf, offset, getlength, tmpData);
+ /* because after call "Set mc id string" RMCP+ will go down
+ * we have no "rsp"
+ */
+ if (strncmp(intf->name, "lanplus", 7)) {
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ }
+ for (i=0; i<getlength; i++) {
+ printf("%c", tmpData[i]);
+ }
+ offset += getlength;
+ taglength -= getlength;
+ }
+ printf("\n");
+ return 0;
+}
+
+/* Issues a discovery command to see what sensors are available on the target.
+ * system.
+ *
+ * @intf: ipmi interface handler
+ * @isnsr: entity ID
+ * @offset: offset (Entity instace start)
+ *
+ * returns ipmi_rs structure
+ */
+struct ipmi_rs *
+ipmi_dcmi_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr, uint8_t offset)
+{
+ struct ipmi_rq req; /* ipmi request struct */
+ uint8_t msg_data[5]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = 0x01; /* Senser Type = Temp (01h) */
+ msg_data[2] = isnsr; /* Sensor Number */
+ msg_data[3] = 0x00; /* Entity Instance, set to read all instances */
+ msg_data[4] = offset; /* Entity instace start */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_GETSNSR;
+ req.msg.data = msg_data; /* Contents above */
+ req.msg.data_len = 5; /* how many times does req.msg.data need to read */
+
+ return intf->sendrecv(intf, &req);
+}
+
+/* DCMI sensor discovery
+ * Uses the dcmi_discvry_snsr_vals struct to print its string and
+ * uses the numeric values to request the sensor sdr record id.
+ *
+ * @intf: ipmi interface handler
+ * @isnsr: entity ID
+ * @ient: sensor entity id
+ */
+static int
+ipmi_dcmi_prnt_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr)
+{
+ int i = 0;
+ struct ipmi_rs * rsp; /* ipmi response */
+ uint8_t records = 0;
+ int8_t instances = 0;
+ uint8_t offset = 0;
+ uint16_t record_id = 0;
+ uint8_t id_buff[16]; /* enough for 8 record IDs */
+ rsp = ipmi_dcmi_discvry_snsr(intf, isnsr, 0);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ instances = rsp->data[1];
+ printf("\n%s: %d temperature sensor%s found:\n",
+ val2str2(isnsr, dcmi_discvry_snsr_vals),
+ instances,
+ (instances > 1) ? "s" : "");
+ while(instances > 0) {
+ ipmi_dcmi_discvry_snsr(intf, isnsr, offset);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ records = rsp->data[2];
+ /* cache the data since it may be destroyed by subsequent
+ * ipmi_xxx calls
+ */
+ memcpy(id_buff, &rsp->data[3], 16);
+ for (i=0; i<records; i++) {
+ /* Record ID is in little endian format */
+ record_id = (id_buff[2*i + 1] << 8) + id_buff[2*i];
+ printf("Record ID 0x%04x: ", record_id);
+ ipmi_print_sensor_info(intf, record_id);
+ }
+ offset += 8;
+ instances -= records;
+ }
+ return 0;
+}
+/* end sensor discovery */
+
+/* Power Management get power reading
+ *
+ * @intf: ipmi interface handler
+ */
+static int
+ipmi_dcmi_pwr_rd(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct power_reading val;
+ struct tm tm_t;
+ time_t t;
+ uint8_t msg_data[4]; /* number of request data bytes */
+ memset(&tm_t, 0, sizeof(tm_t));
+ memset(&t, 0, sizeof(t));
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = 0x01; /* Mode Power Status */
+ msg_data[2] = 0x00; /* reserved */
+ msg_data[3] = 0x00; /* reserved */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_GETRED; /* Get power reading */
+ req.msg.data = msg_data; /* msg_data above */
+ req.msg.data_len = 4; /* how many times does req.msg.data need to read */
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ /* rsp->data[0] is equal to response data byte 2 in spec */
+ /* printf("Group Extension Identification: %02x\n", rsp->data[0]); */
+ memcpy(&val, rsp->data, sizeof (val));
+ t = val.time_stamp;
+ gmtime_r(&t, &tm_t);
+ printf("\n");
+ printf(" Instantaneous power reading: %8d Watts\n",
+ val.curr_pwr);
+ printf(" Minimum during sampling period: %8d Watts\n",
+ val.min_sample);
+ printf(" Maximum during sampling period: %8d Watts\n",
+ val.max_sample);
+ printf(" Average power reading over sample period: %8d Watts\n",
+ val.avg_pwr);
+ printf(" IPMI timestamp: %s",
+ asctime(&tm_t));
+ printf(" Sampling period: %08d Milliseconds\n",
+ val.sample);
+ printf(" Power reading state is: ");
+ /* mask the rsp->data so that we only care about bit 6 */
+ if((val.state & 0x40) == 0x40) {
+ printf("activated");
+ } else {
+ printf("deactivated");
+ }
+ printf("\n\n");
+ return 0;
+}
+/* end Power Management get reading */
+
+
+/* This is the get thermalpolicy command.
+ *
+ * @intf: ipmi interface handler
+ */
+int
+ipmi_dcmi_getthermalpolicy(struct ipmi_intf * intf, uint8_t entityID,
+ uint8_t entityInstance)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct thermal_limit val;
+ uint8_t msg_data[3]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/
+ msg_data[2] = entityInstance; /* Entity Instance */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_GETTERMALLIMIT; /* Get thermal policy reading */
+ req.msg.data = msg_data; /* msg_data above */
+ req.msg.data_len = 3; /* how many times does req.msg.data need to read */
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ /* rsp->data[0] is equal to response data byte 2 in spec */
+ memcpy(&val, rsp->data, sizeof (val));
+ printf("\n");
+ printf(" Persistance flag is: %s\n",
+ ((val.exceptionActions & 0x80) ? "set" : "notset"));
+ printf(" Exception Actions, taken if the Temperature Limit exceeded:\n");
+ printf(" Hard Power Off system and log event: %s\n",
+ ((val.exceptionActions & 0x40) ? "active":"inactive"));
+ printf(" Log event to SEL only: %s\n",
+ ((val.exceptionActions & 0x20) ? "active":"inactive"));
+ printf(" Temperature Limit %d degrees\n",
+ val.tempLimit);
+ printf(" Exception Time %d seconds\n",
+ val.exceptionTime);
+ printf("\n\n");
+ return 0;
+}
+
+/* This is the set thermalpolicy command.
+ *
+ * @intf: ipmi interface handler
+ */
+int
+ipmi_dcmi_setthermalpolicy(struct ipmi_intf * intf,
+ uint8_t entityID,
+ uint8_t entityInst,
+ uint8_t persistanceFlag,
+ uint8_t actionHardPowerOff,
+ uint8_t actionLogToSEL,
+ uint8_t tempLimit,
+ uint8_t samplingTimeLSB,
+ uint8_t samplingTimeMSB)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[7]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/
+ msg_data[2] = entityInst; /* Entity Instance */
+ /* persistance and actions or disabled if no actions */
+ msg_data[3] = (((persistanceFlag ? 1 : 0) << 7) |
+ ((actionHardPowerOff? 1 : 0) << 6) |
+ ((actionLogToSEL ? 1 : 0) << 5));
+ msg_data[4] = tempLimit;
+ msg_data[5] = samplingTimeLSB;
+ msg_data[6] = samplingTimeMSB;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ /* Get thermal policy reading */
+ req.msg.cmd = IPMI_DCMI_SETTERMALLIMIT;
+ req.msg.data = msg_data; /* msg_data above */
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 7;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ /* rsp->data[0] is equal to response data byte 2 in spec */
+ printf("\nThermal policy %d for %0Xh entity successfully set.\n\n",
+ entityInst, entityID);
+ return 0;
+}
+
+/* This is Get Temperature Readings Command
+ *
+ * returns ipmi response structure
+ *
+ * @intf: ipmi interface handler
+ */
+struct ipmi_rs *
+ipmi_dcmi_get_temp_readings(struct ipmi_intf * intf,
+ uint8_t entityID,
+ uint8_t entityInst,
+ uint8_t entityInstStart)
+{
+ struct ipmi_rq req;
+ uint8_t msg_data[5]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = 0x01; /* Sensor type */
+ msg_data[2] = entityID; /* Entity Instance */
+ msg_data[3] = entityInst;
+ msg_data[4] = entityInstStart;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_GETTEMPRED; /* Get thermal policy reading */
+ req.msg.data = msg_data; /* msg_data above */
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 5;
+ return intf->sendrecv(intf, &req);
+}
+
+static int
+ipmi_dcmi_prnt_get_temp_readings(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ int i,j, tota_inst, get_inst, offset = 0;
+ /* Print sensor description */
+ printf("\n\tEntity ID\t\t\tEntity Instance\t Temp. Readings");
+ for (i = 0; dcmi_temp_read_vals[i].str != NULL; i++) {
+ /* get all of the information about this sensor */
+ rsp = ipmi_dcmi_get_temp_readings(intf,
+ dcmi_temp_read_vals[i].val, 0, 0);
+ if (chk_rsp(rsp)) {
+ continue;
+ }
+ /* Total number of available instances for the Entity ID */
+ offset = 0;
+ tota_inst = rsp->data[1];
+ while (tota_inst > 0) {
+ get_inst = ((tota_inst / DCMI_MAX_BYTE_TEMP_READ_SIZE) ?
+ DCMI_MAX_BYTE_TEMP_READ_SIZE :
+ (tota_inst % DCMI_MAX_BYTE_TEMP_READ_SIZE));
+ rsp = ipmi_dcmi_get_temp_readings(intf,
+ dcmi_temp_read_vals[i].val, offset, 0);
+ if (chk_rsp(rsp)) {
+ continue;
+ }
+ /* Number of sets of Temperature Data in this
+ * response (Max 8 per response)
+ */
+ for (j=0; j < rsp->data[2]*2; j=j+2) {
+ /* Print Instance temperature info */
+ printf("\n%s",dcmi_temp_read_vals[i].desc);
+ printf("\t\t%i\t\t%c%i C", rsp->data[j+4],
+ ((rsp->data[j+3]) >> 7) ?
+ '-' : '+', (rsp->data[j+3] & 127));
+ }
+ offset += get_inst;
+ tota_inst -= get_inst;
+ }
+ }
+ return 0;
+}
+
+/* This is Get DCMI Config Parameters Command
+ *
+ * returns ipmi response structure
+ *
+ * @intf: ipmi interface handler
+ */
+struct ipmi_rs *
+ipmi_dcmi_getconfparam(struct ipmi_intf * intf, int param_selector)
+{
+ struct ipmi_rq req;
+ uint8_t msg_data[3]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = param_selector; /* Parameter selector */
+ /* Set Selector. Selects a given set of parameters under a given Parameter
+ * selector value. 00h if parameter doesn't use a Set Selector.
+ */
+ msg_data[2] = 0x00;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_GETCONFPARAM; /* Get DCMI Config Parameters */
+ req.msg.data = msg_data; /* Contents above */
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 3;
+ return intf->sendrecv(intf, &req);
+}
+
+static int
+ipmi_dcmi_prnt_getconfparam(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ const int dcmi_conf_params = 5;
+ int param_selector;
+ uint16_t tmp_value = 0;
+ /* We are not interested in parameter 1 which always will return 0 */
+ for (param_selector = 2 ; param_selector <= dcmi_conf_params;
+ param_selector++) {
+ rsp = ipmi_dcmi_getconfparam(intf, param_selector);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ /* Time to print what we have got */
+ switch(param_selector) {
+ case 2:
+ tmp_value = (rsp->data[4])& 1;
+ printf("\n\tDHCP Discovery method\t: ");
+ printf("\n\t\tManagement Controller ID String is %s",
+ tmp_value ? "enabled" : "disabled");
+ printf("\n\t\tVendor class identifier DCMI IANA and Vendor class-specific Informationa are %s",
+ ((rsp->data[4])& 2) ? "enabled" : "disabled" );
+ break;
+ case 3:
+ printf("\n\tInitial timeout interval\t: %i seconds",
+ rsp->data[4]);
+ break;
+ case 4:
+ printf("\n\tServer contact timeout interval\t: %i seconds",
+ rsp->data[4] + (rsp->data[5]<<8));
+ break;
+ case 5:
+ printf("\n\tServer contact retry interval\t: %i seconds",
+ rsp->data[4] + (rsp->data[5] << 8));
+ break;
+ default:
+ printf("\n\tConfiguration Parameter not supported.");
+ }
+ }
+ return 0;
+}
+
+/* This is Set DCMI Config Parameters Command
+ *
+ * returns ipmi response structure
+ *
+ * @intf: ipmi interface handler
+ */
+struct ipmi_rs *
+ipmi_dcmi_setconfparam(struct ipmi_intf * intf, uint8_t param_selector,
+ uint16_t value)
+{
+ struct ipmi_rq req;
+ uint8_t msg_data[5]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = param_selector; /* Parameter selector */
+ /* Set Selector (use 00h for parameters that only have one set). */
+ msg_data[2] = 0x00;
+
+ if (param_selector > 3) {
+ /* One bite more */
+ msg_data[3] = value & 0xFF;
+ msg_data[4] = value >> 8;
+ } else {
+ msg_data[3] = value;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_SETCONFPARAM; /* Set DCMI Config Parameters */
+ req.msg.data = msg_data; /* Contents above */
+ if (param_selector > 3) {
+ /* One bite more */
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 5;
+ } else {
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 4;
+ }
+ return intf->sendrecv(intf, &req);
+}
+
+/* Power Management get limit ipmi response
+ *
+ * This function returns the currently set power management settings as an
+ * ipmi response structure. The reason it returns in the rsp struct is so
+ * that it can be used in the set limit [slimit()] function to populate
+ * un-changed or un-edited values.
+ *
+ * returns ipmi response structure
+ *
+ * @intf: ipmi interface handler
+ */
+struct ipmi_rs * ipmi_dcmi_pwr_glimit(struct ipmi_intf * intf)
+{
+ struct ipmi_rq req;
+ uint8_t msg_data[3]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = 0x00; /* reserved */
+ msg_data[2] = 0x00; /* reserved */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_GETLMT; /* Get power limit */
+ req.msg.data = msg_data; /* Contents above */
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 3;
+
+ return intf->sendrecv(intf, &req);
+}
+/* end Power Management get limit response */
+
+/* Power Management print the get limit command
+ *
+ * This function calls the get limit function that returns an ipmi response.
+ *
+ * returns 0 else 1 with error
+ * @intf: ipmi interface handler
+ */
+static int
+ipmi_dcmi_pwr_prnt_glimit(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct power_limit val;
+ uint8_t realCc = 0xff;
+
+ rsp = ipmi_dcmi_pwr_glimit(intf);
+ /* rsp can be a null so check response before any operation
+ * on it to avoid sig segv
+ */
+ if (rsp != NULL) {
+ realCc = rsp->ccode;
+ GOOD_PWR_GLIMIT_CCODE(rsp->ccode);
+ }
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ /* rsp->data[0] is equal to response data byte 2 in spec */
+ /* printf("Group Extension Identification: %02x\n", rsp->data[0]); */
+ memcpy(&val, rsp->data, sizeof (val));
+ printf("\n Current Limit State: %s\n",
+ (realCc == 0) ?
+ "Power Limit Active" : "No Active Power Limit");
+ printf(" Exception actions: %s\n",
+ val2str2(val.action, dcmi_pwrmgmt_get_action_vals));
+ printf(" Power Limit: %i Watts\n", val.limit);
+ printf(" Correction time: %i milliseconds\n", val.correction);
+ printf(" Sampling period: %i seconds\n", val.sample);
+ printf("\n");
+ return 0;
+}
+/* end print get limit */
+
+/* Power Management set limit
+ *
+ * Undocumented bounds:
+ * Power limit: 0 - 0xFFFF
+ * Correction period 5750ms to 28751ms or 0x1676 to 0x704F
+ * sample period: 3 sec to 65 sec and 69+
+ *
+ * @intf: ipmi interface handler
+ * @option: Power option to change
+ * @value: Value of the desired change
+ */
+static int
+ipmi_dcmi_pwr_slimit(struct ipmi_intf * intf, const char * option,
+ const char * value)
+{
+ struct ipmi_rs * rsp; /* ipmi response */
+ struct ipmi_rq req; /* ipmi request (to send) */
+ struct power_limit val;
+ uint8_t msg_data[15]; /* number of request data bytes */
+ uint32_t lvalue = 0;
+ int i;
+
+ rsp = ipmi_dcmi_pwr_glimit(intf); /* get the power limit settings */
+# if 0
+ {
+ unsigned char counter = 0;
+ printf("DATA (%d): ", rsp->data_len);
+ for(counter = 0; counter < rsp->data_len; counter ++) {
+ printf("%02X ", rsp->data[counter]);
+ }
+ printf("\n");
+ }
+# endif
+ /* rsp can be a null so check response before any operation on it to
+ * avoid sig segv
+ */
+ if (rsp != NULL) {
+ GOOD_PWR_GLIMIT_CCODE(rsp->ccode);
+ }
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ memcpy(&val, rsp->data, sizeof (val));
+ /* same as above; sets the values of the val struct
+ * DCMI group ID *
+ * val.grp_id = rsp->data[0];
+ * exception action *
+ * val.action = rsp->data[3]; *
+ *
+ * power limit in Watts *
+ * store 16 bits of the rsp from the 4th entity *
+ * val.limit = *(uint16_t*)(&rsp->data[4]);
+ * correction period in mS *
+ * store 32 bits of the rsp from the 6th entity *
+ * val.correction = *(uint32_t*)(&rsp->data[6]);
+ * store 16 bits of the rsp from the 12th entity *
+ * sample period in seconds *
+ * val.sample = *(uint16_t*)(&rsp->data[12]);
+ */
+ lprintf(LOG_INFO,
+ "DCMI IN Limit=%d Correction=%d Action=%d Sample=%d\n",
+ val.limit, val.correction, val.action, val.sample);
+ switch (str2val2(option, dcmi_pwrmgmt_set_usage_vals)) {
+ case 0x00:
+ /* action */
+ switch (str2val2(value, dcmi_pwrmgmt_action_vals)) {
+ case 0x00:
+ /* no_action */
+ val.action = 0;
+ break;
+ case 0x01:
+ /* power_off */
+ val.action = 1;
+ break;
+ case 0x02:
+ /* OEM reserved action */
+ val.action = 0x02;
+ break;
+ case 0x03:
+ /* OEM reserved action */
+ val.action = 0x03;
+ break;
+ case 0x04:
+ /* OEM reserved action */
+ val.action = 0x04;
+ break;
+ case 0x05:
+ /* OEM reserved action */
+ val.action = 0x05;
+ break;
+ case 0x06:
+ /* OEM reserved action */
+ val.action = 0x06;
+ break;
+ case 0x07:
+ /* OEM reserved action */
+ val.action = 0x07;
+ break;
+ case 0x08:
+ /* OEM reserved action */
+ val.action = 0x08;
+ break;
+ case 0x09:
+ /* OEM reserved action */
+ val.action = 0x09;
+ break;
+ case 0x0a:
+ /* OEM reserved action */
+ val.action = 0x0a;
+ break;
+ case 0x0b:
+ /* OEM reserved action */
+ val.action = 0x0b;
+ break;
+ case 0x0c:
+ /* OEM reserved action */
+ val.action = 0x0c;
+ break;
+ case 0x0d:
+ /* OEM reserved action */
+ val.action = 0x0d;
+ break;
+ case 0x0e:
+ /* OEM reserved action */
+ val.action = 0x0e;
+ break;
+ case 0x0f:
+ /* OEM reserved action */
+ val.action = 0x0f;
+ break;
+ case 0x10:
+ /* OEM reserved action */
+ val.action = 0x10;
+ break;
+ case 0x11:
+ /* sel_logging*/
+ val.action = 0x11;
+ break;
+ case 0xFF:
+ /* error - not a string we knew what to do with */
+ lprintf(LOG_ERR, "Given %s '%s' is invalid.",
+ option, value);
+ return -1;
+ }
+ break;
+ case 0x01:
+ /* limit */
+ if (str2uint(value, &lvalue) != 0) {
+ lprintf(LOG_ERR, "Given %s '%s' is invalid.",
+ option, value);
+ return (-1);
+ }
+ val.limit = *(uint16_t*)(&lvalue);
+ break;
+ case 0x02:
+ /* correction */
+ if (str2uint(value, &lvalue) != 0) {
+ lprintf(LOG_ERR, "Given %s '%s' is invalid.",
+ option, value);
+ return (-1);
+ }
+ val.correction = *(uint32_t*)(&lvalue);
+ break;
+ case 0x03:
+ /* sample */
+ if (str2uint(value, &lvalue) != 0) {
+ lprintf(LOG_ERR, "Given %s '%s' is invalid.",
+ option, value);
+ return (-1);
+ }
+ val.sample = *(uint16_t*)(&lvalue);
+ break;
+ case 0xff:
+ /* no valid options */
+ return -1;
+ }
+ lprintf(LOG_INFO, "DCMI OUT Limit=%d Correction=%d Action=%d Sample=%d\n", val.limit, val.correction, val.action, val.sample);
+
+ msg_data[0] = val.grp_id; /* Group Extension Identification */
+ msg_data[1] = 0x00; /* reserved */
+ msg_data[2] = 0x00; /* reserved */
+ msg_data[3] = 0x00; /* reserved */
+ msg_data[4] = val.action; /* exception action; 0x00 disables it */
+
+ /* fill msg_data[5] with the first 16 bits of val.limit */
+ *(uint16_t*)(&msg_data[5]) = val.limit;
+ /* msg_data[5] = 0xFF;
+ * msg_data[6] = 0xFF;
+ */
+ /* fill msg_data[7] with the first 32 bits of val.correction */
+ *(uint32_t*)(&msg_data[7]) = val.correction;
+ /* msg_data[7] = 0x76;
+ * msg_data[8] = 0x16;
+ * msg_data[9] = 0x00;
+ * msg_data[10] = 0x00;
+ */
+ msg_data[11] = 0x00; /* reserved */
+ msg_data[12] = 0x00; /* reserved */
+ /* fill msg_data[7] with the first 16 bits of val.sample */
+ *(uint16_t*)(&msg_data[13]) = val.sample;
+ /* msg_data[13] = 0x03; */
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */
+ req.msg.data = msg_data; /* Contents above */
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 15;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ return 0;
+}
+/* end Power Management set limit */
+
+/* Power Management activate deactivate
+ *
+ * @intf: ipmi interface handler
+ * @option: uint8_t - 0 to deactivate or 1 to activate
+ */
+static int
+ipmi_dcmi_pwr_actdeact(struct ipmi_intf * intf, uint8_t option)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[4]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = option; /* 0 = Deactivate 1 = Activate */
+ msg_data[2] = 0x00; /* reserved */
+ msg_data[3] = 0x00; /* reserved */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_PWRACT; /* Act-deactivate power limit */
+ req.msg.data = msg_data; /* Contents above */
+ req.msg.data_len = 4; /* how mant times does req.msg.data need to read */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ printf("\n Power limit successfully ");
+ if (option == 0x00) {
+ printf("deactivated");
+ } else {
+ printf("activated");
+ }
+ printf("\n");
+ return 0;
+}
+/* end power management activate/deactivate */
+
+/* main
+ *
+ * @intf: dcmi interface handler
+ * @argc: argument count
+ * @argv: argument vector
+ */
+int
+ipmi_dcmi_main(struct ipmi_intf * intf, int argc, char **argv)
+{
+ int rc = 0;
+ uint8_t ctl = 0;
+ int i, ii, instances;
+ struct ipmi_rs *rsp;
+
+ if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) {
+ print_strs(dcmi_cmd_vals,
+ "Data Center Management Interface commands",
+ -1, 0);
+ return -1;
+ }
+ /* start the cmd requested */
+ switch (str2val2(argv[0], dcmi_cmd_vals)) {
+ case 0x00:
+ /* discover capabilities*/
+ for (i = 1; dcmi_capable_vals[i-1].str != NULL; i++) {
+ if (ipmi_dcmi_prnt_getcapabilities(intf, i) < 0) {
+ printf("Error discovering %s capabilities!\n",
+ val2str2(i, dcmi_capable_vals));
+ return -1;
+ }
+ }
+ break;
+ case 0x01:
+ /* power */
+ argv++;
+ if (argv[0] == NULL) {
+ print_strs(dcmi_pwrmgmt_vals, "power <command>",
+ -1, 0);
+ return -1;
+ }
+ /* power management */
+ switch (str2val2(argv[0], dcmi_pwrmgmt_vals)) {
+ case 0x00:
+ /* get reading */
+ rc = ipmi_dcmi_pwr_rd(intf);
+ break;
+ case 0x01:
+ /* get limit */
+ /* because the get limit function is also used to
+ * populate unchanged values for the set limit
+ * command it returns an ipmi response structure
+ */
+ rc = ipmi_dcmi_pwr_prnt_glimit(intf);
+ break;
+ case 0x02:
+ /* set limit */
+ if (argc < 4) {
+ print_strs(dcmi_pwrmgmt_set_usage_vals,
+ "set_limit <parameter> <value>",
+ -1, 0);
+ return -1;
+ }
+ if ( argc == 10) {
+ /* Let`s initialize dcmi power parameters */
+ struct ipmi_rq req;
+ uint8_t data[256];
+ uint16_t sample = 0;
+ uint16_t limit = 0;
+ uint32_t correction = 0;
+
+ memset(data, 0, sizeof(data));
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.lun = 0x00;
+ req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */
+ req.msg.data = data; /* Contents above */
+ req.msg.data_len = 15;
+
+ data[0] = IPMI_DCMI; /* Group Extension Identification */
+ data[1] = 0x0; /* reserved */
+ data[2] = 0x0; /* reserved */
+ data[3] = 0x0; /* reserved */
+
+ /* action */
+ switch (str2val2(argv[2], dcmi_pwrmgmt_action_vals)) {
+ case 0x00:
+ /* no_action */
+ data[4] = 0x00;
+ break;
+ case 0x01:
+ /* power_off */
+ data[4] = 0x01;
+ break;
+ case 0x11:
+ /* sel_logging*/
+ data[4] = 0x11;
+ break;
+ case 0xFF:
+ /* error - not a string we knew what to do with */
+ lprintf(LOG_ERR, "Given Action '%s' is invalid.",
+ argv[2]);
+ return -1;
+ }
+ /* limit */
+ if (str2ushort(argv[4], &limit) != 0) {
+ lprintf(LOG_ERR,
+ "Given Limit '%s' is invalid.",
+ argv[4]);
+ return (-1);
+ }
+ data[5] = limit >> 0;
+ data[6] = limit >> 8;
+ /* correction */
+ if (str2uint(argv[6], &correction) != 0) {
+ lprintf(LOG_ERR,
+ "Given Correction '%s' is invalid.",
+ argv[6]);
+ return (-1);
+ }
+ data[7] = correction >> 0;
+ data[8] = correction >> 8;
+ data[9] = correction >> 16;
+ data[10] = correction >> 24;
+ data[11] = 0x00; /* reserved */
+ data[12] = 0x00; /* reserved */
+ /* sample */
+ if (str2ushort(argv[8], &sample) != 0) {
+ lprintf(LOG_ERR,
+ "Given Sample '%s' is invalid.",
+ argv[8]);
+ return (-1);
+ }
+ data[13] = sample >> 0;
+ data[14] = sample >> 8;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ } else {
+ /* loop through each parameter and value until we have neither */
+ while ((argv[1] != NULL) && (argv[2] != NULL)) {
+ rc = ipmi_dcmi_pwr_slimit(intf, argv[1], argv[2]);
+ /* catch any error that the set limit function returned */
+ if (rc > 0) {
+ print_strs(dcmi_pwrmgmt_set_usage_vals,
+ "set_limit <parameter> <value>", -1, 0);
+ return -1;
+ }
+ /* the first argument is the command and the second is the
+ * value. Move argv two places; what is now 3 will be 1
+ */
+ argv+=2;
+ }
+ }
+ rc = ipmi_dcmi_pwr_prnt_glimit(intf);
+ break;
+ case 0x03:
+ /* activate */
+ rc = ipmi_dcmi_pwr_actdeact(intf, 1);
+ break;
+ case 0x04:
+ /* deactivate */
+ rc = ipmi_dcmi_pwr_actdeact(intf, 0);
+ break;
+ default:
+ /* no valid options */
+ print_strs(dcmi_pwrmgmt_vals,
+ "power <command>", -1, 0);
+ break;
+ }
+ /* power mgmt end */
+ break;
+ /* end power command */
+ case 0x02:
+ /* sensor print */
+ /* Look for each item in the dcmi_discvry_snsr_vals struct
+ * and if it exists, print the sdr record id(s) for it.
+ * Use the val from each one as the sensor number.
+ */
+ for (i = 0; dcmi_discvry_snsr_vals[i].str != NULL; i++) {
+ /* get all of the information about this sensor */
+ rc = ipmi_dcmi_prnt_discvry_snsr(intf,
+ dcmi_discvry_snsr_vals[i].val);
+ }
+ break;
+ /* end sensor print */
+ case 0x03:
+ /* asset tag */
+ if(ipmi_dcmi_prnt_getassettag(intf) < 0) {
+ lprintf(LOG_ERR, "Error getting asset tag!");
+ return -1;
+ }
+ break;
+ /* end asset tag */
+ case 0x04:
+ {
+ /* set asset tag */
+ if (argc == 1 ) {
+ print_strs(dcmi_cmd_vals,
+ "Data Center Management Interface commands",
+ -1, 0);
+ return -1;
+ }
+ if (ipmi_dcmi_prnt_setassettag(intf, argv[1]) < 0) {
+ lprintf(LOG_ERR, "\nError setting asset tag!");
+ return -1;
+ }
+ break;
+ }
+ /* end set asset tag */
+ case 0x05:
+ /* get management controller identifier string */
+ if (ipmi_dcmi_prnt_getmngctrlids(intf) < 0) {
+ lprintf(LOG_ERR,
+ "Error getting management controller identifier string!");
+ return -1;
+ }
+ break;
+ /* end get management controller identifier string */
+ case 0x06:
+ {
+ /* set management controller identifier string */
+ if (argc == 1 ) {
+ print_strs(dcmi_cmd_vals,
+ "Data Center Management Interface commands",
+ -1, 0);
+ return -1;
+ }
+ if (ipmi_dcmi_prnt_setmngctrlids(intf, argv[1]) < 0) {
+ lprintf(LOG_ERR,
+ "Error setting management controller identifier string!");
+ return -1;
+ }
+ break;
+ }
+ /* end set management controller identifier string */
+ case 0x07:
+ {
+ uint8_t entityID = 0;
+ uint8_t entityInst = 0;
+ uint8_t persistanceFlag;
+ uint8_t actionHardPowerOff;
+ uint8_t actionLogToSEL;
+ uint8_t tempLimit = 0;
+ uint8_t samplingTimeLSB;
+ uint8_t samplingTimeMSB;
+ uint16_t samplingTime = 0;
+ /* Thermal policy get/set */
+ /* dcmitool dcmi thermalpolicy get */
+ switch (str2val2(argv[1], dcmi_thermalpolicy_vals)) {
+ case 0x00:
+ if (argc < 4) {
+ lprintf(LOG_NOTICE, "Get <entityID> <instanceID>");
+ return -1;
+ }
+ if (str2uchar(argv[2], &entityID) != 0) {
+ lprintf(LOG_ERR,
+ "Given Entity ID '%s' is invalid.",
+ argv[2]);
+ return (-1);
+ }
+ if (str2uchar(argv[3], &entityInst) != 0) {
+ lprintf(LOG_ERR,
+ "Given Instance ID '%s' is invalid.",
+ argv[3]);
+ return (-1);
+ }
+ rc = ipmi_dcmi_getthermalpolicy(intf, entityID, entityInst);
+ break;
+ case 0x01:
+ if (argc < 4) {
+ lprintf(LOG_NOTICE, "Set <entityID> <instanceID>");
+ return -1;
+ } else if (argc < 9) {
+ print_strs(dcmi_thermalpolicy_set_parameters_vals,
+ "Set thermalpolicy instance parameters: "
+ "<volatile/nonvolatile/disabled> "
+ "<poweroff/nopoweroff/disabled> "
+ "<sel/nosel/disabled> <templimitByte> <exceptionTime>",
+ -1, 0);
+ return -1;
+ }
+ if (str2uchar(argv[2], &entityID) != 0) {
+ lprintf(LOG_ERR,
+ "Given Entity ID '%s' is invalid.",
+ argv[2]);
+ return (-1);
+ }
+ if (str2uchar(argv[3], &entityInst) != 0) {
+ lprintf(LOG_ERR,
+ "Given Instance ID '%s' is invalid.",
+ argv[3]);
+ return (-1);
+ }
+ persistanceFlag = (uint8_t) str2val2(argv[4], dcmi_thermalpolicy_set_parameters_vals);
+ actionHardPowerOff = (uint8_t) str2val2(argv[5], dcmi_thermalpolicy_set_parameters_vals);
+ actionLogToSEL = (uint8_t) str2val2(argv[6], dcmi_thermalpolicy_set_parameters_vals);
+ if (str2uchar(argv[7], &tempLimit) != 0) {
+ lprintf(LOG_ERR,
+ "Given Temp Limit '%s' is invalid.",
+ argv[7]);
+ return (-1);
+ }
+ if (str2ushort(argv[8], &samplingTime) != 0) {
+ lprintf(LOG_ERR,
+ "Given Sampling Time '%s' is invalid.",
+ argv[8]);
+ return (-1);
+ }
+ samplingTimeLSB = (samplingTime & 0xFF);
+ samplingTimeMSB = ((samplingTime & 0xFF00) >> 8);
+
+ rc = ipmi_dcmi_setthermalpolicy(intf,
+ entityID,
+ entityInst,
+ persistanceFlag,
+ actionHardPowerOff,
+ actionLogToSEL,
+ tempLimit,
+ samplingTimeLSB,
+ samplingTimeMSB);
+
+ break;
+ default:
+ print_strs(dcmi_thermalpolicy_vals,
+ "thermalpolicy <command>",
+ -1, 0);
+ return -1;
+ }
+ break;
+ }
+ case 0x08:
+ if(ipmi_dcmi_prnt_get_temp_readings(intf) < 0 ) {
+ lprintf(LOG_ERR,
+ "Error get temperature readings!");
+ }
+ break;
+ case 0x09:
+ if(ipmi_dcmi_prnt_getconfparam(intf) < 0 ) {
+ lprintf(LOG_ERR,
+ "Error Get DCMI Configuration Parameters!");
+ };
+ break;
+ case 0x0A:
+ {
+ switch (argc) {
+ case 2:
+ if (strncmp(argv[1], "activate_dhcp", 13) != 0) {
+ print_strs( dcmi_conf_param_vals,
+ "DCMI Configuration Parameters",
+ -1, 0);
+ return -1;
+ }
+ break;
+ default:
+ if (argc != 3 || strncmp(argv[1], "help", 4) == 0) {
+ print_strs(dcmi_conf_param_vals,
+ "DCMI Configuration Parameters",
+ -1, 0);
+ return -1;
+ }
+ }
+ if (strncmp(argv[1], "activate_dhcp", 13) == 0) {
+ rsp = ipmi_dcmi_setconfparam(intf, 1, 1);
+ } else {
+ uint16_t tmp_val = 0;
+ if (str2ushort(argv[2], &tmp_val) != 0) {
+ lprintf(LOG_ERR,
+ "Given %s '%s' is invalid.",
+ argv[1], argv[2]);
+ return (-1);
+ }
+ rsp = ipmi_dcmi_setconfparam(intf,
+ str2val2(argv[1], dcmi_conf_param_vals),
+ tmp_val);
+ }
+ if (chk_rsp(rsp)) {
+ lprintf(LOG_ERR,
+ "Error Set DCMI Configuration Parameters!");
+ }
+ break;
+ }
+ case 0x0B:
+ {
+ if (intf->session == NULL) {
+ lprintf(LOG_ERR,
+ "\nOOB discovery is available only via RMCP interface.");
+ return -1;
+ }
+ if(ipmi_dcmi_prnt_oobDiscover(intf) < 0) {
+ lprintf(LOG_ERR, "\nOOB discovering capabilities failed.");
+ return -1;
+ }
+ break;
+ }
+ default:
+ /* couldn't detect what the user entered */
+ print_strs(dcmi_cmd_vals,
+ "Data Center Management Interface commands",
+ -1, 0);
+ return -1;
+ break;
+ }
+ printf("\n");
+ return 0;
+}
+
+/* Display DCMI sensor information
+ * Uses the ipmi_sdr_get_next_header to read SDR header and compare to the
+ * target Record ID. Then either ipmi_sensor_print_full or
+ * ipmi_sensor_print_compact is called to print the data
+ *
+ * @intf: ipmi interface handler
+ * @rec_id: target Record ID
+ */
+static int
+ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id)
+{
+ struct sdr_get_rs *header;
+ struct ipmi_sdr_iterator *itr;
+ int rc = 0;
+ uint8_t *rec = NULL;
+
+ itr = ipmi_sdr_start(intf, 0);
+ if (itr == NULL) {
+ lprintf(LOG_ERR, "Unable to open SDR for reading");
+ return (-1);
+ }
+
+ while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) {
+ if (header->id == rec_id) {
+ break;
+ }
+ }
+ if (header == NULL) {
+ lprintf(LOG_DEBUG, "header == NULL");
+ ipmi_sdr_end(intf, itr);
+ return (-1);
+ }
+ /* yes, we found the SDR for this record ID, now get full record */
+ rec = ipmi_sdr_get_record(intf, header, itr);
+ if (rec == NULL) {
+ lprintf(LOG_DEBUG, "rec == NULL");
+ ipmi_sdr_end(intf, itr);
+ return (-1);
+ }
+ if ((header->type == SDR_RECORD_TYPE_FULL_SENSOR) ||
+ (header->type == SDR_RECORD_TYPE_COMPACT_SENSOR)) {
+ rc = ipmi_sdr_print_rawentry(intf, header->type,
+ rec, header->length);
+ } else {
+ rc = (-1);
+ }
+ free(rec);
+ rec = NULL;
+ ipmi_sdr_end(intf, itr);
+ return rc;
+}