xref: /openbmc/openpower-occ-control/pldm.cpp (revision a8857c50)
1815f9f55STom Joseph #include "pldm.hpp"
2815f9f55STom Joseph 
300325238STom Joseph #include "file.hpp"
400325238STom Joseph 
5*a8857c50SChris Cain #include <fmt/core.h>
6815f9f55STom Joseph #include <libpldm/entity.h>
7815f9f55STom Joseph #include <libpldm/platform.h>
8815f9f55STom Joseph #include <libpldm/state_set.h>
9815f9f55STom Joseph 
10815f9f55STom Joseph #include <phosphor-logging/log.hpp>
11815f9f55STom Joseph 
12815f9f55STom Joseph namespace pldm
13815f9f55STom Joseph {
14815f9f55STom Joseph 
15815f9f55STom Joseph using sdbusplus::exception::SdBusError;
16815f9f55STom Joseph using namespace phosphor::logging;
17815f9f55STom Joseph 
18815f9f55STom Joseph void Interface::fetchOCCSensorInfo(const PdrList& pdrs,
19815f9f55STom Joseph                                    SensorToOCCInstance& sensorInstanceMap,
20815f9f55STom Joseph                                    SensorOffset& sensorOffset)
21815f9f55STom Joseph {
22815f9f55STom Joseph     bool offsetFound = false;
23815f9f55STom Joseph     auto pdr =
24815f9f55STom Joseph         reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
25815f9f55STom Joseph     auto possibleStatesPtr = pdr->possible_states;
26815f9f55STom Joseph     for (auto offset = 0; offset < pdr->composite_sensor_count; offset++)
27815f9f55STom Joseph     {
28815f9f55STom Joseph         auto possibleStates =
29815f9f55STom Joseph             reinterpret_cast<const state_sensor_possible_states*>(
30815f9f55STom Joseph                 possibleStatesPtr);
31815f9f55STom Joseph 
32815f9f55STom Joseph         if (possibleStates->state_set_id ==
33815f9f55STom Joseph             PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS)
34815f9f55STom Joseph         {
35815f9f55STom Joseph             sensorOffset = offset;
36815f9f55STom Joseph             offsetFound = true;
37815f9f55STom Joseph             break;
38815f9f55STom Joseph         }
39815f9f55STom Joseph         possibleStatesPtr += sizeof(possibleStates->state_set_id) +
40815f9f55STom Joseph                              sizeof(possibleStates->possible_states_size) +
41815f9f55STom Joseph                              possibleStates->possible_states_size;
42815f9f55STom Joseph     }
43815f9f55STom Joseph 
44815f9f55STom Joseph     if (!offsetFound)
45815f9f55STom Joseph     {
46815f9f55STom Joseph         log<level::ERR>("pldm: OCC state sensor PDR with StateSetId "
47815f9f55STom Joseph                         "PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS not found");
48815f9f55STom Joseph         return;
49815f9f55STom Joseph     }
50815f9f55STom Joseph 
51815f9f55STom Joseph     // To order SensorID based on the EntityInstance
52815f9f55STom Joseph     std::map<EntityInstance, SensorID> entityInstMap{};
53815f9f55STom Joseph     for (auto& pdr : pdrs)
54815f9f55STom Joseph     {
55815f9f55STom Joseph         auto pdrPtr =
56815f9f55STom Joseph             reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
57815f9f55STom Joseph         entityInstMap.emplace(
58815f9f55STom Joseph             static_cast<EntityInstance>(pdrPtr->entity_instance),
59815f9f55STom Joseph             static_cast<SensorID>(pdrPtr->sensor_id));
60815f9f55STom Joseph     }
61815f9f55STom Joseph 
62815f9f55STom Joseph     open_power::occ::instanceID count = start;
63815f9f55STom Joseph     for (auto const& pair : entityInstMap)
64815f9f55STom Joseph     {
65815f9f55STom Joseph         sensorInstanceMap.emplace(pair.second, count);
66815f9f55STom Joseph         count++;
67815f9f55STom Joseph     }
68815f9f55STom Joseph }
69815f9f55STom Joseph 
70815f9f55STom Joseph void Interface::sensorEvent(sdbusplus::message::message& msg)
71815f9f55STom Joseph {
72815f9f55STom Joseph     if (!isOCCSensorCacheValid())
73815f9f55STom Joseph     {
74815f9f55STom Joseph         PdrList pdrs{};
75815f9f55STom Joseph 
76815f9f55STom Joseph         try
77815f9f55STom Joseph         {
78815f9f55STom Joseph             auto method = bus.new_method_call(
79815f9f55STom Joseph                 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
80815f9f55STom Joseph                 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
81815f9f55STom Joseph             method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE,
82815f9f55STom Joseph                           (uint16_t)PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS);
83815f9f55STom Joseph 
84815f9f55STom Joseph             auto responseMsg = bus.call(method);
85815f9f55STom Joseph             responseMsg.read(pdrs);
86815f9f55STom Joseph         }
87815f9f55STom Joseph         catch (const SdBusError& e)
88815f9f55STom Joseph         {
89815f9f55STom Joseph             log<level::ERR>("pldm: Failed to fetch the OCC state sensor PDRs",
90815f9f55STom Joseph                             entry("ERROR=%s", e.what()));
91815f9f55STom Joseph         }
92815f9f55STom Joseph 
93815f9f55STom Joseph         if (!pdrs.size())
94815f9f55STom Joseph         {
95815f9f55STom Joseph             log<level::ERR>("pldm: OCC state sensor PDRs not present");
96815f9f55STom Joseph             return;
97815f9f55STom Joseph         }
98815f9f55STom Joseph 
99815f9f55STom Joseph         fetchOCCSensorInfo(pdrs, sensorToOCCInstance, sensorOffset);
100815f9f55STom Joseph     }
101815f9f55STom Joseph 
102815f9f55STom Joseph     TerminusID tid{};
103815f9f55STom Joseph     SensorID sensorId{};
104815f9f55STom Joseph     SensorOffset msgSensorOffset{};
105815f9f55STom Joseph     EventState eventState{};
106815f9f55STom Joseph     EventState previousEventState{};
107815f9f55STom Joseph 
108a17f6e8cSGeorge Liu     msg.read(tid, sensorId, msgSensorOffset, eventState, previousEventState);
109815f9f55STom Joseph 
110815f9f55STom Joseph     auto sensorEntry = sensorToOCCInstance.find(sensorId);
111815f9f55STom Joseph     if (sensorEntry == sensorToOCCInstance.end() ||
112815f9f55STom Joseph         (msgSensorOffset != sensorOffset))
113815f9f55STom Joseph     {
114815f9f55STom Joseph         // No action for non matching sensorEvents
115815f9f55STom Joseph         return;
116815f9f55STom Joseph     }
117815f9f55STom Joseph 
118815f9f55STom Joseph     if (eventState == static_cast<EventState>(
119815f9f55STom Joseph                           PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
120815f9f55STom Joseph     {
121*a8857c50SChris Cain         log<level::INFO>(
122*a8857c50SChris Cain             fmt::format("PLDM: OCC{} is RUNNING", sensorEntry->second).c_str());
123*a8857c50SChris Cain         callBack(sensorEntry->second, true);
124815f9f55STom Joseph     }
125815f9f55STom Joseph     else if (eventState ==
126815f9f55STom Joseph              static_cast<EventState>(
127815f9f55STom Joseph                  PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
128815f9f55STom Joseph     {
129*a8857c50SChris Cain         log<level::INFO>(
130*a8857c50SChris Cain             fmt::format("PLDM: OCC{} has now STOPPED", sensorEntry->second)
131*a8857c50SChris Cain                 .c_str());
132*a8857c50SChris Cain         callBack(sensorEntry->second, false);
133815f9f55STom Joseph     }
134815f9f55STom Joseph 
135815f9f55STom Joseph     return;
136815f9f55STom Joseph }
137815f9f55STom Joseph 
138815f9f55STom Joseph void Interface::hostStateEvent(sdbusplus::message::message& msg)
139815f9f55STom Joseph {
140815f9f55STom Joseph     std::map<std::string, std::variant<std::string>> properties{};
141815f9f55STom Joseph     std::string interface;
142815f9f55STom Joseph     msg.read(interface, properties);
143815f9f55STom Joseph     const auto stateEntry = properties.find("CurrentHostState");
144815f9f55STom Joseph     if (stateEntry != properties.end())
145815f9f55STom Joseph     {
146815f9f55STom Joseph         auto stateEntryValue = stateEntry->second;
147815f9f55STom Joseph         auto propVal = std::get<std::string>(stateEntryValue);
148815f9f55STom Joseph         if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
149815f9f55STom Joseph         {
150815f9f55STom Joseph             sensorToOCCInstance.clear();
15100325238STom Joseph             occInstanceToEffecter.clear();
152815f9f55STom Joseph         }
153815f9f55STom Joseph     }
154815f9f55STom Joseph }
155815f9f55STom Joseph 
15600325238STom Joseph void Interface::fetchOCCEffecterInfo(
15700325238STom Joseph     const PdrList& pdrs, OccInstanceToEffecter& instanceToEffecterMap,
15800325238STom Joseph     CompositeEffecterCount& count, uint8_t& bootRestartPos)
15900325238STom Joseph {
16000325238STom Joseph     bool offsetFound = false;
16100325238STom Joseph     auto pdr =
16200325238STom Joseph         reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
16300325238STom Joseph     auto possibleStatesPtr = pdr->possible_states;
16400325238STom Joseph     for (auto offset = 0; offset < pdr->composite_effecter_count; offset++)
16500325238STom Joseph     {
16600325238STom Joseph         auto possibleStates =
16700325238STom Joseph             reinterpret_cast<const state_effecter_possible_states*>(
16800325238STom Joseph                 possibleStatesPtr);
16900325238STom Joseph 
17000325238STom Joseph         if (possibleStates->state_set_id == PLDM_STATE_SET_BOOT_RESTART_CAUSE)
17100325238STom Joseph         {
17200325238STom Joseph             bootRestartPos = offset;
17300325238STom Joseph             effecterCount = pdr->composite_effecter_count;
17400325238STom Joseph             offsetFound = true;
17500325238STom Joseph             break;
17600325238STom Joseph         }
17700325238STom Joseph         possibleStatesPtr += sizeof(possibleStates->state_set_id) +
17800325238STom Joseph                              sizeof(possibleStates->possible_states_size) +
17900325238STom Joseph                              possibleStates->possible_states_size;
18000325238STom Joseph     }
18100325238STom Joseph 
18200325238STom Joseph     if (!offsetFound)
18300325238STom Joseph     {
18400325238STom Joseph         return;
18500325238STom Joseph     }
18600325238STom Joseph 
18700325238STom Joseph     std::map<EntityInstance, EffecterID> entityInstMap{};
18800325238STom Joseph     for (auto& pdr : pdrs)
18900325238STom Joseph     {
19000325238STom Joseph         auto pdrPtr =
19100325238STom Joseph             reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
19200325238STom Joseph         entityInstMap.emplace(
19300325238STom Joseph             static_cast<EntityInstance>(pdrPtr->entity_instance),
19400325238STom Joseph             static_cast<SensorID>(pdrPtr->effecter_id));
19500325238STom Joseph     }
19600325238STom Joseph 
19700325238STom Joseph     open_power::occ::instanceID position = start;
19800325238STom Joseph     for (auto const& pair : entityInstMap)
19900325238STom Joseph     {
20000325238STom Joseph         occInstanceToEffecter.emplace(position, pair.second);
20100325238STom Joseph         position++;
20200325238STom Joseph     }
20300325238STom Joseph }
20400325238STom Joseph 
20500325238STom Joseph std::vector<uint8_t>
20600325238STom Joseph     Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId,
20700325238STom Joseph                                      CompositeEffecterCount effecterCount,
20800325238STom Joseph                                      uint8_t bootRestartPos)
20900325238STom Joseph {
21000325238STom Joseph     std::vector<uint8_t> request(
21100325238STom Joseph         sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
21200325238STom Joseph         (effecterCount * sizeof(set_effecter_state_field)));
21300325238STom Joseph     auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
21400325238STom Joseph     std::vector<set_effecter_state_field> stateField;
21500325238STom Joseph 
21600325238STom Joseph     for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
21700325238STom Joseph     {
21800325238STom Joseph         if (effecterPos == bootRestartPos)
21900325238STom Joseph         {
22000325238STom Joseph             stateField.emplace_back(set_effecter_state_field{
22100325238STom Joseph                 PLDM_REQUEST_SET,
22200325238STom Joseph                 PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET});
22300325238STom Joseph         }
22400325238STom Joseph         else
22500325238STom Joseph         {
22600325238STom Joseph             stateField.emplace_back(
22700325238STom Joseph                 set_effecter_state_field{PLDM_NO_CHANGE, 0});
22800325238STom Joseph         }
22900325238STom Joseph     }
23000325238STom Joseph     auto rc = encode_set_state_effecter_states_req(
23100325238STom Joseph         instanceId, effecterId, effecterCount, stateField.data(), requestMsg);
23200325238STom Joseph     if (rc != PLDM_SUCCESS)
23300325238STom Joseph     {
23400325238STom Joseph         log<level::ERR>("encode set effecter states request returned error ",
23500325238STom Joseph                         entry("RC=%d", rc));
23600325238STom Joseph         request.clear();
23700325238STom Joseph     }
23800325238STom Joseph     return request;
23900325238STom Joseph }
24000325238STom Joseph 
24100325238STom Joseph void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
24200325238STom Joseph {
24300325238STom Joseph     if (!isPDREffecterCacheValid())
24400325238STom Joseph     {
24500325238STom Joseph         PdrList pdrs{};
24600325238STom Joseph 
24700325238STom Joseph         try
24800325238STom Joseph         {
24900325238STom Joseph             auto method = bus.new_method_call(
25000325238STom Joseph                 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
25100325238STom Joseph                 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
25200325238STom Joseph             method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE,
25300325238STom Joseph                           (uint16_t)PLDM_STATE_SET_BOOT_RESTART_CAUSE);
25400325238STom Joseph 
25500325238STom Joseph             auto responseMsg = bus.call(method);
25600325238STom Joseph             responseMsg.read(pdrs);
25700325238STom Joseph         }
25800325238STom Joseph         catch (const SdBusError& e)
25900325238STom Joseph         {
26000325238STom Joseph             log<level::ERR>("pldm: Failed to fetch the OCC state effecter PDRs",
26100325238STom Joseph                             entry("ERROR=%s", e.what()));
26200325238STom Joseph         }
26300325238STom Joseph 
26400325238STom Joseph         if (!pdrs.size())
26500325238STom Joseph         {
26600325238STom Joseph             log<level::ERR>("pldm: OCC state effecter PDRs not present");
26700325238STom Joseph             return;
26800325238STom Joseph         }
26900325238STom Joseph 
27000325238STom Joseph         fetchOCCEffecterInfo(pdrs, occInstanceToEffecter, effecterCount,
27100325238STom Joseph                              bootRestartPosition);
27200325238STom Joseph     }
27300325238STom Joseph 
27400325238STom Joseph     // Find the matching effecter for the OCC instance
27500325238STom Joseph     auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
27600325238STom Joseph     if (effecterEntry == occInstanceToEffecter.end())
27700325238STom Joseph     {
27800325238STom Joseph         log<level::ERR>(
27900325238STom Joseph             "pldm: Failed to find a matching effecter for OCC instance",
28000325238STom Joseph             entry("OCC_INSTANCE_ID=%d", occInstanceId));
28100325238STom Joseph 
28200325238STom Joseph         return;
28300325238STom Joseph     }
28400325238STom Joseph 
28500325238STom Joseph     uint8_t instanceId{};
28600325238STom Joseph 
28700325238STom Joseph     try
28800325238STom Joseph     {
28900325238STom Joseph         auto method = bus.new_method_call(
29000325238STom Joseph             "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
29100325238STom Joseph             "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
29200325238STom Joseph         method.append(mctpEid);
29300325238STom Joseph         auto reply = bus.call(method);
29400325238STom Joseph         reply.read(instanceId);
29500325238STom Joseph     }
29600325238STom Joseph     catch (const SdBusError& e)
29700325238STom Joseph     {
29800325238STom Joseph         log<level::ERR>("pldm: GetInstanceId returned error",
29900325238STom Joseph                         entry("ERROR=%s", e.what()));
30000325238STom Joseph         return;
30100325238STom Joseph     }
30200325238STom Joseph 
30300325238STom Joseph     // Prepare the SetStateEffecterStates request to reset the OCC
30400325238STom Joseph     auto request = prepareSetEffecterReq(instanceId, effecterEntry->second,
30500325238STom Joseph                                          effecterCount, bootRestartPosition);
30600325238STom Joseph 
30700325238STom Joseph     if (request.empty())
30800325238STom Joseph     {
30900325238STom Joseph         log<level::ERR>("pldm: SetStateEffecterStates request message empty");
31000325238STom Joseph         return;
31100325238STom Joseph     }
31200325238STom Joseph 
31300325238STom Joseph     // Connect to MCTP scoket
31400325238STom Joseph     int fd = pldm_open();
31500325238STom Joseph     if (fd == -1)
31600325238STom Joseph     {
31700325238STom Joseph         log<level::ERR>("pldm: Failed to connect to MCTP socket");
31800325238STom Joseph         return;
31900325238STom Joseph     }
32000325238STom Joseph     open_power::occ::FileDescriptor fileFd(fd);
32100325238STom Joseph 
32200325238STom Joseph     // Send the PLDM request message to HBRT
32300325238STom Joseph     uint8_t* response = nullptr;
32400325238STom Joseph     size_t responseSize{};
32500325238STom Joseph     auto rc = pldm_send_recv(mctpEid, fileFd(), request.data(), request.size(),
32600325238STom Joseph                              &response, &responseSize);
32700325238STom Joseph     std::unique_ptr<uint8_t, decltype(std::free)*> responsePtr{response,
32800325238STom Joseph                                                                std::free};
32900325238STom Joseph     if (rc)
33000325238STom Joseph     {
33100325238STom Joseph         log<level::ERR>("pldm: pldm_send_recv failed for OCC reset",
33200325238STom Joseph                         entry("RC=%d", rc));
33300325238STom Joseph     }
33400325238STom Joseph 
33500325238STom Joseph     uint8_t completionCode{};
33600325238STom Joseph     auto responseMsg = reinterpret_cast<const pldm_msg*>(responsePtr.get());
33700325238STom Joseph     auto rcDecode = decode_set_state_effecter_states_resp(
33800325238STom Joseph         responseMsg, responseSize - sizeof(pldm_msg_hdr), &completionCode);
33900325238STom Joseph     if (rcDecode || completionCode)
34000325238STom Joseph     {
34100325238STom Joseph         log<level::ERR>(
34200325238STom Joseph             "pldm: decode_set_state_effecter_states_resp returned error",
34300325238STom Joseph             entry("RC=%d", rcDecode),
34400325238STom Joseph             entry("COMPLETION_CODE=%d", completionCode));
34500325238STom Joseph     }
34600325238STom Joseph 
34700325238STom Joseph     return;
34800325238STom Joseph }
34900325238STom Joseph 
350815f9f55STom Joseph } // namespace pldm
351