From ee717d71a2f294a8de5d1e17c9106b65af59d310 Mon Sep 17 00:00:00 2001 From: Deepak Kodihalli Date: Wed, 24 Jan 2018 04:53:09 -0600 Subject: dcmi : implement get temperature readings This commit implements the plumbing around the 'Get Temperature Readings' command. It doesn't read the temperatures from the relevant sensors. That code is coming up in a subsequent commit. Change-Id: I4514b65eb3ca65d52dd35185338a2c397e9a76ca Signed-off-by: Deepak Kodihalli --- dcmihandler.cpp | 116 ++++++++++++++++++++++++++++++++++++++++++++++ dcmihandler.hpp | 82 ++++++++++++++++++++++++++++++++ host-ipmid-whitelist.conf | 1 + 3 files changed, 199 insertions(+) diff --git a/dcmihandler.cpp b/dcmihandler.cpp index aa9f14e..e5a5384 100644 --- a/dcmihandler.cpp +++ b/dcmihandler.cpp @@ -731,6 +731,117 @@ ipmi_ret_t getDCMICapabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd, return IPMI_CC_OK; } +namespace dcmi +{ +namespace temp_readings +{ + +std::tuple read(const std::string& type, + uint8_t instance) +{ + Response empty{}; + return std::make_tuple(empty, 0); +} + +std::tuple readAll(const std::string& type, + uint8_t instanceStart) +{ + ResponseList empty{}; + return std::make_tuple(empty, 0); +} + +} // namsespace temp_readings +} // namsepace dcmi + +ipmi_ret_t getTempReadings(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) +{ + // Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec + static const std::map entityIdToName + { + {0x40, "inlet"}, + {0x37, "inlet"}, + {0x41, "cpu"}, + {0x03, "cpu"}, + {0x42, "baseboard"}, + {0x07, "baseboard"} + }; + + auto requestData = + reinterpret_cast(request); + auto responseData = + reinterpret_cast(response); + + if (*data_len != sizeof(dcmi::GetTempReadingsRequest)) + { + log("Malformed request data", + entry("DATA_SIZE=%d", *data_len)); + return IPMI_CC_REQ_DATA_LEN_INVALID; + } + *data_len = 0; + + auto it = entityIdToName.find(requestData->entityId); + if (it == entityIdToName.end()) + { + log("Unknown Entity ID", + entry("ENTITY_ID=%d", requestData->entityId)); + return IPMI_CC_INVALID_FIELD_REQUEST; + } + + if (requestData->groupID != dcmi::groupExtId) + { + log("Invalid Group ID", + entry("GROUP_ID=%d", requestData->groupID)); + return IPMI_CC_INVALID_FIELD_REQUEST; + } + + if (requestData->sensorType != dcmi::temperatureSensorType) + { + log("Invalid sensor type", + entry("SENSOR_TYPE=%d", requestData->sensorType)); + return IPMI_CC_INVALID_FIELD_REQUEST; + } + + dcmi::temp_readings::ResponseList temps{}; + try + { + if (!requestData->entityInstance) + { + // Read all instances + std::tie(temps, responseData->numInstances) = + dcmi::temp_readings::readAll(it->second, + requestData->instanceStart); + } + else + { + // Read one instance + temps.resize(1); + std::tie(temps[0], responseData->numInstances) = + dcmi::temp_readings::read(it->second, + requestData->entityInstance); + } + responseData->numDataSets = temps.size(); + } + catch (InternalFailure& e) + { + return IPMI_CC_UNSPECIFIED_ERROR; + } + + responseData->groupID = dcmi::groupExtId; + size_t payloadSize = + temps.size() * sizeof(dcmi::temp_readings::Response); + if (!temps.empty()) + { + memcpy(responseData + 1, // copy payload right after the response header + temps.data(), + payloadSize); + } + *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize; + + return IPMI_CC_OK; +} + void register_netfn_dcmi_functions() { // @@ -784,6 +895,11 @@ void register_netfn_dcmi_functions() // ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES, NULL, getDCMICapabilities, PRIVILEGE_USER); + + // + ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS, + NULL, getTempReadings, PRIVILEGE_USER); + return; } // 956379 diff --git a/dcmihandler.hpp b/dcmihandler.hpp index 288e4d7..a7cfe8a 100644 --- a/dcmihandler.hpp +++ b/dcmihandler.hpp @@ -20,6 +20,7 @@ enum Commands SET_ASSET_TAG = 0x08, GET_MGMNT_CTRL_ID_STR = 0x09, SET_MGMNT_CTRL_ID_STR = 0x0A, + GET_TEMP_READINGS = 0x10, }; static constexpr auto propIntf = "org.freedesktop.DBus.Properties"; @@ -32,6 +33,7 @@ static constexpr auto networkConfigObj = static constexpr auto networkConfigIntf = "xyz.openbmc_project.Network.SystemConfiguration"; static constexpr auto hostNameProp = "HostName"; +static constexpr auto temperatureSensorType = 0x01; namespace assettag { @@ -43,6 +45,33 @@ namespace assettag } //namespace assettag +namespace temp_readings +{ + static constexpr auto maxDataSets = 8; + static constexpr auto maxInstances = 255; + static constexpr auto maxTemp = 128; // degrees C + + /** @struct Response + * + * DCMI payload for Get Temperature Readings response + */ + struct Response + { +#if BYTE_ORDER == LITTLE_ENDIAN + uint8_t temperature: 7; //!< Temperature reading in Celsius + uint8_t sign: 1; //!< Sign bit +#endif +#if BYTE_ORDER == BIG_ENDIAN + uint8_t sign: 1; //!< Sign bit + uint8_t temperature: 7; //!< Temperature reading in Celsius +#endif + uint8_t instance; //!< Entity instance number + } __attribute__((packed)); + + using ResponseList = std::vector; + using NumInstances = size_t; +} + static constexpr auto groupExtId = 0xDC; static constexpr auto assetTagMaxOffset = 62; @@ -320,6 +349,59 @@ struct DCMICapEntry using DCMICaps = std::map; +/** @struct GetTempReadingsRequest + * + * DCMI payload for Get Temperature Readings request + */ +struct GetTempReadingsRequest +{ + uint8_t groupID; //!< Group extension identification. + uint8_t sensorType; //!< Type of the sensor + uint8_t entityId; //!< Entity ID + uint8_t entityInstance; //!< Entity Instance (0 means all instances) + uint8_t instanceStart; //!< Instance start (used if instance is 0) +} __attribute__((packed)); + +/** @struct GetTempReadingsResponse + * + * DCMI header for Get Temperature Readings response + */ +struct GetTempReadingsResponseHdr +{ + uint8_t groupID; //!< Group extension identification. + uint8_t numInstances; //!< No. of instances for requested id + uint8_t numDataSets; //!< No. of sets of temperature data +} __attribute__((packed)); + +namespace temp_readings +{ + /** @brief Read temperatures and fill up DCMI response for the Get + * Temperature Readings command. This looks at a specific + * instance. + * + * @param[in] type - one of "inlet", "cpu", "baseboard" + * @param[in] instance - A non-zero Entity instance number + * + * @return A tuple, containing a temperature reading and the + * number of instances. + */ + std::tuple read (const std::string& type, + uint8_t instance); + + /** @brief Read temperatures and fill up DCMI response for the Get + * Temperature Readings command. This looks at a range of + * instances. + * + * @param[in] type - one of "inlet", "cpu", "baseboard" + * @param[in] instanceStart - Entity instance start index + * + * @return A tuple, containing a list of temperature readings and the + * number of instances. + */ + std::tuple readAll(const std::string& type, + uint8_t instanceStart); +} + } // namespace dcmi #endif diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf index 941800a..f1084d0 100644 --- a/host-ipmid-whitelist.conf +++ b/host-ipmid-whitelist.conf @@ -30,3 +30,4 @@ 0x2C:0x01 //: 0x2C:0x03 //: 0x2C:0x06 //: +0x2C:0x10 //: -- cgit v1.2.1