oemcommands: Implement OEM Get Reading command
Newly implement OEM Get Reading command API. It implements for
"Inlet Air Temperature" Reading type.
Tested:
Verified on single node system using Oem get reading commands.
Command: ipmitool raw 0x30 0xe2 0x00 0x00 0x00 //OEM Get reading
Response: Unable to send RAW command (channel=0x0 netfn=0x30 lun=0x0
cmd=0xe2 rsp=0xc9): Parameter out of range
Command: ipmitool raw 0x30 0xe2 0x10 0x0 0x0 //OEM Get reading
Response: 10 1a 00
Command: ipmitool raw 0x30 0xe2 0x20 0x0 0x0 //OEM Get reading
Response: Unable to send RAW command (channel=0x0 netfn=0x30 lun=0x0
cmd=0xe2 rsp=0xc9): Parameter out of range
Command: ipmitool raw 0x30 0xe2 0x30 0x0 0x0
Response: Unable to send RAW command (channel=0x0 netfn=0x30 lun=0x0
cmd=0xe2 rsp=0xcc): Invalid data field in request
Signed-off-by: srikanta mondal <srikantax.mondal@intel.com>
Change-Id: I6450fe95b4ef52eed4784561180d1da667d30360
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index f532884..78f4f82 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -69,6 +69,10 @@
static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
+static constexpr const char* multiNodeObjPath =
+ "/xyz/openbmc_project/MultiNode/Status";
+static constexpr const char* multiNodeIntf =
+ "xyz.openbmc_project.Chassis.MultiNode";
enum class NmiSource : uint8_t
{
@@ -3535,6 +3539,111 @@
return ipmi::responseSuccess(result);
}
+std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx,
+ const std::string& name)
+{
+ Value dbusValue = 0;
+ std::string serviceName;
+
+ boost::system::error_code ec =
+ ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
+
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to perform Multinode getService.");
+ return std::nullopt;
+ }
+
+ ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
+ multiNodeIntf, name, dbusValue);
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to perform Multinode get property");
+ return std::nullopt;
+ }
+
+ auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
+ if (!multiNodeVal)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "getMultiNodeInfoPresence: error to get multinode");
+ return std::nullopt;
+ }
+ return *multiNodeVal;
+}
+
+/** @brief implements OEM get reading command
+ * @param domain ID
+ * @param reading Type
+ * - 00h = platform Power Consumption
+ * - 01h = inlet Air Temp
+ * - 02h = icc_TDC from PECI
+ * @param reserved, write as 0000h
+ *
+ * @returns IPMI completion code plus response data
+ * - response
+ * - domain ID
+ * - reading Type
+ * - 00h = platform Power Consumption
+ * - 01h = inlet Air Temp
+ * - 02h = icc_TDC from PECI
+ * - reading
+ */
+ipmi::RspType<uint4_t, // domain ID
+ uint4_t, // reading Type
+ uint16_t // reading Value
+ >
+ ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId,
+ uint4_t readingType, uint16_t reserved)
+{
+ constexpr uint8_t platformPower = 0;
+ constexpr uint8_t inletAirTemp = 1;
+ constexpr uint8_t iccTdc = 2;
+
+ if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
+ {
+ return ipmi::responseInvalidFieldRequest();
+ }
+
+ // This command should run only from multi-node product.
+ // For all other platforms this command will return invalid.
+
+ std::optional<uint8_t> nodeInfo =
+ getMultiNodeInfoPresence(ctx, "NodePresence");
+ if (!nodeInfo || !*nodeInfo)
+ {
+ return ipmi::responseInvalidCommand();
+ }
+
+ uint16_t oemReadingValue = 0;
+ if (static_cast<uint8_t>(readingType) == inletAirTemp)
+ {
+ double value = 0;
+ boost::system::error_code ec = ipmi::getDbusProperty(
+ ctx, "xyz.openbmc_project.HwmonTempSensor",
+ "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
+ "xyz.openbmc_project.Sensor.Value", "Value", value);
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to get BMC Get OEM temperature",
+ phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
+ return ipmi::responseUnspecifiedError();
+ }
+ // Take the Inlet temperature
+ oemReadingValue = static_cast<uint16_t>(value);
+ }
+ else
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Currently Get OEM Reading support only for Inlet Air Temp");
+ return ipmi::responseParmOutOfRange();
+ }
+ return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
+}
+
/** @brief implements the maximum size of
* bridgeable messages used between KCS and
* IPMB interfacesget security mode command.
@@ -3720,6 +3829,10 @@
registerHandler(prioOemBase, intel::netFnGeneral,
intel::general::cmdGetBufferSize, Privilege::User,
ipmiOEMGetBufferSize);
+
+ registerHandler(prioOemBase, intel::netFnGeneral,
+ intel::general::cmdOEMGetReading, Privilege::User,
+ ipmiOEMGetReading);
}
} // namespace ipmi