diff options
-rw-r--r-- | dcmihandler.cpp | 186 | ||||
-rw-r--r-- | dcmihandler.hpp | 100 | ||||
-rw-r--r-- | host-ipmid-whitelist.conf | 1 |
3 files changed, 241 insertions, 46 deletions
diff --git a/dcmihandler.cpp b/dcmihandler.cpp index bfc8466..54c8799 100644 --- a/dcmihandler.cpp +++ b/dcmihandler.cpp @@ -40,6 +40,18 @@ using namespace phosphor::logging; namespace dcmi { +// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec +static const std::map<uint8_t, std::string> entityIdToName +{ + {0x40, "inlet"}, + {0x37, "inlet"}, + {0x41, "cpu"}, + {0x03, "cpu"}, + {0x42, "baseboard"}, + {0x07, "baseboard"} +}; + + uint32_t getPcap(sdbusplus::bus::bus& bus) { auto settingService = ipmi::getService(bus, @@ -232,6 +244,25 @@ std::string getHostName(void) return value.get<std::string>(); } +Json parseSensorConfig() +{ + std::ifstream jsonFile(configFile); + if (!jsonFile.is_open()) + { + log<level::ERR>("Temperature readings JSON file not found"); + elog<InternalFailure>(); + } + + auto data = Json::parse(jsonFile, nullptr, false); + if (data.is_discarded()) + { + log<level::ERR>("Temperature readings JSON parser failure"); + elog<InternalFailure>(); + } + + return data; +} + } // namespace dcmi ipmi_ret_t getPowerLimit(ipmi_netfn_t netfn, ipmi_cmd_t cmd, @@ -742,25 +773,6 @@ namespace dcmi namespace temp_readings { -Json parseConfig() -{ - std::ifstream jsonFile(configFile); - if (!jsonFile.is_open()) - { - log<level::ERR>("Temperature readings JSON file not found"); - elog<InternalFailure>(); - } - - auto data = Json::parse(jsonFile, nullptr, false); - if (data.is_discarded()) - { - log<level::ERR>("Temperature readings JSON parser failure"); - elog<InternalFailure>(); - } - - return data; -} - Temperature readTemp(const std::string& dbusService, const std::string& dbusPath) { @@ -815,7 +827,7 @@ std::tuple<Response, NumInstances> read(const std::string& type, elog<InternalFailure>(); } - auto data = parseConfig(); + auto data = parseSensorConfig(); static const std::vector<Json> empty{}; std::vector<Json> readings = data.value(type, empty); size_t numInstances = readings.size(); @@ -868,7 +880,7 @@ std::tuple<ResponseList, NumInstances> readAll(const std::string& type, sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; size_t numInstances = 0; - auto data = parseConfig(); + auto data = parseSensorConfig(); static const std::vector<Json> empty{}; std::vector<Json> readings = data.value(type, empty); numInstances = readings.size(); @@ -925,17 +937,6 @@ 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<uint8_t, std::string> entityIdToName - { - {0x40, "inlet"}, - {0x37, "inlet"}, - {0x41, "cpu"}, - {0x03, "cpu"}, - {0x42, "baseboard"}, - {0x07, "baseboard"} - }; - auto requestData = reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request); auto responseData = @@ -949,8 +950,8 @@ ipmi_ret_t getTempReadings(ipmi_netfn_t netfn, ipmi_cmd_t cmd, } *data_len = 0; - auto it = entityIdToName.find(requestData->entityId); - if (it == entityIdToName.end()) + auto it = dcmi::entityIdToName.find(requestData->entityId); + if (it == dcmi::entityIdToName.end()) { log<level::ERR>("Unknown Entity ID", entry("ENTITY_ID=%d", requestData->entityId)); @@ -1107,6 +1108,118 @@ ipmi_ret_t getPowerReading(ipmi_netfn_t netfn, ipmi_cmd_t cmd, return rc; } +namespace dcmi +{ +namespace sensor_info +{ + +std::tuple<Response, NumInstances> read(const std::string& type, + uint8_t instance, + const Json& config) +{ + Response empty{}; + return std::make_tuple(empty, 0); +} + +std::tuple<ResponseList, NumInstances> readAll(const std::string& type, + uint8_t instanceStart, + const Json& config) +{ + ResponseList empty{}; + return std::make_tuple(empty, 0); +} + +} // namespace sensor_info +} // namespace dcmi + +ipmi_ret_t getSensorInfo(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) +{ + auto requestData = + reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request); + auto responseData = + reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response); + + if (*data_len != sizeof(dcmi::GetSensorInfoRequest)) + { + log<level::ERR>("Malformed request data", + entry("DATA_SIZE=%d", *data_len)); + return IPMI_CC_REQ_DATA_LEN_INVALID; + } + *data_len = 0; + + auto it = dcmi::entityIdToName.find(requestData->entityId); + if (it == dcmi::entityIdToName.end()) + { + log<level::ERR>("Unknown Entity ID", + entry("ENTITY_ID=%d", requestData->entityId)); + return IPMI_CC_INVALID_FIELD_REQUEST; + } + + if (requestData->groupID != dcmi::groupExtId) + { + log<level::ERR>("Invalid Group ID", + entry("GROUP_ID=%d", requestData->groupID)); + return IPMI_CC_INVALID_FIELD_REQUEST; + } + + if (requestData->sensorType != dcmi::temperatureSensorType) + { + log<level::ERR>("Invalid sensor type", + entry("SENSOR_TYPE=%d", requestData->sensorType)); + return IPMI_CC_INVALID_FIELD_REQUEST; + } + + dcmi::sensor_info::ResponseList sensors{}; + static dcmi::Json config{}; + static bool parsed = false; + + try + { + if (!parsed) + { + config = dcmi::parseSensorConfig(); + parsed = true; + } + + if (!requestData->entityInstance) + { + // Read all instances + std::tie(sensors, responseData->numInstances) = + dcmi::sensor_info::readAll(it->second, + requestData->instanceStart, + config); + } + else + { + // Read one instance + sensors.resize(1); + std::tie(sensors[0], responseData->numInstances) = + dcmi::sensor_info::read(it->second, + requestData->entityInstance, + config); + } + responseData->numRecords = sensors.size(); + } + catch (InternalFailure& e) + { + return IPMI_CC_UNSPECIFIED_ERROR; + } + + responseData->groupID = dcmi::groupExtId; + size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response); + if (!sensors.empty()) + { + memcpy(responseData + 1, // copy payload right after the response header + sensors.data(), + payloadSize); + } + *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize; + + return IPMI_CC_OK; +} + void register_netfn_dcmi_functions() { // <Get Power Limit> @@ -1168,6 +1281,11 @@ void register_netfn_dcmi_functions() // <Get Power Reading> ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING, NULL, getPowerReading, PRIVILEGE_USER); + + // <Get Sensor Info> + ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, + NULL, getSensorInfo, PRIVILEGE_USER); + return; } // 956379 diff --git a/dcmihandler.hpp b/dcmihandler.hpp index 4e95eba..09921a0 100644 --- a/dcmihandler.hpp +++ b/dcmihandler.hpp @@ -10,6 +10,9 @@ namespace dcmi { +using NumInstances = size_t; +using Json = nlohmann::json; + enum Commands { // Get capability bits @@ -19,6 +22,7 @@ enum Commands SET_POWER_LIMIT = 0x04, APPLY_POWER_LIMIT = 0x05, GET_ASSET_TAG = 0x06, + GET_SENSOR_INFO = 0x07, SET_ASSET_TAG = 0x08, GET_MGMNT_CTRL_ID_STR = 0x09, SET_MGMNT_CTRL_ID_STR = 0x0A, @@ -36,6 +40,9 @@ static constexpr auto networkConfigIntf = "xyz.openbmc_project.Network.SystemConfiguration"; static constexpr auto hostNameProp = "HostName"; static constexpr auto temperatureSensorType = 0x01; +static constexpr auto maxInstances = 255; +static constexpr auto configFile = + "/usr/share/ipmi-providers/dcmi_sensors.json"; namespace assettag { @@ -50,10 +57,7 @@ namespace assettag namespace temp_readings { static constexpr auto maxDataSets = 8; - static constexpr auto maxInstances = 255; static constexpr auto maxTemp = 127; // degrees C - static constexpr auto configFile = - "/usr/share/ipmi-providers/dcmi_temp_readings.json"; /** @struct Response * @@ -73,13 +77,28 @@ namespace temp_readings } __attribute__((packed)); using ResponseList = std::vector<Response>; - using NumInstances = size_t; using Value = uint8_t; using Sign = bool; using Temperature = std::tuple<Value, Sign>; - using Json = nlohmann::json; } +namespace sensor_info +{ + static constexpr auto maxRecords = 8; + + /** @struct Response + * + * DCMI payload for Get Sensor Info response + */ + struct Response + { + uint8_t recordIdLsb; //!< SDR record id LS byte + uint8_t recordIdMsb; //!< SDR record id MS byte + } __attribute__((packed)); + + using ResponseList = std::vector<Response>; +} // namespace sensor_info + static constexpr auto groupExtId = 0xDC; static constexpr auto assetTagMaxOffset = 62; @@ -381,6 +400,13 @@ struct GetTempReadingsResponseHdr uint8_t numDataSets; //!< No. of sets of temperature data } __attribute__((packed)); +/** @brief Parse out JSON config file containing information + * related to sensors. + * + * @return A json object + */ +Json parseSensorConfig(); + namespace temp_readings { /** @brief Read temperature from a d-bus object, scale it as per dcmi @@ -394,13 +420,6 @@ namespace temp_readings Temperature readTemp(const std::string& dbusService, const std::string& dbusPath); - /** @brief Parse out JSON config file containing information - * related to temperature readings. - * - * @return A json object - */ - Json parseConfig(); - /** @brief Read temperatures and fill up DCMI response for the Get * Temperature Readings command. This looks at a specific * instance. @@ -428,6 +447,39 @@ namespace temp_readings uint8_t instanceStart); } +namespace sensor_info +{ + /** @brief Read sensor info and fill up DCMI response for the Get + * Sensor Info command. This looks at a specific + * instance. + * + * @param[in] type - one of "inlet", "cpu", "baseboard" + * @param[in] instance - A non-zero Entity instance number + * @param[in] config - JSON config info about DCMI sensors + * + * @return A tuple, containing a sensor info response and + * number of instances. + */ + std::tuple<Response, NumInstances> read(const std::string& type, + uint8_t instance, + const Json& config); + + /** @brief Read sensor info and fill up DCMI response for the Get + * Sensor Info command. This looks at a range of + * instances. + * + * @param[in] type - one of "inlet", "cpu", "baseboard" + * @param[in] instanceStart - Entity instance start index + * @param[in] config - JSON config info about DCMI sensors + * + * @return A tuple, containing a list of sensor info responses and the + * number of instances. + */ + std::tuple<ResponseList, NumInstances> readAll(const std::string& type, + uint8_t instanceStart, + const Json& config); +} // namespace sensor_info + /** @brief Read power reading from power reading sensor object * * @param[in] bus - dbus connection @@ -469,6 +521,30 @@ struct GetPowerReadingResponse uint8_t powerReadingState; //!< Power Reading State } __attribute__((packed)); +/** @struct GetSensorInfoRequest + * + * DCMI payload for Get Sensor Info request + */ +struct GetSensorInfoRequest +{ + 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 GetSensorInfoResponseHdr + * + * DCMI header for Get Sensor Info response + */ +struct GetSensorInfoResponseHdr +{ + uint8_t groupID; //!< Group extension identification. + uint8_t numInstances; //!< No. of instances for requested id + uint8_t numRecords; //!< No. of record ids in the response +} __attribute__((packed)); + } // namespace dcmi #endif diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf index 0c9c382..97544a0 100644 --- a/host-ipmid-whitelist.conf +++ b/host-ipmid-whitelist.conf @@ -31,4 +31,5 @@ 0x2C:0x02 //<Group Extension>:<Get Power Reading> 0x2C:0x03 //<Group Extension>:<Get Power Limit> 0x2C:0x06 //<Group Extension>:<Get Asset Tag> +0x2C:0x07 //<Group Extension>:<Get Sensor Info> 0x2C:0x10 //<Group Extension>:<Get Temperature Readings> |