mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-05-10 18:47:22 +00:00
Commit is a response(and fix) to double-free bug in 'lib/ipmi_main.c' via username. Now, pointers should be set to NULL after calling free(). Reported-by: Ales Ledvinka
2015 lines
79 KiB
C
Executable File
2015 lines
79 KiB
C
Executable File
/*
|
||
* 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;
|
||
|
||
/*******************************************************************************
|
||
* 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", " Pltform power limit command options" },
|
||
{ 0x02, "sensors", " Prints the available DCMI sensors" },
|
||
{ 0x03, "asset_tag", " Prints the platforms asset tag" },
|
||
{ 0x04, "set_asset_tag", " Sets the platforms 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", " <sel_logging | power_off>" },
|
||
{ 0x01, "limit", " <number in Watts>" },
|
||
{ 0x02, "correction", "<number in milliseconds>" },
|
||
{ 0x03, "sample", " <number in seconds>" },
|
||
{ 0xFF, NULL, NULL }
|
||
};
|
||
|
||
/* power management/set action commands */
|
||
const struct dcmi_cmd dcmi_pwrmgmt_action_vals[] = {
|
||
{ 0x00, "No Action", "" },
|
||
{ 0x01, "Hard Power Off & Log Event to SEL", "" },
|
||
{ 0x11, "Log Event to SEL", "" },
|
||
{ 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->data[0]);
|
||
return 1;
|
||
} else if (rsp->ccode > 0) {
|
||
lprintf(LOG_ERR, "\n DCMI request failed because: %s (%x)",
|
||
val2str(rsp->ccode, completion_code_vals), rsp->data[0]);
|
||
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;
|
||
|
||
if (intf->opened == 0 && intf->open != NULL) {
|
||
if (intf->open(intf) < 0)
|
||
return (int) NULL;
|
||
}
|
||
|
||
|
||
struct ipmi_session *s;
|
||
|
||
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;
|
||
|
||
/* open port to BMC */
|
||
memset(&s->addr, 0, sizeof(struct sockaddr_in));
|
||
s->addr.sin_family = AF_INET;
|
||
s->addr.sin_port = htons(s->port);
|
||
|
||
rc = inet_pton(AF_INET, (const char *)s->hostname, &s->addr.sin_addr);
|
||
if (rc <= 0) {
|
||
struct hostent *host = gethostbyname((const char *)s->hostname);
|
||
if (host == NULL) {
|
||
lprintf(LOG_ERR, "Address lookup for %s failed",
|
||
s->hostname);
|
||
return -1;
|
||
}
|
||
s->addr.sin_family = host->h_addrtype;
|
||
memcpy(&s->addr.sin_addr, host->h_addr, host->h_length);
|
||
}
|
||
|
||
lprintf(LOG_DEBUG, "IPMI LAN host %s port %d",
|
||
s->hostname, ntohs(s->addr.sin_port));
|
||
|
||
intf->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||
if (intf->fd < 0) {
|
||
lperror(LOG_ERR, "Socket failed");
|
||
return -1;
|
||
}
|
||
|
||
/* connect to UDP socket so we get async errors */
|
||
rc = connect(intf->fd, (struct sockaddr *)&s->addr,
|
||
sizeof(struct sockaddr_in));
|
||
if (rc < 0) {
|
||
lperror(LOG_ERR, "Connect failed");
|
||
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 ipmi_rs * rsp;
|
||
rsp = ipmi_dcmi_getcapabilities(intf, selector);
|
||
|
||
if(chk_rsp(rsp))
|
||
return -1;
|
||
|
||
/* if there were no errors, the command worked! */
|
||
|
||
struct capabilities cape;
|
||
memcpy(&cape, rsp->data, sizeof (cape));
|
||
|
||
/* check to make sure that this is a 1.0 and 1.1 command */
|
||
if ((cape.conformance != IPMI_DCMI_CONFORM) && (cape.conformance != IPMI_DCMI_1_1_CONFORM)) {
|
||
printf("ERROR! This command is not available on this platform\n");
|
||
return -1;
|
||
}
|
||
|
||
/* check to make sure that this is a rev .01 or .02 */
|
||
if (cape.revision != 0x01 && cape.revision != 0x02) {
|
||
printf("ERROR! This command is not compatible with this version\n");
|
||
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 */
|
||
req.msg.data_len = length +3; /* How many times does req.msg.data need to read */
|
||
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){
|
||
printf("\nValue to long\n");
|
||
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 */
|
||
req.msg.data_len = 3; /* How many times does req.msg.data need to read */
|
||
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 */
|
||
req.msg.data_len = 3 + length; /* How many times does req.msg.data need to read */
|
||
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){
|
||
printf("\nValue to long\n");
|
||
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);
|
||
|
||
if(strncmp(intf->name, "lanplus", 7)) //because after call "Set mc id string" RMCP+ will go down we have no "rsp"
|
||
{
|
||
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);
|
||
}
|
||
|
||
static int ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id);
|
||
|
||
/*******************************************************************************
|
||
* 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;
|
||
uint8_t msg_data[4]; /* number of request data bytes */
|
||
|
||
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]); */
|
||
struct power_reading val;
|
||
memcpy(&val, rsp->data, sizeof (val));
|
||
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",
|
||
ctime((time_t *)&val.time_stamp));
|
||
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;
|
||
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 */
|
||
|
||
struct thermal_limit val;
|
||
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 */
|
||
|
||
msg_data[3] = ( ((persistanceFlag ?1:0)<<7) |
|
||
((actionHardPowerOff?1:0)<<6) |
|
||
((actionLogToSEL ?1:0)<<5)
|
||
); /* persistance and actions or disabled if no actions */
|
||
|
||
msg_data[4] = tempLimit;
|
||
|
||
msg_data[5] = samplingTimeLSB;
|
||
msg_data[6] = samplingTimeMSB;
|
||
|
||
memset(&req, 0, sizeof(req));
|
||
req.msg.netfn = IPMI_NETFN_DCGRP;
|
||
req.msg.cmd = IPMI_DCMI_SETTERMALLIMIT; /* Get thermal policy reading */
|
||
req.msg.data = msg_data; /* msg_data above */
|
||
req.msg.data_len = 7; /* 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("\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 */
|
||
req.msg.data_len = 5; /* how many times does req.msg.data need to read */
|
||
|
||
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 */
|
||
msg_data[2] = 0x00; /*Set Selector. Selects a given set of parameters under a given Parameter selector value. 00h if parameter doesn't use a Set Selector. */
|
||
|
||
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 */
|
||
req.msg.data_len = 3; /* how many times does req.msg.data need to read */
|
||
|
||
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;
|
||
|
||
for (param_selector=2 ; param_selector <= dcmi_conf_params; param_selector++)//We are not interested in parameter 1 which always will return 0
|
||
{
|
||
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 */
|
||
msg_data[2] = 0x00; /* Set Selector (use 00h for parameters that only have one set). */
|
||
|
||
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 */
|
||
req.msg.data_len = 5; /* how many times does req.msg.data need to read */
|
||
else
|
||
req.msg.data_len = 4; /* how many times does req.msg.data need to read */
|
||
|
||
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 */
|
||
req.msg.data_len = 3; /* how many times does req.msg.data need to read */
|
||
|
||
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;
|
||
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]); */
|
||
|
||
struct power_limit val;
|
||
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_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) */
|
||
uint8_t msg_data[15]; /* number of request data bytes */
|
||
uint32_t lvalue = strtol(value, NULL, 10);
|
||
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;
|
||
|
||
struct power_limit val;
|
||
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]);
|
||
*/
|
||
|
||
switch (str2val2(option, dcmi_pwrmgmt_set_usage_vals)) {
|
||
case 0x00:
|
||
/* action */
|
||
switch (str2val2(value, dcmi_pwrmgmt_action_vals)) {
|
||
case 0x01:
|
||
/* power_off */
|
||
val.action = 1;
|
||
break;
|
||
case 0x11:
|
||
/* sel_logging*/
|
||
val.action = 0x11;
|
||
break;
|
||
case 0xFF:
|
||
/* error - not a string we knew what to do with */
|
||
return -1;
|
||
}
|
||
break;
|
||
case 0x01:
|
||
/* limit */
|
||
val.limit = *(uint16_t*)(&lvalue);
|
||
break;
|
||
case 0x02:
|
||
/* correction */
|
||
val.correction = *(uint32_t*)(&lvalue);
|
||
break;
|
||
case 0x03:
|
||
/* sample */
|
||
val.sample = *(uint16_t*)(&lvalue);
|
||
break;
|
||
case 0xff:
|
||
/* no valid options */
|
||
return -1;
|
||
}
|
||
|
||
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 */
|
||
req.msg.data_len = 15; /* how many times does req.msg.data need to read */
|
||
|
||
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; /* Return code used when calling some of the dcmi commands */
|
||
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;
|
||
/* end discover */
|
||
|
||
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];
|
||
|
||
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 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 */
|
||
return -1;
|
||
}
|
||
*(uint16_t*)(&data[5]) = strtol(argv[4], NULL, 10);/* limit */
|
||
*(uint32_t*)(&data[7]) = strtol(argv[6], NULL, 10);/* correction */
|
||
data[11] = 0x00; /* reserved */
|
||
data[12] = 0x00; /* reserved */
|
||
*(uint16_t*)(&data[13]) = strtol(argv[8], NULL, 10); /* sample */
|
||
|
||
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) {
|
||
printf("Error getting asset tag!\n");
|
||
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) {
|
||
printf("\nError setting asset tag!\n");
|
||
return -1;
|
||
}
|
||
break;
|
||
}
|
||
/* end set asset tag */
|
||
case 0x05:
|
||
/* get management controller identifier string */
|
||
if(ipmi_dcmi_prnt_getmngctrlids(intf) < 0) {
|
||
printf("Error getting management controller identifier string!\n");
|
||
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) {
|
||
printf("Error setting management controller identifier string!\n");
|
||
return -1;
|
||
}
|
||
break;
|
||
}
|
||
/* end set management controller identifier string */
|
||
|
||
case 0x07:
|
||
{
|
||
uint8_t entityID, entityInst;
|
||
uint8_t persistanceFlag;
|
||
uint8_t actionHardPowerOff;
|
||
uint8_t actionLogToSEL;
|
||
uint8_t tempLimit;
|
||
uint16_t samplingTime;
|
||
uint8_t samplingTimeLSB;
|
||
uint8_t samplingTimeMSB;
|
||
|
||
/* Thermal policy get/set */
|
||
/* dcmitool dcmi thermalpolicy get */
|
||
|
||
switch (str2val2(argv[1], dcmi_thermalpolicy_vals)) {
|
||
case 0x00:
|
||
if (argc < 4)
|
||
{
|
||
printf("Get <entityID> <instanceID>\n");
|
||
return -1;
|
||
}
|
||
|
||
entityID = (uint8_t)strtol(argv[2], NULL,0);
|
||
entityInst = (uint8_t) strtol(argv[3], NULL, 0);
|
||
rc = ipmi_dcmi_getthermalpolicy(intf, entityID, entityInst);
|
||
break;
|
||
|
||
case 0x01:
|
||
if (argc < 4)
|
||
{
|
||
printf("Set <entityID> <instanceID>\n");
|
||
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;
|
||
}
|
||
|
||
entityID = (uint8_t) strtol(argv[2],NULL, 0);
|
||
entityInst = (uint8_t) strtol(argv[3], NULL, 0);
|
||
|
||
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);
|
||
tempLimit = (uint8_t) strtol(argv[7], NULL, 0);
|
||
samplingTime = (uint16_t) strtol(argv[8], NULL, 0);
|
||
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 )
|
||
{
|
||
printf("Error get temperature readings!\n");
|
||
};
|
||
break;
|
||
case 0x09:
|
||
if(ipmi_dcmi_prnt_getconfparam(intf) < 0 )
|
||
{
|
||
printf("Error Get DCMI Configuration Parameters!\n");
|
||
};
|
||
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 {
|
||
rsp = ipmi_dcmi_setconfparam(intf, str2val2(argv[1], dcmi_conf_param_vals), (uint16_t) strtol(argv[2], NULL, 0));
|
||
}
|
||
if(chk_rsp(rsp))
|
||
{
|
||
printf("Error Set DCMI Configuration Parameters!\n");
|
||
}
|
||
break;
|
||
}
|
||
case 0x0B:
|
||
{
|
||
if (intf->session == NULL){
|
||
printf("\nOOB discovery is available only via RMCP interface.\n");
|
||
return -1;
|
||
}
|
||
if(ipmi_dcmi_prnt_oobDiscover(intf) < 0)
|
||
{
|
||
printf("\nOOB discovering capabilities failed.\n");
|
||
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;
|
||
}
|