summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dcmihandler.cpp116
-rw-r--r--dcmihandler.hpp82
-rw-r--r--host-ipmid-whitelist.conf1
3 files changed, 199 insertions, 0 deletions
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<Response, NumInstances> read(const std::string& type,
+ uint8_t instance)
+{
+ Response empty{};
+ return std::make_tuple(empty, 0);
+}
+
+std::tuple<ResponseList, NumInstances> 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<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 =
+ reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
+
+ if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
+ {
+ log<level::ERR>("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<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::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()
{
// <Get Power Limit>
@@ -784,6 +895,11 @@ void register_netfn_dcmi_functions()
// <Get DCMI capabilities>
ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
NULL, getDCMICapabilities, PRIVILEGE_USER);
+
+ // <Get Temperature Readings>
+ 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<Response>;
+ using NumInstances = size_t;
+}
+
static constexpr auto groupExtId = 0xDC;
static constexpr auto assetTagMaxOffset = 62;
@@ -320,6 +349,59 @@ struct DCMICapEntry
using DCMICaps = std::map<DCMICapParameters, DCMICapEntry>;
+/** @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<Response, NumInstances> 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<ResponseList, NumInstances> 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 //<Group Extension>:<Get DCMI Capabilities>
0x2C:0x03 //<Group Extension>:<Get Power Limit>
0x2C:0x06 //<Group Extension>:<Get Asset Tag>
+0x2C:0x10 //<Group Extension>:<Get Temperature Readings>
OpenPOWER on IntegriCloud