pldm: Add support for OCC state changes
When the state of the OCC changes, host sends stateSensorEvent to
indicate going active or not active which is send as a D-Bus signal
by PLDM daemon. openpower-occ-control app listens for this signal
and updates the OCC D-Bus object. The lowest entity instance number
in the PDRs corresponds to first instance of the OCC.
Tested:
1) On a simics session verified that the sensor event is handled for
OCC going active and OCCActive property is set to true.
2) A sensorEvent is generated for OCC going non active and verified
OCCActive property is set to false.
3) Powered off the host and OCCActive property is set to false.
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
Change-Id: I0469cc483184b66acabc5f0cea1613a7768b3393
diff --git a/pldm.cpp b/pldm.cpp
new file mode 100644
index 0000000..c520340
--- /dev/null
+++ b/pldm.cpp
@@ -0,0 +1,154 @@
+#include "pldm.hpp"
+
+#include <libpldm/entity.h>
+#include <libpldm/platform.h>
+#include <libpldm/state_set.h>
+
+#include <phosphor-logging/log.hpp>
+
+namespace pldm
+{
+
+using sdbusplus::exception::SdBusError;
+using namespace phosphor::logging;
+
+void Interface::fetchOCCSensorInfo(const PdrList& pdrs,
+ SensorToOCCInstance& sensorInstanceMap,
+ SensorOffset& sensorOffset)
+{
+ bool offsetFound = false;
+ auto pdr =
+ reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
+ auto possibleStatesPtr = pdr->possible_states;
+ for (auto offset = 0; offset < pdr->composite_sensor_count; offset++)
+ {
+ auto possibleStates =
+ reinterpret_cast<const state_sensor_possible_states*>(
+ possibleStatesPtr);
+
+ if (possibleStates->state_set_id ==
+ PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS)
+ {
+ sensorOffset = offset;
+ offsetFound = true;
+ break;
+ }
+ possibleStatesPtr += sizeof(possibleStates->state_set_id) +
+ sizeof(possibleStates->possible_states_size) +
+ possibleStates->possible_states_size;
+ }
+
+ if (!offsetFound)
+ {
+ log<level::ERR>("pldm: OCC state sensor PDR with StateSetId "
+ "PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS not found");
+ return;
+ }
+
+ // To order SensorID based on the EntityInstance
+ std::map<EntityInstance, SensorID> entityInstMap{};
+ for (auto& pdr : pdrs)
+ {
+ auto pdrPtr =
+ reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
+ entityInstMap.emplace(
+ static_cast<EntityInstance>(pdrPtr->entity_instance),
+ static_cast<SensorID>(pdrPtr->sensor_id));
+ }
+
+ open_power::occ::instanceID count = start;
+ for (auto const& pair : entityInstMap)
+ {
+ sensorInstanceMap.emplace(pair.second, count);
+ count++;
+ }
+}
+
+void Interface::sensorEvent(sdbusplus::message::message& msg)
+{
+ if (!isOCCSensorCacheValid())
+ {
+ PdrList pdrs{};
+
+ try
+ {
+ auto method = bus.new_method_call(
+ "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
+ "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
+ method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE,
+ (uint16_t)PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS);
+
+ auto responseMsg = bus.call(method);
+ responseMsg.read(pdrs);
+ }
+ catch (const SdBusError& e)
+ {
+ log<level::ERR>("pldm: Failed to fetch the OCC state sensor PDRs",
+ entry("ERROR=%s", e.what()));
+ }
+
+ if (!pdrs.size())
+ {
+ log<level::ERR>("pldm: OCC state sensor PDRs not present");
+ return;
+ }
+
+ fetchOCCSensorInfo(pdrs, sensorToOCCInstance, sensorOffset);
+ }
+
+ TerminusID tid{};
+ SensorID sensorId{};
+ SensorOffset msgSensorOffset{};
+ EventState eventState{};
+ EventState previousEventState{};
+
+ msg.read(tid, sensorId, sensorOffset, eventState, previousEventState);
+
+ auto sensorEntry = sensorToOCCInstance.find(sensorId);
+ if (sensorEntry == sensorToOCCInstance.end() ||
+ (msgSensorOffset != sensorOffset))
+ {
+ // No action for non matching sensorEvents
+ return;
+ }
+
+ bool newState{};
+ if (eventState == static_cast<EventState>(
+ PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
+ {
+ newState = callBack(sensorEntry->second, true);
+ }
+ else if (eventState ==
+ static_cast<EventState>(
+ PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
+ {
+ newState = callBack(sensorEntry->second, false);
+ }
+ else
+ {
+ return;
+ }
+
+ log<level::INFO>("pldm: Updated OCCActive state",
+ entry("STATE=%s", newState ? "true" : "false"));
+ return;
+}
+
+void Interface::hostStateEvent(sdbusplus::message::message& msg)
+{
+ std::map<std::string, std::variant<std::string>> properties{};
+ std::string interface;
+ msg.read(interface, properties);
+ const auto stateEntry = properties.find("CurrentHostState");
+ if (stateEntry != properties.end())
+ {
+ auto stateEntryValue = stateEntry->second;
+ auto propVal = std::get<std::string>(stateEntryValue);
+ if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
+ {
+ sensorToOCCInstance.clear();
+ }
+ }
+}
+
+} // namespace pldm
\ No newline at end of file