From e29be41f1d014a55e93abd3e55ac23f158f5fa16 Mon Sep 17 00:00:00 2001 From: Dhruvaraj Subhashchandran Date: Tue, 16 Jan 2018 05:11:56 -0600 Subject: DCMI: Implement Get DCMI capabilities info command. This commit adds ipmi changes for supporting the get DCMI capabilities command Resolves openbmc/openbmc#2618 Change-Id: I7d0e7c132f4a8d459351e025fa2bfca9fcf1340b Signed-off-by: Dhruvaraj Subhashchandran --- dcmihandler.cpp | 131 ++++++++++++++++++++++++++++++++++++++++++++++ dcmihandler.hpp | 62 ++++++++++++++++++++++ host-ipmid-whitelist.conf | 1 + 3 files changed, 194 insertions(+) diff --git a/dcmihandler.cpp b/dcmihandler.cpp index ab3aa58..aa9f14e 100644 --- a/dcmihandler.cpp +++ b/dcmihandler.cpp @@ -7,6 +7,9 @@ #include #include #include +#include +#include +#include "nlohmann/json.hpp" #include "xyz/openbmc_project/Common/error.hpp" using namespace phosphor::logging; @@ -21,6 +24,11 @@ constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap"; constexpr auto POWER_CAP_PROP = "PowerCap"; constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable"; +constexpr auto DCMI_PARAMETER_REVISION = 2; +constexpr auto DCMI_SPEC_MAJOR_VERSION = 1; +constexpr auto DCMI_SPEC_MINOR_VERSION = 5; +constexpr auto DCMI_CAP_JSON_FILE = "/usr/share/ipmi-providers/dcmi_cap.json"; + using namespace phosphor::logging; namespace dcmi @@ -603,6 +611,126 @@ ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t netfn, ipmi_cmd_t cmd, return IPMI_CC_OK; } +//List of the capabilities under each parameter +dcmi::DCMICaps dcmiCaps = +{ +//Supported DCMI Capabilities + { + dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS, + { + 3, {{"PowerManagement", 2, 0, 1}, + {"OOBSecondaryLan", 3, 2, 1}, + {"SerialTMODE", 3, 1, 1}, + {"InBandSystemInterfaceChannel", 3, 0, 1} + } + } + }, +//Mandatory Platform Attributes + { + dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES, + { + 5, {{"SELAutoRollOver", 1, 15, 1}, + {"FlushEntireSELUponRollOver", 1, 14, 1}, + {"RecordLevelSELFlushUponRollOver", 1, 13, 1}, + {"NumberOfSELEntries", 1, 0, 12}, + {"TempMonitoringSamplingFreq", 5, 0, 8} + } + } + }, +//Optional Platform Attributes + { + dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES, + { + 2, {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7}, + {"BMCChannelNumber", 2, 4, 4}, + {"DeviceRivision", 2, 0, 4} + } + } + }, +//Manageability Access Attributes + { + dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES, + { + 3, {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8}, + {"OptionalSecondaryLanOOBSupport", 2, 0, 8}, + {"OptionalSerialOOBMTMODECapability", 3, 0, 8} + } + } + } +}; + +ipmi_ret_t getDCMICapabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, ipmi_response_t response, + ipmi_data_len_t data_len, ipmi_context_t context) +{ + + std::ifstream dcmiCapFile(DCMI_CAP_JSON_FILE); + if (!dcmiCapFile.is_open()) + { + log("DCMI Capabilities file not found"); + return IPMI_CC_UNSPECIFIED_ERROR; + } + + auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false); + if (data.is_discarded()) + { + log("DCMI Capabilities JSON parser failure"); + return IPMI_CC_UNSPECIFIED_ERROR; + } + + auto requestData = reinterpret_cast + (request); + + //get list of capabilities in a parameter + auto caps = + dcmiCaps.find(static_cast(requestData->param)); + if (caps == dcmiCaps.end()) + { + log("Invalid input parameter"); + return IPMI_CC_INVALID_FIELD_REQUEST; + } + + if (requestData->groupID != dcmi::groupExtId) + { + *data_len = 0; + return IPMI_CC_INVALID_FIELD_REQUEST; + } + + auto responseData = reinterpret_cast + (response); + + //For each capabilities in a parameter fill the data from + //the json file based on the capability name. + for (auto cap : caps->second.capList) + { + //If the data is beyond first byte boundary, insert in a + //16bit pattern for example number of SEL entries are represented + //in 12bits. + if ((cap.length + cap.position) > 8) + { + //Read the value corresponding to capability name and assign to + //16bit bitset. + std::bitset<16> val(data.value(cap.name.c_str(), 0)); + val <<= cap.position; + reinterpret_cast(responseData->data)[ + (cap.bytePosition - 1) / sizeof(uint16_t)] |= val.to_ulong(); + } + else + { + responseData->data[cap.bytePosition - 1] |= + data.value(cap.name.c_str(), 0) << cap.position; + } + } + + responseData->groupID = dcmi::groupExtId; + responseData->major = DCMI_SPEC_MAJOR_VERSION; + responseData->minor = DCMI_SPEC_MINOR_VERSION; + responseData->paramRevision = DCMI_PARAMETER_REVISION; + *data_len = sizeof(*responseData) + caps->second.size; + + return IPMI_CC_OK; +} + void register_netfn_dcmi_functions() { // @@ -653,6 +781,9 @@ void register_netfn_dcmi_functions() ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR, NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN); + // + ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES, + NULL, getDCMICapabilities, PRIVILEGE_USER); return; } // 956379 diff --git a/dcmihandler.hpp b/dcmihandler.hpp index 91707f3..288e4d7 100644 --- a/dcmihandler.hpp +++ b/dcmihandler.hpp @@ -12,6 +12,7 @@ namespace dcmi enum Commands { // Get capability bits + GET_CAPABILITIES = 0x01, GET_POWER_LIMIT = 0x03, SET_POWER_LIMIT = 0x04, APPLY_POWER_LIMIT = 0x05, @@ -258,6 +259,67 @@ struct SetMgmntCtrlIdStrResponse uint8_t offset; //!< Last Offset Written. } __attribute__((packed)); +/** @enum DCMICapParameters + * + * DCMI Capability parameters + */ +enum class DCMICapParameters +{ + SUPPORTED_DCMI_CAPS = 0x01, //!< Supported DCMI Capabilities + MANDATORY_PLAT_ATTRIBUTES = 0x02, //!< Mandatory Platform Attributes + OPTIONAL_PLAT_ATTRIBUTES = 0x03, //!< Optional Platform Attributes + MANAGEABILITY_ACCESS_ATTRIBUTES = 0x04, //!< Manageability Access Attributes +}; + +/** @struct GetDCMICapRequest + * + * DCMI payload for Get capabilities cmd request. + */ +struct GetDCMICapRequest +{ + uint8_t groupID; //!< Group extension identification. + uint8_t param; //!< Capability parameter selector. +} __attribute__((packed)); + +/** @struct GetDCMICapRequest + * + * DCMI payload for Get capabilities cmd response. + */ +struct GetDCMICapResponse +{ + uint8_t groupID; //!< Group extension identification. + uint8_t major; //!< DCMI Specification Conformance - major ver + uint8_t minor; //!< DCMI Specification Conformance - minor ver + uint8_t paramRevision; //!< Parameter Revision = 02h + uint8_t data[]; //!< Capability array +} __attribute__((packed)); + +/** @struct DCMICap + * + * DCMI capabilities protocol info. + */ +struct DCMICap +{ + std::string name; //!< Name of DCMI capability. + uint8_t bytePosition; //!< Starting byte number from DCMI spec. + uint8_t position; //!< bit position from the DCMI spec. + uint8_t length; //!< Length of the value from DCMI spec. +}; + +using DCMICapList = std::vector; + +/** @struct DCMICapEntry + * + * DCMI capabilities list and size for each parameter. + */ +struct DCMICapEntry +{ + uint8_t size; //!< Size of capability array in bytes. + DCMICapList capList; //!< List of capabilities for a parameter. +}; + +using DCMICaps = std::map; + } // namespace dcmi #endif diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf index 68e3233..941800a 100644 --- a/host-ipmid-whitelist.conf +++ b/host-ipmid-whitelist.conf @@ -27,5 +27,6 @@ 0x0A:0x49 //: 0x0C:0x02 //: 0x2C:0x00 //: +0x2C:0x01 //: 0x2C:0x03 //: 0x2C:0x06 //: -- cgit v1.2.1