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