mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-05-12 11:37:23 +00:00
The nm module has a lot of repeated code such as searching for a subcommand, or verification of command line arguments. It also extensively uses magic numbers for option processing. This commit improves code reuse, reduces complexity of code, and gets rid of at least some of magic numbers in the code. This is a work in progress on this branch.
1900 lines
51 KiB
C
1900 lines
51 KiB
C
/*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
/* This file implements Intel Intelligent Power Node Manager commands
|
|
* according to the corresponding specification.
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <ipmitool/ipmi_dcmi.h>
|
|
#include <ipmitool/ipmi_nm.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_time.h>
|
|
|
|
/*
|
|
* Start of Node Manager Operations
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
* The structs below are the NM 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(). *
|
|
******************************************************************************/
|
|
|
|
/* Primary Node Manager commands */
|
|
|
|
/* clang-format off */
|
|
|
|
/* NM commands (local, not from the specification */
|
|
|
|
#define NM_UNDEF 0xFF
|
|
|
|
enum {
|
|
NM_DISCOVER,
|
|
NM_CAPAB,
|
|
NM_POL_CTRL,
|
|
NM_POL_ADD_RM,
|
|
NM_STATS,
|
|
NM_POWER,
|
|
NM_SUSPEND,
|
|
NM_RESET,
|
|
NM_ALERT,
|
|
NM_THRESHOLD
|
|
};
|
|
|
|
#define NM_CMD_END DCMI_CMD_END(NM_UNDEF)
|
|
|
|
const struct dcmi_cmd nm_cmd_vals[] = {
|
|
{ NM_DISCOVER, "discover", "Discover Node Manager" },
|
|
{ NM_CAPAB, "capability", "Get Node Manager Capabilities" },
|
|
{ NM_POL_CTRL, "control", "Enable/Disable Policy Control" },
|
|
{ NM_POL_ADD_RM, "policy", "Add/Remove Policies" },
|
|
{ NM_STATS, "statistics", "Get Statistics" },
|
|
{ NM_POWER, "power", "Set Power Draw Range" },
|
|
{ NM_SUSPEND, "suspend", "Set/Get Policy suspend periods" },
|
|
{ NM_RESET, "reset", "Reset Statistics" },
|
|
{ NM_ALERT, "alert", "Set/Get/Clear Alert destination" },
|
|
{ NM_THRESHOLD, "threshold", "Set/Get Alert Thresholds" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_ctl_cmds[] = {
|
|
{ 0x01, "enable", "<control scope>" },
|
|
{ 0x00, "disable", "<control scope>" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_ctl_domain[] = {
|
|
{ 0x00, "global", "" },
|
|
{ 0x02, "per_domain", "<platform|CPU|Memory> (default is platform)" },
|
|
{ 0x04, "per_policy", "<0-255>" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
/* Node Manager Domain codes */
|
|
|
|
enum {
|
|
NM_DOM_PLATFORM,
|
|
NM_DOM_CPU,
|
|
NM_DOM_MEMORY,
|
|
NM_DOM_PROT,
|
|
NM_DOM_IO,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_domain_vals[] = {
|
|
{ NM_DOM_PLATFORM, "platform", "" },
|
|
{ NM_DOM_CPU, "CPU", "" },
|
|
{ NM_DOM_MEMORY, "Memory", "" },
|
|
{ NM_DOM_PROT, "protection", "" },
|
|
{ NM_DOM_IO, "I/O", "" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_version_vals[] = {
|
|
{ 0x01, "1.0", "" },
|
|
{ 0x02, "1.5", "" },
|
|
{ 0x03, "2.0", "" },
|
|
{ 0x04, "2.5", "" },
|
|
{ 0x05, "3.0", "" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
enum {
|
|
NM_CAP_DOMAIN = 0x10,
|
|
NM_CAP_INLET,
|
|
NM_CAP_MISSING,
|
|
NM_CAP_RESET,
|
|
NM_CAP_BOOT,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_capability_opts[] = {
|
|
{ NM_CAP_DOMAIN, "domain", "<platform|CPU|Memory> (default is platform)" },
|
|
{ NM_CAP_INLET, "inlet", "Inlet temp trigger" },
|
|
{ NM_CAP_MISSING, "missing", "Missing Power reading trigger" },
|
|
{ NM_CAP_RESET, "reset", "Time after Host reset trigger" },
|
|
{ NM_CAP_BOOT, "boot", "Boot time policy" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_policy_type_vals[] = {
|
|
{ 0x00, "No trigger, use Power Limit", "" },
|
|
{ 0x01, "Inlet temp trigger", "" },
|
|
{ 0x02, "Missing Power reading trigger", "" },
|
|
{ 0x03, "Time after Host reset trigger", "" },
|
|
{ 0x04, "number of cores to disable at boot time", "" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_stats_opts[] = {
|
|
{ 0x01, "domain", "<platform|CPU|Memory> (default is platform)" },
|
|
{ 0x02, "policy_id", "<0-255>" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_stats_mode[] = {
|
|
{ 0x01, "power", "global power" },
|
|
{ 0x02, "temps", "inlet temperature" },
|
|
{ 0x11, "policy_power", "per policy power" },
|
|
{ 0x12, "policy_temps", "per policy inlet temp" },
|
|
{ 0x13, "policy_throt", "per policy throttling stats" },
|
|
{ 0x1B, "requests", "unhandled requests" },
|
|
{ 0x1C, "response", "response time" },
|
|
{ 0x1D, "cpu_throttling", "CPU throttling" },
|
|
{ 0x1E, "mem_throttling", "memory throttling" },
|
|
{ 0x1F, "comm_fail", "host communication failures" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_policy_action[] = {
|
|
{ 0x00, "get", "nm policy get policy_id <0-255> "
|
|
"[domain <platform|CPU|Memory>]" },
|
|
{ 0x04, "add", "nm policy add policy_id <0-255> "
|
|
"[domain <platform|CPU|Memory>] "
|
|
"correction auto|soft|hard power <watts> | "
|
|
"inlet <temp> trig_lim <param> "
|
|
"stats <seconds> enable|disable" },
|
|
{ 0x05, "remove", "nm policy remove policy_id <0-255> "
|
|
"[domain <platform|CPU|Memory>]" },
|
|
{ 0x06, "limiting", "nm policy limiting [domain <platform|CPU|Memory>]" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
const struct dcmi_cmd nm_policy_options[] = {
|
|
{ 0x01, "enable", "" },
|
|
{ 0x02, "disable", "" },
|
|
{ 0x03, "domain", "" },
|
|
{ 0x04, "inlet", "inlet air temp full limiting (SCRAM)" },
|
|
{ 0x06, "correction", "auto, soft, hard" },
|
|
{ 0x08, "power", "power limit in watts" },
|
|
{ 0x09, "trig_lim", "time to send alert" },
|
|
{ 0x0A, "stats", "moving window averaging time" },
|
|
{ 0x0B, "policy_id", "policy number" },
|
|
{ 0x0C, "volatile", "save policy in volatiel memory" },
|
|
{ 0x0D, "cores_off", "at boot time, disable N cores" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
/* if "trigger" command used from nm_policy_options */
|
|
const struct dcmi_cmd nm_trigger[] = {
|
|
{ 0x00, "none", "" },
|
|
{ 0x01, "temp", "" },
|
|
{ 0x02, "reset", "" },
|
|
{ 0x03, "boot", "" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
/* if "correction" used from nm_policy_options */
|
|
const struct dcmi_cmd nm_correction[] = {
|
|
{ 0x00, "auto", "" },
|
|
{ 0x01, "soft", "" },
|
|
{ 0x02, "hard", "" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
/* returned codes from get policy */
|
|
const struct dcmi_cmd nm_correction_vals[] = {
|
|
{ 0x00, "no T-state use", "" },
|
|
{ 0x01, "no T-state use", "" },
|
|
{ 0x02, "use T-states", "" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
/* if "exception" used from nm_policy_options */
|
|
const struct dcmi_cmd nm_exception[] = {
|
|
{ 0x00, "none", "" },
|
|
{ 0x01, "alert", "" },
|
|
{ 0x02, "shutdown", "" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_reset_mode[] = {
|
|
{ 0x00, "global", "" },
|
|
{ 0x01, "per_policy", "" },
|
|
{ 0x1B, "requests", "" },
|
|
{ 0x1C, "response", "" },
|
|
{ 0x1D, "throttling", "" },
|
|
{ 0x1E, "memory", "" },
|
|
{ 0x1F, "comm", "" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_power_range[] = {
|
|
{ 0x01, "domain", "domain <platform|CPU|Memory> (default is platform)" },
|
|
{ 0x02, "min", "min <integer value>" },
|
|
{ 0x03, "max", "max <integer value>" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_alert_opts[] = {
|
|
{ 0x01, "set", "nm alert set chan <chan> dest <dest> string <string>" },
|
|
{ 0x02, "get", "nm alert get" },
|
|
{ 0x03, "clear", "nm alert clear dest <dest>" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_set_alert_param[] = {
|
|
{ 0x01, "chan", "chan <channel>" },
|
|
{ 0x02, "dest", "dest <destination>" },
|
|
{ 0x03, "string", "string <string>" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_thresh_cmds[] = {
|
|
{ 0x01, "set", "nm thresh set [domain <platform|CPU|Memory>] "
|
|
"policy_id <policy> thresh_array" },
|
|
{ 0x02, "get", "nm thresh get [domain <platform|CPU|Memory>] "
|
|
"policy_id <policy>" },
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_thresh_param[] = {
|
|
{ 0x01, "domain", "<platform|CPU|Memory> (default is platform)" },
|
|
{ 0x02, "policy_id", "<0-255>" },
|
|
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct dcmi_cmd nm_suspend_cmds[] = {
|
|
{ 0x01, "set", "nm suspend set [domain <platform|CPU|Memory]> "
|
|
"policy_id <policy> <start> "
|
|
"<stop> <pattern>" },
|
|
{ 0x02, "get", "nm suspend get [domain <platform|CPU|Memory]> "
|
|
"policy_id <policy>" },
|
|
NM_CMD_END,
|
|
};
|
|
|
|
const struct valstr nm_ccode_vals[] = {
|
|
{ IPMI_NM_CC_POLICY_ID_INVALID,
|
|
"Policy ID Invalid" },
|
|
{ IPMI_NM_CC_POLICY_DOMAIN_INVALID,
|
|
"Domain ID Invalid" },
|
|
{ IPMI_NM_CC_POLICY_LIMIT_NONE,
|
|
"No policy is currently limiting for the specified domain ID" },
|
|
{ IPMI_NM_CC_POLICY_CORRECTION_RANGE,
|
|
"Correction Time out of range" },
|
|
{ IPMI_NM_CC_POLICY_TRIGGER_UNKNOWN,
|
|
"Unknown policy trigger type" },
|
|
{ IPMI_NM_CC_POLICY_TRIGGER_RANGE,
|
|
"Policy Trigger value out of range" },
|
|
{ IPMI_NM_CC_POLICY_PARAM_BUSY,
|
|
"Policy exists and param unchangeable while enabled" },
|
|
{ IPMI_NM_CC_POLICY_DOMAIN_ERR,
|
|
"Policies in given power domain cannot be created in the "
|
|
"current configuration" },
|
|
{ IPMI_NM_CC_POLICY_STATS_RANGE,
|
|
"Statistics Reporting Period out of range" },
|
|
{ IPMI_NM_CC_POLICY_VALUE_INVALID,
|
|
"Invalid value for Aggressive CPU correction field" },
|
|
{ IPMI_NM_CC_POWER_LIMIT_RANGE,
|
|
"Power Limit out of range" },
|
|
{ IPMI_NM_CC_STATS_MODE_INVALID,
|
|
"Invalid Mode" },
|
|
{ IPMI_CC_OUT_OF_SPACE,
|
|
"No space available" },
|
|
{ IPMI_CC_INSUFFICIENT_PRIVILEGES,
|
|
"Insufficient privilege level or other security restriction" },
|
|
{ IPMI_CC_ILLEGAL_COMMAND_DISABLED,
|
|
"Command subfunction disabled or unavailable" },
|
|
{ 0xFF, NULL },
|
|
};
|
|
/* clang-format on */
|
|
|
|
/* End strings */
|
|
|
|
/**
|
|
* @brief Get the NM subcommand number from command line arguments
|
|
* @param[in] argc Number of elements in \p argv
|
|
* @param[in] argv Array of command line arguments with \p argc elements
|
|
* @param[in] cmds Array of acceptable NM subcommands
|
|
* @param[in] cmd The name of the parent command
|
|
* @param[in] expected_args The minimum expected number of arguments to the
|
|
* subcommand
|
|
*/
|
|
static
|
|
uint8_t nm_get_cmd(int argc, const char **argv,
|
|
struct dcmi_cmd *cmds,
|
|
const char *cmd,
|
|
int expected_args)
|
|
{
|
|
uint8_t action = NM_UNDEF;
|
|
|
|
if (argv[0] && argc > expected_args)
|
|
action = dcmi_str2val(argv[0], cmds);
|
|
|
|
if(NM_UNDEF == action)
|
|
{
|
|
uprintf(LOG_ERR, "%s:", cmd);
|
|
dcmi_print_strs(cmds, NULL, LOG_ERR, 0);
|
|
}
|
|
|
|
return action;
|
|
}
|
|
|
|
/* Check whether the Node Manager response from the BMC is an error
|
|
* @rsp: Response data structure
|
|
*/
|
|
static bool
|
|
is_nm_error(struct ipmi_rs *rsp)
|
|
{
|
|
bool rc = true; /* There IS an error */
|
|
|
|
/* if the response from the intf is NULL then the BMC is experiencing
|
|
* some issue and cannot complete the command
|
|
*/
|
|
if (!rsp) {
|
|
lprintf(LOG_ERR, "\n No response to NM request");
|
|
goto out;
|
|
}
|
|
|
|
/* 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 dictionary or the generic IPMI codes dictionary.
|
|
*/
|
|
if (rsp->ccode) {
|
|
/* Try to find the code in NM dictionary */
|
|
lprintf(LOG_ERR, "\n NM request failed: %s",
|
|
specific_val2str(rsp->ccode,
|
|
nm_ccode_vals,
|
|
completion_code_vals),
|
|
rsp->ccode);
|
|
goto out;
|
|
}
|
|
|
|
/* The code was OK, but was it an NM firmware at all? */
|
|
if (!nm_check_id(rsp->data)) {
|
|
printf("\n No valid NM ID in response! (%06x)",
|
|
ipmi24toh(rsp->data));
|
|
goto out;
|
|
}
|
|
|
|
rc = false; /* No error */
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
/* Node Manager discover */
|
|
static int
|
|
_ipmi_nm_discover(struct ipmi_intf *intf, struct nm_discover *disc)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
|
|
|
|
nm_set_id(msg_data);
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_GET_VERSION;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 3;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
memcpy(disc, rsp->data, sizeof(struct nm_discover));
|
|
return 0;
|
|
}
|
|
/* Get NM capabilities
|
|
*
|
|
* This function returns the available capabilities of the platform.
|
|
*
|
|
* returns success/failure
|
|
*
|
|
* @intf: ipmi interface handler
|
|
* @caps: fills in capability struct
|
|
*/
|
|
static int
|
|
_ipmi_nm_getcapabilities(struct ipmi_intf *intf, uint8_t domain,
|
|
uint8_t trigger, struct nm_capability *caps)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */
|
|
|
|
nm_set_id(msg_data);
|
|
msg_data[3] = domain;
|
|
msg_data[4] = trigger; /* power control policy or trigger */
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_GET_CAP;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 5;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
memcpy(caps, rsp->data, sizeof(struct nm_capability));
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_ipmi_nm_get_policy(struct ipmi_intf *intf, uint8_t domain, uint8_t policy_id,
|
|
struct nm_get_policy *policy)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */
|
|
|
|
nm_set_id(msg_data);
|
|
msg_data[3] = domain;
|
|
msg_data[4] = policy_id;
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_GET_POLICY;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 5;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
memcpy(policy, rsp->data, sizeof(struct nm_get_policy));
|
|
return 0;
|
|
}
|
|
static int
|
|
_ipmi_nm_set_policy(struct ipmi_intf *intf, struct nm_policy *policy)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_SET_POLICY;
|
|
req.msg.data = (uint8_t *)policy;
|
|
req.msg.data_len = sizeof(struct nm_policy);
|
|
nm_set_id(policy->intel_id);
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_ipmi_nm_policy_limiting(struct ipmi_intf *intf, uint8_t domain)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[4]; /* 'raw' data to be sent to the BMC */
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_LIMITING;
|
|
nm_set_id(msg_data);
|
|
msg_data[3] = domain;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 4;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
/* check for special case error of no policy is limiting */
|
|
if (rsp && (rsp->ccode == IPMI_NM_CC_POLICY_LIMIT_NONE))
|
|
return 0x80;
|
|
else if (is_nm_error(rsp))
|
|
return -1;
|
|
return rsp->data[0];
|
|
}
|
|
|
|
static int
|
|
_ipmi_nm_control(struct ipmi_intf *intf, uint8_t scope,
|
|
uint8_t domain, uint8_t policy_id)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */
|
|
|
|
nm_set_id(msg_data);
|
|
msg_data[3] = scope;
|
|
msg_data[4] = domain;
|
|
msg_data[5] = policy_id;
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_POLICY_CTL;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 6;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Get NM statistics
|
|
*
|
|
* This function returns the statistics
|
|
*
|
|
* returns success/failure
|
|
*
|
|
* @intf: ipmi interface handler
|
|
* @selector: Parameter selector
|
|
*/
|
|
static int
|
|
_ipmi_nm_statistics(struct ipmi_intf *intf, uint8_t mode, uint8_t domain,
|
|
uint8_t policy_id, struct nm_statistics *caps)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */
|
|
|
|
nm_set_id(msg_data);
|
|
msg_data[3] = mode;
|
|
msg_data[4] = domain;
|
|
msg_data[5] = policy_id;
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_GET_STATS;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 6;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
memcpy(caps, rsp->data, sizeof(struct nm_statistics));
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_ipmi_nm_reset_stats(struct ipmi_intf *intf, uint8_t mode,
|
|
uint8_t domain, uint8_t policy_id)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */
|
|
|
|
nm_set_id(msg_data);
|
|
msg_data[3] = mode;
|
|
msg_data[4] = domain;
|
|
msg_data[5] = policy_id;
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_RESET_STATS;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 6;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_nm_set_range(struct ipmi_intf *intf, uint8_t domain,
|
|
uint16_t minimum, uint16_t maximum)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[8]; /* 'raw' data to be sent to the BMC */
|
|
|
|
nm_set_id(msg_data);
|
|
msg_data[3] = domain;
|
|
msg_data[4] = minimum & 0xFF;
|
|
msg_data[5] = minimum >> 8;
|
|
msg_data[6] = maximum & 0xFF;
|
|
msg_data[7] = maximum >> 8;
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_SET_POWER;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 8;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_ipmi_nm_get_alert(struct ipmi_intf *intf, struct nm_set_alert *alert)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
|
|
|
|
nm_set_id(msg_data);
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_GET_ALERT_DS;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 3;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
memcpy(alert, rsp->data, sizeof(struct nm_set_alert));
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_ipmi_nm_set_alert(struct ipmi_intf *intf, struct nm_set_alert *alert)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */
|
|
|
|
nm_set_id(msg_data);
|
|
msg_data[3] = alert->chan;
|
|
msg_data[4] = alert->dest;
|
|
msg_data[5] = alert->string;
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_SET_ALERT_DS;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 6;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*
|
|
* get alert threshold values.
|
|
*
|
|
* the list pointer is assumed to point to an array of 16 short integers.
|
|
* This array is filled in for valid thresholds returned.
|
|
*/
|
|
static int
|
|
_ipmi_nm_get_thresh(struct ipmi_intf *intf, uint8_t domain,
|
|
uint8_t policy_id, uint16_t *list)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */
|
|
|
|
nm_set_id(msg_data);
|
|
msg_data[3] = domain;
|
|
msg_data[4] = policy_id;
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_GET_ALERT_TH;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 5;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
if (rsp->data[3] > 0)
|
|
*list++ = (rsp->data[5] << 8) | rsp->data[4];
|
|
if (rsp->data[3] > 1)
|
|
*list++ = (rsp->data[7] << 8) | rsp->data[6];
|
|
if (rsp->data[3] > 2)
|
|
*list = (rsp->data[9] << 8) | rsp->data[8];
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_ipmi_nm_set_thresh(struct ipmi_intf *intf, struct nm_thresh * thresh)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[IPMI_NM_SET_THRESH_LEN]; /* 'raw' data to be sent to the BMC */
|
|
|
|
memset(&msg_data, 0, sizeof(msg_data));
|
|
nm_set_id(msg_data);
|
|
msg_data[3] = thresh->domain;
|
|
msg_data[4] = thresh->policy_id;
|
|
msg_data[5] = thresh->count;
|
|
if (thresh->count > 0) {
|
|
msg_data[7] = thresh->thresholds[0] >> 8;
|
|
msg_data[6] = thresh->thresholds[0] & 0xFF;
|
|
}
|
|
if (thresh->count > 1) {
|
|
msg_data[9] = thresh->thresholds[1] >> 8;
|
|
msg_data[8] = thresh->thresholds[1] & 0xFF;
|
|
}
|
|
if (thresh->count > 2) {
|
|
msg_data[11] = thresh->thresholds[2] >> 8;
|
|
msg_data[10] = thresh->thresholds[2] & 0xFF;
|
|
}
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_SET_ALERT_TH;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 6 + (thresh->count * 2);
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*
|
|
* get suspend periods
|
|
*
|
|
*/
|
|
static int
|
|
_ipmi_nm_get_suspend(struct ipmi_intf *intf, uint8_t domain,
|
|
uint8_t policy_id, int *count,
|
|
struct nm_period *periods)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */
|
|
int i;
|
|
|
|
nm_set_id(msg_data);
|
|
msg_data[3] = domain;
|
|
msg_data[4] = policy_id;
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_GET_SUSPEND;
|
|
req.msg.data = msg_data;
|
|
req.msg.data_len = 5;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
*count = rsp->data[3];
|
|
for (i = 0; i < rsp->data[3]; i += 3, periods++) {
|
|
periods->start = rsp->data[4 + i];
|
|
periods->stop = rsp->data[5 + i];
|
|
periods->repeat = rsp->data[6 + i];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_ipmi_nm_set_suspend(struct ipmi_intf *intf, struct nm_suspend *suspend)
|
|
{
|
|
struct ipmi_rq req; /* request data to send to the BMC */
|
|
struct ipmi_rs *rsp;
|
|
uint8_t msg_data[21]; /* 6 control bytes + 5 suspend periods, 3 bytes per
|
|
period */
|
|
struct nm_period *periods;
|
|
int i;
|
|
|
|
nm_set_id(msg_data);
|
|
msg_data[3] = suspend->domain;
|
|
msg_data[4] = suspend->policy_id;
|
|
msg_data[5] = suspend->count;
|
|
for (i = 0, periods = &suspend->period[0];
|
|
i < (suspend->count * 3);
|
|
i += 3, periods++)
|
|
{
|
|
msg_data[6 + i] = periods->start;
|
|
msg_data[7 + i] = periods->stop;
|
|
msg_data[8 + i] = periods->repeat;
|
|
}
|
|
memset(&req, 0, sizeof(req));
|
|
req.msg.data_len = 6 + (suspend->count * 3);
|
|
req.msg.netfn = IPMI_NETFN_OEM;
|
|
req.msg.cmd = IPMI_NM_SET_SUSPEND;
|
|
req.msg.data = msg_data;
|
|
rsp = intf->sendrecv(intf, &req);
|
|
if (is_nm_error(rsp)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipmi_nm_getcapabilities(struct ipmi_intf *intf, int argc, char **argv)
|
|
{
|
|
uint8_t option;
|
|
uint8_t domain = 0; /* default domain of platform */
|
|
uint8_t trigger = 0; /* default power policy (no trigger) */
|
|
struct nm_capability caps = {0};
|
|
|
|
trigger = nm_get_cmd(argc, argv, nm_capability_opts,
|
|
"Capability commands", 0);
|
|
if (NM_UNDEF == trigger) {
|
|
return -1;
|
|
}
|
|
|
|
if (NM_CAP_DOMAIN == trigger) {
|
|
/* get domain scope */
|
|
domain = nm_get_cmd(--argc, ++argv, nm_domain_vals,
|
|
"Domain Scope", 0);
|
|
if (NM_UNDEF == domain)
|
|
domain = NM_DOM_PLATFORM;
|
|
}
|
|
|
|
if (_ipmi_nm_getcapabilities(intf, domain, trigger, &caps))
|
|
return -1;
|
|
|
|
if (csv_output) {
|
|
printf("%d,%u,%u,%u,%u,%u,%u,%s\n",
|
|
caps.max_settings, caps.max_value, caps.min_value,
|
|
caps.min_corr / 1000, caps.max_corr / 1000,
|
|
caps.min_stats, caps.max_stats,
|
|
dcmi_val2str(caps.scope & 0xF, nm_domain_vals));
|
|
return 0;
|
|
}
|
|
|
|
printf(" power policies:\t\t%d\n", caps.max_settings);
|
|
switch (trigger) {
|
|
case NM_CAP_DOMAIN: /* power */
|
|
printf(" max_power\t\t%7u Watts\n min_power\t\t%7u Watts\n",
|
|
caps.max_value, caps.min_value);
|
|
break;
|
|
case NM_CAP_INLET: /* Inlet */
|
|
printf(" max_temp\t\t%7u C\n min_temp\t\t%7u C\n",
|
|
caps.max_value, caps.min_value);
|
|
break;
|
|
case NM_CAP_MISSING: /* Missing reading time */
|
|
case NM_CAP_RESET: /* Time after host reset */
|
|
printf(" max_time\t\t%7u Secs\n min_time\t\t%7u Secs\n",
|
|
caps.max_value / 10, caps.min_value / 10);
|
|
break;
|
|
case NM_CAP_BOOT: /* boot time policy does not use these values */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
printf(" min_corr\t\t%7u secs\n max_corr\t\t%7u secs\n",
|
|
caps.min_corr / 1000, caps.max_corr / 1000);
|
|
printf(" min_stats\t\t%7u secs\n max_stats\t\t%7u secs\n",
|
|
caps.min_stats, caps.max_stats);
|
|
printf(" domain scope:\t%s\n",
|
|
dcmi_val2str(caps.scope & 0xF, nm_domain_vals));
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipmi_nm_get_policy(struct ipmi_intf *intf, int argc, char **argv)
|
|
{
|
|
uint8_t option;
|
|
uint8_t domain = 0; /* default domain of platform */
|
|
uint8_t policy_id = -1;
|
|
uint8_t have_policy_id = FALSE;
|
|
struct nm_get_policy policy;
|
|
|
|
memset(&policy, 0, sizeof(policy));
|
|
|
|
while (--argc) {
|
|
argv++;
|
|
if (!argv[0]) break;
|
|
if ((option = dcmi_str2val(argv[0], nm_policy_options)) == 0xFF) {
|
|
dcmi_print_strs(nm_policy_options,
|
|
"Get Policy commands", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
switch (option) {
|
|
case 0x03: /* get domain scope */
|
|
if ((domain = dcmi_str2val(argv[1], nm_domain_vals)) == 0xFF) {
|
|
dcmi_print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
policy.domain |= domain & 0xF;
|
|
break;
|
|
case 0x0B: /* policy id */
|
|
if (str2uchar(argv[1], &policy_id) < 0) {
|
|
lprintf(LOG_ERR,
|
|
" Policy ID must be a positive "
|
|
"integer (0-255)\n");
|
|
return -1;
|
|
}
|
|
have_policy_id = TRUE;
|
|
break;
|
|
default:
|
|
printf(" Unknown command 0x%x, skipping.\n", option);
|
|
break;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
if (!have_policy_id) {
|
|
dcmi_print_strs(nm_stats_opts,
|
|
"Missing policy_id parameter:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
if (_ipmi_nm_get_policy(intf, policy.domain, policy_id, &policy))
|
|
return -1;
|
|
if (csv_output) {
|
|
printf("%s,0x%x,%s,%s,%s,%u,%u,%u,%u,%s\n",
|
|
dcmi_val2str(policy.domain & 0xF, nm_domain_vals),
|
|
policy.domain,
|
|
(policy.policy_type & 0x10) ? "power" : "nopower ",
|
|
dcmi_val2str(policy.policy_type & 0xF, nm_policy_type_vals),
|
|
dcmi_val2str(policy.policy_exception, nm_exception),
|
|
policy.policy_limits,
|
|
policy.corr_time,
|
|
policy.trigger_limit,
|
|
policy.stats_period,
|
|
policy.policy_type & 0x80 ? "volatile" : "non-volatile");
|
|
return 0;
|
|
}
|
|
printf(" Power domain: %s\n",
|
|
dcmi_val2str(policy.domain & 0xF, nm_domain_vals));
|
|
printf(" Policy is %s %s%s%s\n",
|
|
(policy.domain & 0x10) ? "enabled" : "not enabled",
|
|
(policy.domain & 0x20) ? "per Domain " : "",
|
|
(policy.domain & 0x40) ? "Globally " : "",
|
|
(policy.domain & 0x80) ? "via DCMI api " : "");
|
|
printf(" Policy is %sa power control type.\n",
|
|
(policy.policy_type & 0x10) ? "" : "not ");
|
|
printf(" Policy Trigger Type: %s\n",
|
|
dcmi_val2str(policy.policy_type & 0xF, nm_policy_type_vals));
|
|
printf(" Correction Aggressiveness: %s\n",
|
|
dcmi_val2str((policy.policy_type >> 5) & 0x3, nm_correction_vals));
|
|
printf(" Policy Exception Actions: %s\n",
|
|
dcmi_val2str(policy.policy_exception, nm_exception));
|
|
printf(" Power Limit: %u Watts\n",
|
|
policy.policy_limits);
|
|
printf(" Correction Time Limit: %u milliseconds\n",
|
|
policy.corr_time);
|
|
printf(" Trigger Limit: %u units\n",
|
|
policy.trigger_limit);
|
|
printf(" Statistics Reporting Period: %u seconds\n",
|
|
policy.stats_period);
|
|
printf(" Policy retention: %s\n",
|
|
(policy.policy_type & 0x80) ? "volatile" : "non-volatile");
|
|
if ((policy_id == 0) && ((policy.domain & 0xf) == 0x3))
|
|
printf(" HW Prot Power domain: %s\n",
|
|
(policy.policy_type & 0x80) ? "Secondary" : "Primary");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipmi_nm_policy(struct ipmi_intf *intf, int argc, char **argv)
|
|
{
|
|
uint8_t action;
|
|
uint8_t option;
|
|
uint8_t correction;
|
|
uint8_t domain = 0; /* default domain of platform */
|
|
uint8_t policy_id = -1;
|
|
uint8_t have_policy_id = FALSE;
|
|
uint16_t power, period, inlet;
|
|
uint16_t cores;
|
|
uint32_t limit;
|
|
struct nm_policy policy;
|
|
|
|
argv++;
|
|
argc--;
|
|
if (!argv[0]
|
|
|| 0xFF == (action = dcmi_str2val(argv[0], nm_policy_action)))
|
|
{
|
|
dcmi_print_strs(nm_policy_action, "Policy commands", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
if (action == 0) /* get */
|
|
return (ipmi_nm_get_policy(intf, argc, argv));
|
|
memset(&policy, 0, sizeof(policy));
|
|
/*
|
|
* nm policy add [domain <param>] enable|disable policy_id <param>
|
|
* correction <opt> power <watts> limit <param>
|
|
* period <param>
|
|
* nm policy remove [domain <param>] policy_id <param>
|
|
* nm policy limiting {domain <param>]
|
|
*/
|
|
while (--argc > 0) {
|
|
argv++;
|
|
if (!argv[0])
|
|
break;
|
|
if ((option = dcmi_str2val(argv[0], nm_policy_options)) == 0xFF) {
|
|
dcmi_print_strs(nm_policy_options, "Policy options", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
switch (option) {
|
|
case 0x01: /* policy enable */
|
|
policy.domain |= IPMI_NM_POLICY_ENABLE;
|
|
break;
|
|
case 0x02: /* policy disable */
|
|
break; /* value is initialized to zero already */
|
|
case 0x03: /* get domain scope */
|
|
if ((domain = dcmi_str2val(argv[1], nm_domain_vals)) == 0xFF) {
|
|
dcmi_print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
policy.domain |= domain & 0xF;
|
|
break;
|
|
case 0x04: /* inlet */
|
|
if (str2ushort(argv[1], &inlet) < 0) {
|
|
printf("Inlet Temp value must be 20-45.\n");
|
|
return -1;
|
|
}
|
|
policy.policy_type |= 1;
|
|
policy.policy_limits = 0;
|
|
policy.trigger_limit = inlet;
|
|
break;
|
|
case 0x06: /* get correction action */
|
|
if (action == 0x5)
|
|
break; /* skip if this is a remove */
|
|
if ((correction = dcmi_str2val(argv[1], nm_correction)) == 0xFF) {
|
|
dcmi_print_strs(nm_correction,
|
|
"Correction Actions",
|
|
LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
policy.policy_type |= (correction << 5);
|
|
break;
|
|
case 0x07: /* not implemented */
|
|
break;
|
|
case 0x08: /* power */
|
|
if (str2ushort(argv[1], &power) < 0) {
|
|
printf("Power limit value must be 0-500.\n");
|
|
return -1;
|
|
}
|
|
policy.policy_limits = power;
|
|
break;
|
|
case 0x09: /* trigger limit */
|
|
if (str2uint(argv[1], &limit) < 0) {
|
|
printf("Trigger Limit value must be positive integer.\n");
|
|
return -1;
|
|
}
|
|
policy.corr_time = limit;
|
|
break;
|
|
case 0x0A: /* statistics period */
|
|
if (str2ushort(argv[1], &period) < 0) {
|
|
printf("Statistics Reporting Period must be a positive "
|
|
"integer.\n");
|
|
return -1;
|
|
}
|
|
policy.stats_period = period;
|
|
break;
|
|
case 0x0B: /* policy ID */
|
|
if (str2uchar(argv[1], &policy_id) < 0) {
|
|
printf("Policy ID must be a positive integer (0-255)\n");
|
|
return -1;
|
|
}
|
|
policy.policy_id = policy_id;
|
|
have_policy_id = TRUE;
|
|
break;
|
|
case 0x0C: /* volatile */
|
|
policy.policy_type |= 0x80;
|
|
break;
|
|
case 0x0D: /* cores_off, number of cores to disable at boot time */
|
|
policy.policy_type |= 4;
|
|
if (str2ushort(argv[1], &cores) < 0) {
|
|
printf("number of cores disabled must be 1-127.\n");
|
|
return -1;
|
|
}
|
|
if ((cores < 1) || (cores > 127)) {
|
|
printf("number of cores disabled must be 1-127.\n");
|
|
return -1;
|
|
}
|
|
policy.policy_type |= 4;
|
|
policy.policy_limits = cores << 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
if (action == 0x06) { /* limiting */
|
|
limit = _ipmi_nm_policy_limiting(intf, domain);
|
|
if (limit == (uint32_t) -1) {
|
|
return -1;
|
|
}
|
|
printf("limit %x\n", limit);
|
|
return 0;
|
|
}
|
|
if (!have_policy_id) {
|
|
dcmi_print_strs(nm_stats_opts,
|
|
"Missing policy_id parameter:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
if (action == 0x04) /* add */
|
|
policy.policy_type |= 0x10;
|
|
if (_ipmi_nm_set_policy(intf, &policy))
|
|
return -1;
|
|
return 0;
|
|
}
|
|
/* end policy */
|
|
|
|
static int
|
|
ipmi_nm_control(struct ipmi_intf *intf, int argc, char **argv)
|
|
{
|
|
uint8_t action;
|
|
uint8_t scope = 0; /* default control scope of global */
|
|
uint8_t domain = 0; /* default domain of platform */
|
|
uint8_t policy_id = -1;
|
|
uint8_t have_policy_id = FALSE;
|
|
|
|
argv++;
|
|
argc--;
|
|
/* nm_ctl_cmds returns 0 for disable, 1 for enable */
|
|
if (!argv[0]
|
|
|| 0xFF == (action = dcmi_str2val(argv[0], nm_ctl_cmds)))
|
|
{
|
|
dcmi_print_strs(nm_ctl_cmds, "Control parameters:",
|
|
LOG_ERR, 0);
|
|
dcmi_print_strs(nm_ctl_domain, "control Scope (required):",
|
|
LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
argv++;
|
|
while (--argc) {
|
|
/* nm_ctl_domain returns correct bit field except for action */
|
|
if (!argv[0]
|
|
|| 0xFF == (scope = dcmi_str2val(argv[0], nm_ctl_domain)))
|
|
{
|
|
dcmi_print_strs(nm_ctl_domain, "Control Scope (required):",
|
|
LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
argv++;
|
|
if (!argv[0])
|
|
break;
|
|
if (scope == 0x02) { /* domain */
|
|
if ((domain = dcmi_str2val(argv[0], nm_domain_vals)) == 0xFF) {
|
|
dcmi_print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
} else if (scope == 0x04) { /* per_policy */
|
|
if (str2uchar(argv[0], &policy_id) < 0) {
|
|
lprintf(LOG_ERR,
|
|
"Policy ID must be a positive integer (0-255)\n");
|
|
return -1;
|
|
}
|
|
have_policy_id = TRUE;
|
|
break;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
if ((scope == 0x04) && !have_policy_id) {
|
|
dcmi_print_strs(nm_stats_opts,
|
|
"Missing policy_id parameter:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
if (_ipmi_nm_control(intf, scope | (action & 1), domain, policy_id) < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipmi_nm_get_statistics(struct ipmi_intf *intf, int argc, char **argv)
|
|
{
|
|
uint8_t mode = 0;
|
|
uint8_t option;
|
|
uint8_t domain = 0; /* default domain of platform */
|
|
uint8_t policy_id = -1;
|
|
uint8_t have_policy_id = FALSE;
|
|
int policy_mode = 0;
|
|
char *units = "";
|
|
struct nm_statistics stats;
|
|
|
|
argv++;
|
|
if (!argv[0]
|
|
|| 0xFF == (mode = dcmi_str2val(argv[0], nm_stats_mode)))
|
|
{
|
|
dcmi_print_strs(nm_stats_mode, "Statistics commands", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
while (--argc) {
|
|
argv++;
|
|
if (!argv[0])
|
|
break;
|
|
if ((option = dcmi_str2val(argv[0], nm_stats_opts)) == 0xFF) {
|
|
dcmi_print_strs(nm_stats_opts, "Control Scope options", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
switch (option) {
|
|
case 0x01: /* get domain scope */
|
|
if ((domain = dcmi_str2val(argv[1], nm_domain_vals)) == 0xFF) {
|
|
dcmi_print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
break;
|
|
case 0x02: /* policy ID */
|
|
if (str2uchar(argv[1], &policy_id) < 0) {
|
|
lprintf(LOG_ERR,
|
|
"Policy ID must be a positive integer (0-255)\n");
|
|
return -1;
|
|
}
|
|
have_policy_id = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
|
|
switch (mode) {
|
|
case 0x01:
|
|
units = "Watts";
|
|
break;
|
|
case 0x02:
|
|
units = "Celsius";
|
|
break;
|
|
case 0x03:
|
|
units = "%";
|
|
break;
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
policy_mode = 1;
|
|
units = (mode == 0x11) ? "Watts" : (mode == 0x12) ? "Celsius" : " %";
|
|
if (!have_policy_id) {
|
|
dcmi_print_strs(nm_stats_opts,
|
|
"Missing policy_id parameter:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (_ipmi_nm_statistics(intf, mode, domain, policy_id, &stats))
|
|
return -1;
|
|
if (csv_output) {
|
|
printf("%s,%s,%s,%s,%s,%d,%d,%d,%d,%s,%d\n",
|
|
dcmi_val2str(stats.id_state & 0xF, nm_domain_vals),
|
|
((stats.id_state >> 4) & 1) ? (policy_mode ? "Policy Enabled"
|
|
: "Globally Enabled")
|
|
: "Disabled" ,
|
|
((stats.id_state >> 5) & 1) ? "active"
|
|
: "suspended",
|
|
((stats.id_state >> 6) & 1) ? "in progress"
|
|
: "suspended",
|
|
((stats.id_state >> 7) & 1) ? "triggered"
|
|
: "not triggered",
|
|
stats.curr_value,
|
|
stats.min_value,
|
|
stats.max_value,
|
|
stats.ave_value,
|
|
ipmi_timestamp_numeric(ipmi32toh(&stats.time_stamp)),
|
|
stats.stat_period);
|
|
return 0;
|
|
}
|
|
printf(" Power domain: %s\n",
|
|
dcmi_val2str(stats.id_state & 0xF, nm_domain_vals));
|
|
printf(" Policy/Global Admin state %s\n",
|
|
((stats.id_state >> 4) & 1) ? (policy_mode ? "Policy Enabled"
|
|
: "Globally Enabled")
|
|
: "Disabled" );
|
|
printf(" Policy/Global Operational state %s\n",
|
|
((stats.id_state >> 5) & 1) ? "active"
|
|
: "suspended");
|
|
printf(" Policy/Global Measurement state %s\n",
|
|
((stats.id_state >> 6) & 1) ? "in progress"
|
|
: "suspended");
|
|
printf(" Policy Activation state %s\n",
|
|
((stats.id_state >> 7) & 1) ? "triggered"
|
|
: "not triggered");
|
|
printf(" Instantaneous reading: %8d %s\n",
|
|
stats.curr_value, units);
|
|
printf(" Minimum during sampling period: %8d %s\n",
|
|
stats.min_value, units);
|
|
printf(" Maximum during sampling period: %8d %s\n",
|
|
stats.max_value, units);
|
|
printf(" Average reading over sample period: %8d %s\n",
|
|
stats.ave_value, units);
|
|
printf(" IPMI timestamp: %s\n",
|
|
ipmi_timestamp_numeric(ipmi32toh(&stats.time_stamp)));
|
|
printf(" Sampling period: %08d Seconds.\n",
|
|
stats.stat_period);
|
|
printf("\n");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipmi_nm_reset_statistics(struct ipmi_intf *intf, int argc, char **argv)
|
|
{
|
|
uint8_t mode;
|
|
uint8_t option;
|
|
uint8_t domain = 0; /* default domain of platform */
|
|
uint8_t policy_id = -1;
|
|
uint8_t have_policy_id = FALSE;
|
|
|
|
argv++;
|
|
if (!argv[0]
|
|
|| 0xFF == (mode = dcmi_str2val(argv[0], nm_reset_mode)))
|
|
{
|
|
dcmi_print_strs(nm_reset_mode, "Reset Statistics Modes:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
while (--argc) {
|
|
argv++;
|
|
if (!argv[0])
|
|
break;
|
|
if ((option = dcmi_str2val(argv[0], nm_stats_opts)) == 0xFF) {
|
|
dcmi_print_strs(nm_stats_opts, "Reset Scope options", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
switch (option) {
|
|
case 0x01: /* get domain scope */
|
|
if ((domain = dcmi_str2val(argv[1], nm_domain_vals)) == 0xFF) {
|
|
dcmi_print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
break;
|
|
case 0x02: /* policy ID */
|
|
if (str2uchar(argv[1], &policy_id) < 0) {
|
|
lprintf(LOG_ERR,
|
|
"Policy ID must be a positive integer (0-255)\n");
|
|
return -1;
|
|
}
|
|
have_policy_id = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
if (mode && !have_policy_id) {
|
|
dcmi_print_strs(nm_stats_opts,
|
|
"Missing policy_id parameter:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
if (_ipmi_nm_reset_stats(intf, mode, domain, policy_id) < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipmi_nm_set_range(struct ipmi_intf *intf, int argc, char **argv)
|
|
{
|
|
uint8_t domain = 0;
|
|
uint8_t param;
|
|
uint16_t minimum = -1;
|
|
uint16_t maximum = -1;
|
|
|
|
while (--argc) {
|
|
argv++;
|
|
if (!argv[0]) break;
|
|
if ((param = dcmi_str2val(argv[0], nm_power_range)) == 0xFF) {
|
|
dcmi_print_strs(nm_power_range,
|
|
"power range parameters:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
switch (param) {
|
|
case 0x01: /* get domain scope */
|
|
if ((domain = dcmi_str2val(argv[1], nm_domain_vals)) == 0xFF) {
|
|
dcmi_print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
break;
|
|
case 0x02: /* min */
|
|
if (str2ushort(argv[1], &minimum) < 0) {
|
|
lprintf(LOG_ERR, "Power minimum must be a positive integer.\n");
|
|
return -1;
|
|
}
|
|
break;
|
|
case 0x03: /* max */
|
|
if (str2ushort(argv[1], &maximum) < 0) {
|
|
lprintf(LOG_ERR, "Power maximum must be a positive integer.\n");
|
|
return -1;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
if ((minimum == 0xFFFF) || (maximum == 0xFFFF)) {
|
|
lprintf(LOG_ERR, "Missing parameters: nm power range min <minimum> "
|
|
"max <maximum>.\n");
|
|
return -1;
|
|
}
|
|
if (_nm_set_range(intf, domain, minimum, maximum) < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipmi_nm_get_alert(struct ipmi_intf *intf)
|
|
{
|
|
struct nm_set_alert alert;
|
|
|
|
memset(&alert, 0, sizeof(alert));
|
|
if (_ipmi_nm_get_alert(intf, &alert))
|
|
return -1;
|
|
if (csv_output) {
|
|
printf("%d,%s,0x%x,%s,0x%x\n",
|
|
alert.chan & 0xF,
|
|
(alert.chan >> 7) ? "not registered"
|
|
: "registered",
|
|
alert.dest,
|
|
(alert.string >> 7) ? "yes"
|
|
: "no",
|
|
alert.string & 0x7F);
|
|
return 0;
|
|
}
|
|
printf(" Alert Chan: %d\n",
|
|
alert.chan & 0xF);
|
|
printf(" Alert Receiver: %s\n",
|
|
(alert.chan >> 7) ? "not registered" : "registered");
|
|
printf(" Alert Lan Destination: 0x%x\n",
|
|
alert.dest);
|
|
printf(" Use Alert String: %s\n",
|
|
(alert.string >> 7) ? "yes" : "no");
|
|
printf(" Alert String Selector: 0x%x\n",
|
|
alert.string & 0x7F);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipmi_nm_alert(struct ipmi_intf *intf, int argc, char **argv)
|
|
{
|
|
uint8_t action;
|
|
uint8_t chan = -1;
|
|
uint8_t dest = -1;
|
|
uint8_t string = -1;
|
|
struct nm_set_alert alert;
|
|
|
|
argv++;
|
|
argc--;
|
|
if (!argv[0]
|
|
|| 0xFF == (action = dcmi_str2val(argv[0], nm_alert_opts)))
|
|
{
|
|
dcmi_print_strs(nm_alert_opts, "Alert commands", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
if (action == 0x02) /* get */
|
|
return (ipmi_nm_get_alert(intf));
|
|
/* set */
|
|
memset(&alert, 0, sizeof(alert));
|
|
while (--argc) {
|
|
argv++;
|
|
if (!argv[0])
|
|
break;
|
|
switch (dcmi_str2val(argv[0], nm_set_alert_param)) {
|
|
case 0x01: /* channel */
|
|
if (str2uchar(argv[1], &chan) < 0) {
|
|
lprintf(LOG_ERR,
|
|
"Alert Lan chan must be a positive integer.\n");
|
|
return -1;
|
|
}
|
|
if (action == 0x03) /* Clear */
|
|
chan |= 0x80; /* deactivate alert receiver */
|
|
break;
|
|
case 0x02: /* dest */
|
|
if (str2uchar(argv[1], &dest) < 0) {
|
|
lprintf(LOG_ERR,
|
|
"Alert Destination must be a positive integer.\n");
|
|
return -1;
|
|
}
|
|
break;
|
|
case 0x03: /* string number */
|
|
if (str2uchar(argv[1], &string) < 0) {
|
|
lprintf(LOG_ERR,
|
|
"Alert String # must be a positive integer.\n");
|
|
return -1;
|
|
}
|
|
string |= 0x80; /* set string select flag */
|
|
break;
|
|
case 0xFF: /* error, print usage */
|
|
dcmi_print_strs(nm_set_alert_param,
|
|
"Set alert Parameters:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
if ((chan == 0xFF) || (dest == 0xFF)) {
|
|
dcmi_print_strs(nm_set_alert_param,
|
|
"Must set alert chan and dest params.", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
if (string == 0xFF)
|
|
string = 0;
|
|
alert.chan = chan;
|
|
alert.dest = dest;
|
|
alert.string = string;
|
|
if (_ipmi_nm_set_alert(intf, &alert))
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipmi_nm_get_thresh(struct ipmi_intf *intf, uint8_t domain, uint8_t policy_id)
|
|
{
|
|
uint16_t list[3];
|
|
|
|
memset(list, 0, sizeof(list));
|
|
if (_ipmi_nm_get_thresh(intf, domain, policy_id, &list[0]))
|
|
return -1;
|
|
|
|
printf(" Alert Threshold domain: %s\n",
|
|
dcmi_val2str(domain, nm_domain_vals));
|
|
printf(" Alert Threshold Policy ID: %d\n",
|
|
policy_id);
|
|
printf(" Alert Threshold 1: %d\n",
|
|
list[0]);
|
|
printf(" Alert Threshold 2: %d\n",
|
|
list[1]);
|
|
printf(" Alert Threshold 3: %d\n",
|
|
list[2]);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ipmi_nm_thresh(struct ipmi_intf *intf, int argc, char **argv)
|
|
{
|
|
uint8_t option;
|
|
uint8_t action;
|
|
uint8_t domain = 0; /* default domain of platform */
|
|
uint8_t policy_id = -1;
|
|
uint8_t have_policy_id = FALSE;
|
|
struct nm_thresh thresh;
|
|
int i = 0;
|
|
|
|
argv++;
|
|
argc--;
|
|
/* set or get */
|
|
if (!argv[0] || argc < 3
|
|
|| 0xFF == (action = dcmi_str2val(argv[0], nm_thresh_cmds)))
|
|
{
|
|
dcmi_print_strs(nm_thresh_cmds, "Threshold commands", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
memset(&thresh, 0, sizeof(thresh));
|
|
while (--argc) {
|
|
argv++;
|
|
if (!argv[0])
|
|
break;
|
|
option = dcmi_str2val(argv[0], nm_thresh_param);
|
|
switch (option) {
|
|
case 0x01: /* get domain scope */
|
|
if ((domain = dcmi_str2val(argv[1], nm_domain_vals)) == 0xFF) {
|
|
dcmi_print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
case 0x02: /* policy ID */
|
|
if (str2uchar(argv[1], &policy_id) < 0) {
|
|
lprintf(LOG_ERR,
|
|
"Policy ID must be a positive integer (0-255)\n");
|
|
return -1;
|
|
}
|
|
have_policy_id = TRUE;
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
case 0xFF:
|
|
if (i > 2) {
|
|
lprintf(LOG_ERR, "Set Threshold requires 1, 2, or 3 "
|
|
"threshold integer values.\n");
|
|
return -1;
|
|
}
|
|
if (str2ushort(argv[0], &thresh.thresholds[i++]) < 0) {
|
|
lprintf(LOG_ERR,
|
|
"threshold value %d count must be a positive "
|
|
"integer.\n",
|
|
i);
|
|
return -1;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (!have_policy_id) {
|
|
dcmi_print_strs(nm_stats_opts,
|
|
"Missing policy_id parameter:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
if (action == 0x02) /* get */
|
|
return (ipmi_nm_get_thresh(intf, domain, policy_id));
|
|
thresh.domain = domain;
|
|
thresh.policy_id = policy_id;
|
|
thresh.count = i;
|
|
if (_ipmi_nm_set_thresh(intf, &thresh) < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static inline int
|
|
click2hour(int click)
|
|
{
|
|
if ((click * 6) < 60)
|
|
return 0;
|
|
return ((click * 6) / 60);
|
|
}
|
|
|
|
static inline int
|
|
click2min(int click)
|
|
{
|
|
if (!click)
|
|
return 0;
|
|
if ((click * 6) < 60)
|
|
return click * 6;
|
|
return (click * 6) % 60;
|
|
}
|
|
|
|
static int
|
|
ipmi_nm_get_suspend(struct ipmi_intf *intf, uint8_t domain, uint8_t policy_id)
|
|
{
|
|
struct nm_period periods[5];
|
|
int i;
|
|
int j;
|
|
int count = 0;
|
|
const char *days[7] = {"M", "Tu", "W", "Th", "F", "Sa", "Su"};
|
|
|
|
memset(periods, 0, sizeof(periods));
|
|
if (_ipmi_nm_get_suspend(intf, domain, policy_id, &count, &periods[0]))
|
|
return -1;
|
|
|
|
printf(" Suspend Policy domain: %s\n",
|
|
dcmi_val2str(domain, nm_domain_vals));
|
|
printf(" Suspend Policy Policy ID: %d\n", policy_id);
|
|
if (!count) {
|
|
printf(" No suspend Periods.\n");
|
|
return 0;
|
|
}
|
|
for (i = 0; i < count; i++) {
|
|
printf(" Suspend Period %d: %02d:%02d to "
|
|
"%02d:%02d",
|
|
i, click2hour(periods[i].start), click2min(periods[i].start),
|
|
click2hour(periods[i].stop), click2min(periods[i].stop));
|
|
if (periods[i].repeat)
|
|
printf(", ");
|
|
for (j = 0; j < 7; j++)
|
|
printf("%s", ((periods[i].repeat >> j) & 1)
|
|
? days[j]
|
|
: "");
|
|
printf("\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
bool
|
|
nm_suspend_process_periods(int *argc, char **argv, struct nm_suspend *suspend)
|
|
{
|
|
bool err = true;
|
|
int count = 0;
|
|
|
|
for (; *argc > 0 && count < IPMI_NM_SUSPEND_PERIOD_MAX;
|
|
*argc -= 3, argv += 3, count++)
|
|
{
|
|
if (*argc < 3) {
|
|
lprintf(LOG_ERR,
|
|
"Error: suspend period requires a "
|
|
"start, stop, and repeat values.\n");
|
|
goto out;
|
|
}
|
|
if (str2uchar(argv[0], &suspend->period[count].start) < 0) {
|
|
lprintf(LOG_ERR,
|
|
"suspend start value %d must be 0-239.\n",
|
|
count);
|
|
goto out;
|
|
}
|
|
if (str2uchar(argv[1], &suspend->period[count].stop) < 0) {
|
|
lprintf(LOG_ERR,
|
|
"suspend stop value %d must be 0-239.\n",
|
|
count);
|
|
goto out;
|
|
}
|
|
if (str2uchar(argv[2], &suspend->period[count].repeat) < 0) {
|
|
lprintf(LOG_ERR,
|
|
"suspend repeat value %d unable to convert.\n",
|
|
count);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (*argc <= 0) {
|
|
err = false;
|
|
}
|
|
out:
|
|
return err;
|
|
}
|
|
|
|
static
|
|
int
|
|
ipmi_nm_suspend(struct ipmi_intf *intf, int argc, char **argv)
|
|
{
|
|
uint8_t action;
|
|
uint8_t domain = 0; /* default domain of platform */
|
|
uint8_t policy_id = -1;
|
|
uint8_t have_policy_id = FALSE;
|
|
struct nm_suspend suspend;
|
|
|
|
argv++;
|
|
argc--;
|
|
/* set or get */
|
|
if (!argv[0] || argc < 3
|
|
|| 0xFF == (action = dcmi_str2val(argv[0], nm_suspend_cmds)))
|
|
{
|
|
dcmi_print_strs(nm_suspend_cmds,
|
|
"Suspend commands", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
memset(&suspend, 0, sizeof(suspend));
|
|
while (--argc > 0) {
|
|
argv++;
|
|
if (!argv[0])
|
|
break;
|
|
|
|
switch (dcmi_str2val(argv[0], nm_thresh_param)) {
|
|
case 0x01: /* get domain scope */
|
|
domain = dcmi_str2val(argv[1], nm_domain_vals);
|
|
if (0xFF == domain) {
|
|
dcmi_print_strs(nm_domain_vals,
|
|
"Domain Scope:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
case 0x02: /* policy ID */
|
|
if (str2uchar(argv[1], &policy_id) < 0) {
|
|
lprintf(LOG_ERR,
|
|
"Policy ID must be a positive "
|
|
"integer (0-255)\n");
|
|
return -1;
|
|
}
|
|
have_policy_id = TRUE;
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
case 0xFF: /* process periods */
|
|
if (nm_suspend_process_periods(&argc, argv, &suspend)) {
|
|
return -1;
|
|
}
|
|
if (argc <= 0) {
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!have_policy_id) {
|
|
dcmi_print_strs(nm_stats_opts,
|
|
"Missing policy_id parameter:", LOG_ERR, 0);
|
|
return -1;
|
|
}
|
|
|
|
if (action == 0x02) /* get */
|
|
return (ipmi_nm_get_suspend(intf, domain, policy_id));
|
|
|
|
suspend.domain = domain;
|
|
suspend.policy_id = policy_id;
|
|
if (_ipmi_nm_set_suspend(intf, &suspend) < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
/* Node Manager main
|
|
*
|
|
* @intf: nm interface handler
|
|
* @argc: argument count
|
|
* @argv: argument vector
|
|
*/
|
|
int
|
|
ipmi_nm_main(struct ipmi_intf *intf, int argc, char **argv)
|
|
{
|
|
struct nm_discover disc;
|
|
const char *cmdstr = argv[0];
|
|
uint8_t cmd;
|
|
int rc = -1;
|
|
|
|
if (!argc || !strcmp(cmdstr, "help")) {
|
|
dcmi_print_strs(nm_cmd_vals, "Node Manager Interface commands",
|
|
LOG_ERR, 0);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* Get the command number and shift the argument list for
|
|
* subsequent handler calls to have their subcommand in argv[0]
|
|
*/
|
|
cmd = nm_get_cmd(argc--, argv++, nm_cmd_vals,
|
|
"Node Manager Interface", 0);
|
|
switch (cmd) {
|
|
/* discover */
|
|
case NM_DISCOVER:
|
|
rc = _ipmi_nm_discover(intf, &disc);
|
|
if (rc) break;
|
|
|
|
printf(" Node Manager Version %s\n",
|
|
dcmi_val2str(disc.nm_version, nm_version_vals));
|
|
printf(" revision %d.%d%d patch version %d\n",
|
|
disc.major_rev,
|
|
disc.minor_rev >> 4,
|
|
disc.minor_rev & 0xf,
|
|
disc.patch_version);
|
|
break;
|
|
|
|
/* capability */
|
|
case NM_CAPAB:
|
|
rc = ipmi_nm_getcapabilities(intf, argc, argv);
|
|
break;
|
|
|
|
/* policy control enable-disable */
|
|
case NM_POL_CTRL:
|
|
rc = ipmi_nm_control(intf, argc, argv);
|
|
break;
|
|
|
|
/* policy */
|
|
case NM_POL_ADD_RM:
|
|
rc = ipmi_nm_policy(intf, argc, argv);
|
|
break;
|
|
|
|
/* Get statistics */
|
|
case NM_STATS:
|
|
rc = ipmi_nm_get_statistics(intf, argc, argv);
|
|
break;
|
|
|
|
/* set power draw range */
|
|
case NM_POWER:
|
|
rc = ipmi_nm_set_range(intf, argc, argv);
|
|
break;
|
|
|
|
/* set/get suspend periods */
|
|
case NM_SUSPEND:
|
|
rc = ipmi_nm_suspend(intf, argc, argv);
|
|
break;
|
|
|
|
/* reset statistics */
|
|
case NM_RESET:
|
|
rc = ipmi_nm_reset_statistics(intf, argc, argv);
|
|
break;
|
|
|
|
/* set/get alert destination */
|
|
case NM_ALERT:
|
|
rc = ipmi_nm_alert(intf, argc, argv);
|
|
break;
|
|
|
|
/* set/get alert thresholds */
|
|
case NM_THRESHOLD:
|
|
rc = ipmi_nm_thresh(intf, argc, argv);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/* end nm */
|
|
|
|
|