xref: /openbmc/openpower-occ-control/pldm.cpp (revision 7b00cde2)
1815f9f55STom Joseph #include "pldm.hpp"
2815f9f55STom Joseph 
300325238STom Joseph #include "file.hpp"
400325238STom Joseph 
5a8857c50SChris Cain #include <fmt/core.h>
6815f9f55STom Joseph #include <libpldm/entity.h>
7815f9f55STom Joseph #include <libpldm/platform.h>
8815f9f55STom Joseph #include <libpldm/state_set.h>
936313c71SEddie James #include <libpldm/state_set_oem_ibm.h>
10815f9f55STom Joseph 
11815f9f55STom Joseph #include <phosphor-logging/log.hpp>
12bae4d07eSChris Cain #include <sdbusplus/bus.hpp>
13bae4d07eSChris Cain #include <sdeventplus/clock.hpp>
14bae4d07eSChris Cain #include <sdeventplus/exception.hpp>
15bae4d07eSChris Cain #include <sdeventplus/source/io.hpp>
16bae4d07eSChris Cain #include <sdeventplus/source/time.hpp>
17bae4d07eSChris Cain 
18bae4d07eSChris Cain #include <algorithm>
19815f9f55STom Joseph 
20815f9f55STom Joseph namespace pldm
21815f9f55STom Joseph {
22815f9f55STom Joseph 
23815f9f55STom Joseph using namespace phosphor::logging;
24815f9f55STom Joseph 
25bae4d07eSChris Cain using namespace sdeventplus;
26bae4d07eSChris Cain using namespace sdeventplus::source;
27bae4d07eSChris Cain constexpr auto clockId = sdeventplus::ClockId::RealTime;
28bae4d07eSChris Cain using Clock = sdeventplus::Clock<clockId>;
29bae4d07eSChris Cain using Timer = Time<clockId>;
30bae4d07eSChris Cain 
31cbad219eSEddie James void Interface::fetchSensorInfo(uint16_t stateSetId,
32cbad219eSEddie James                                 SensorToInstance& sensorInstanceMap,
33815f9f55STom Joseph                                 SensorOffset& sensorOffset)
34815f9f55STom Joseph {
35cbad219eSEddie James     PdrList pdrs{};
36bae4d07eSChris Cain     static bool tracedError = false;
37cbad219eSEddie James 
38cbad219eSEddie James     auto& bus = open_power::occ::utils::getBus();
39cbad219eSEddie James     try
40cbad219eSEddie James     {
41cbad219eSEddie James         auto method = bus.new_method_call(
42cbad219eSEddie James             "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
43cbad219eSEddie James             "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
44bae4d07eSChris Cain         method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
45cbad219eSEddie James 
46cbad219eSEddie James         auto responseMsg = bus.call(method);
47cbad219eSEddie James         responseMsg.read(pdrs);
48cbad219eSEddie James     }
49af40808fSPatrick Williams     catch (const sdbusplus::exception_t& e)
50cbad219eSEddie James     {
51bae4d07eSChris Cain         if (!tracedError)
52bae4d07eSChris Cain         {
53bae4d07eSChris Cain             log<level::ERR>(
54bae4d07eSChris Cain                 fmt::format(
55bae4d07eSChris Cain                     "fetchSensorInfo: Failed to find stateSetID:{} PDR: {}",
56bae4d07eSChris Cain                     stateSetId, e.what())
57bae4d07eSChris Cain                     .c_str());
58bae4d07eSChris Cain             tracedError = true;
59bae4d07eSChris Cain         }
60cbad219eSEddie James     }
61cbad219eSEddie James 
62cbad219eSEddie James     if (pdrs.empty())
63cbad219eSEddie James     {
64bae4d07eSChris Cain         if (!tracedError)
65bae4d07eSChris Cain         {
66bae4d07eSChris Cain             log<level::ERR>(
67bae4d07eSChris Cain                 fmt::format(
68bae4d07eSChris Cain                     "fetchSensorInfo: state sensor PDRs ({}) not present",
69bae4d07eSChris Cain                     stateSetId)
70bae4d07eSChris Cain                     .c_str());
71bae4d07eSChris Cain             tracedError = true;
72bae4d07eSChris Cain         }
73cbad219eSEddie James         return;
74cbad219eSEddie James     }
75cbad219eSEddie James 
76bae4d07eSChris Cain     // Found PDR
77bae4d07eSChris Cain     if (tracedError)
78bae4d07eSChris Cain     {
79bae4d07eSChris Cain         log<level::INFO>(
80bae4d07eSChris Cain             fmt::format("fetchSensorInfo: found {} PDRs", pdrs.size()).c_str());
81bae4d07eSChris Cain         tracedError = false;
82bae4d07eSChris Cain     }
83bae4d07eSChris Cain 
84815f9f55STom Joseph     bool offsetFound = false;
85f3a4a69fSGeorge Liu     auto stateSensorPDR =
86815f9f55STom Joseph         reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
87f3a4a69fSGeorge Liu     auto possibleStatesPtr = stateSensorPDR->possible_states;
88f3a4a69fSGeorge Liu     for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count;
89f3a4a69fSGeorge Liu          offset++)
90815f9f55STom Joseph     {
91815f9f55STom Joseph         auto possibleStates =
92815f9f55STom Joseph             reinterpret_cast<const state_sensor_possible_states*>(
93815f9f55STom Joseph                 possibleStatesPtr);
94815f9f55STom Joseph 
95cbad219eSEddie James         if (possibleStates->state_set_id == stateSetId)
96815f9f55STom Joseph         {
97815f9f55STom Joseph             sensorOffset = offset;
98815f9f55STom Joseph             offsetFound = true;
99815f9f55STom Joseph             break;
100815f9f55STom Joseph         }
101815f9f55STom Joseph         possibleStatesPtr += sizeof(possibleStates->state_set_id) +
102815f9f55STom Joseph                              sizeof(possibleStates->possible_states_size) +
103815f9f55STom Joseph                              possibleStates->possible_states_size;
104815f9f55STom Joseph     }
105815f9f55STom Joseph 
106815f9f55STom Joseph     if (!offsetFound)
107815f9f55STom Joseph     {
108cbad219eSEddie James         log<level::ERR>("pldm: state sensor PDR not found");
109815f9f55STom Joseph         return;
110815f9f55STom Joseph     }
111815f9f55STom Joseph 
1121339ab60SMatt Spinler     // To order SensorID based on the EntityInstance.
1131339ab60SMatt Spinler     // Note that when a proc is on a DCM, the PDRs for these sensors
1141339ab60SMatt Spinler     // could have the same instance IDs but different container IDs.
1151339ab60SMatt Spinler     std::map<uint32_t, SensorID> entityInstMap{};
116815f9f55STom Joseph     for (auto& pdr : pdrs)
117815f9f55STom Joseph     {
118815f9f55STom Joseph         auto pdrPtr =
119815f9f55STom Joseph             reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
12072d01aabSChris Cain         uint32_t key = pdrPtr->sensor_id;
1211339ab60SMatt Spinler         entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->sensor_id));
122815f9f55STom Joseph     }
123815f9f55STom Joseph 
124815f9f55STom Joseph     open_power::occ::instanceID count = start;
125815f9f55STom Joseph     for (auto const& pair : entityInstMap)
126815f9f55STom Joseph     {
127815f9f55STom Joseph         sensorInstanceMap.emplace(pair.second, count);
128815f9f55STom Joseph         count++;
129815f9f55STom Joseph     }
130815f9f55STom Joseph }
131815f9f55STom Joseph 
132af40808fSPatrick Williams void Interface::sensorEvent(sdbusplus::message_t& msg)
133815f9f55STom Joseph {
134815f9f55STom Joseph     if (!isOCCSensorCacheValid())
135815f9f55STom Joseph     {
136cbad219eSEddie James         fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
137cbad219eSEddie James                         sensorToOCCInstance, OCCSensorOffset);
138815f9f55STom Joseph     }
139815f9f55STom Joseph 
140cbad219eSEddie James     if (sensorToSBEInstance.empty())
141815f9f55STom Joseph     {
142cbad219eSEddie James         fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSBEInstance,
143cbad219eSEddie James                         SBESensorOffset);
144815f9f55STom Joseph     }
145815f9f55STom Joseph 
14672d01aabSChris Cain     TerminusID sensorTid{};
147815f9f55STom Joseph     SensorID sensorId{};
148815f9f55STom Joseph     SensorOffset msgSensorOffset{};
149815f9f55STom Joseph     EventState eventState{};
150815f9f55STom Joseph     EventState previousEventState{};
151815f9f55STom Joseph 
15272d01aabSChris Cain     msg.read(sensorTid, sensorId, msgSensorOffset, eventState,
15372d01aabSChris Cain              previousEventState);
154815f9f55STom Joseph 
155cbad219eSEddie James     if (msgSensorOffset == OCCSensorOffset)
156815f9f55STom Joseph     {
157cbad219eSEddie James         auto sensorEntry = sensorToOCCInstance.find(sensorId);
158cbad219eSEddie James 
159432dc486SEddie James         if (sensorEntry != sensorToOCCInstance.end())
160cbad219eSEddie James         {
1618b508bfbSChris Cain             const uint8_t instance = sensorEntry->second;
162*7b00cde2SChris Cain             bool isRunning = false;
163cbad219eSEddie James             if (eventState ==
164cbad219eSEddie James                 static_cast<EventState>(
165815f9f55STom Joseph                     PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
166815f9f55STom Joseph             {
167a8857c50SChris Cain                 log<level::INFO>(
1688b508bfbSChris Cain                     fmt::format("PLDM: OCC{} is RUNNING", instance).c_str());
169*7b00cde2SChris Cain                 isRunning = true;
170815f9f55STom Joseph             }
171815f9f55STom Joseph             else if (eventState ==
172815f9f55STom Joseph                      static_cast<EventState>(
173815f9f55STom Joseph                          PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
174815f9f55STom Joseph             {
1758b508bfbSChris Cain                 log<level::INFO>(
1768b508bfbSChris Cain                     fmt::format("PLDM: OCC{} has now STOPPED", instance)
177a8857c50SChris Cain                         .c_str());
178815f9f55STom Joseph             }
179bae4d07eSChris Cain             else if (eventState ==
180bae4d07eSChris Cain                      static_cast<EventState>(
181bae4d07eSChris Cain                          PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT))
182bae4d07eSChris Cain             {
183bae4d07eSChris Cain                 log<level::INFO>(
184bae4d07eSChris Cain                     fmt::format(
185bae4d07eSChris Cain                         "PLDM: OCC{} has now STOPPED and system is in SAFE MODE",
1868b508bfbSChris Cain                         instance)
187bae4d07eSChris Cain                         .c_str());
18831a2f13aSSheldon Bailey 
18931a2f13aSSheldon Bailey                 // Setting safe mode true
19031a2f13aSSheldon Bailey                 safeModeCallBack(true);
191bae4d07eSChris Cain             }
192bae4d07eSChris Cain             else
193bae4d07eSChris Cain             {
194bae4d07eSChris Cain                 log<level::INFO>(
195bae4d07eSChris Cain                     fmt::format("PLDM: Unexpected PLDM state {} for OCC{}",
1968b508bfbSChris Cain                                 eventState, instance)
197bae4d07eSChris Cain                         .c_str());
198bae4d07eSChris Cain             }
199*7b00cde2SChris Cain 
200*7b00cde2SChris Cain             if (!open_power::occ::utils::isHostRunning())
201*7b00cde2SChris Cain             {
202*7b00cde2SChris Cain                 log<level::INFO>("PLDM: HOST is not running");
203*7b00cde2SChris Cain                 isRunning = false;
204*7b00cde2SChris Cain             }
205*7b00cde2SChris Cain             callBack(instance, isRunning);
206*7b00cde2SChris Cain 
207432dc486SEddie James             return;
208cbad219eSEddie James         }
209432dc486SEddie James     }
210432dc486SEddie James 
211432dc486SEddie James     if (msgSensorOffset == SBESensorOffset)
212cbad219eSEddie James     {
213cbad219eSEddie James         auto sensorEntry = sensorToSBEInstance.find(sensorId);
214815f9f55STom Joseph 
215432dc486SEddie James         if (sensorEntry != sensorToSBEInstance.end())
216cbad219eSEddie James         {
21712d0b828SChris Cain             const uint8_t instance = sensorEntry->second;
21812d0b828SChris Cain             auto match = std::find(outstandingHResets.begin(),
21912d0b828SChris Cain                                    outstandingHResets.end(), instance);
22012d0b828SChris Cain             if (match != outstandingHResets.end())
22112d0b828SChris Cain             {
22212d0b828SChris Cain                 outstandingHResets.erase(match);
223cbad219eSEddie James                 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
224cbad219eSEddie James                 {
225bae4d07eSChris Cain                     log<level::INFO>(
226bae4d07eSChris Cain                         fmt::format("pldm: HRESET is NOT READY (OCC{})",
22712d0b828SChris Cain                                     instance)
228bae4d07eSChris Cain                             .c_str());
229cbad219eSEddie James                 }
23012d0b828SChris Cain                 else if (eventState ==
23112d0b828SChris Cain                          static_cast<EventState>(SBE_HRESET_READY))
232cbad219eSEddie James                 {
23312d0b828SChris Cain                     sbeCallBack(instance, true);
234cbad219eSEddie James                 }
23512d0b828SChris Cain                 else if (eventState ==
23612d0b828SChris Cain                          static_cast<EventState>(SBE_HRESET_FAILED))
237cbad219eSEddie James                 {
23812d0b828SChris Cain                     sbeCallBack(instance, false);
239cbad219eSEddie James                 }
240cbad219eSEddie James             }
24112d0b828SChris Cain             // else request was not from us
24212d0b828SChris Cain         }
243cbad219eSEddie James     }
244432dc486SEddie James }
245cbad219eSEddie James 
246af40808fSPatrick Williams void Interface::hostStateEvent(sdbusplus::message_t& msg)
247157467d0SChris Cain {
248157467d0SChris Cain     std::map<std::string, std::variant<std::string>> properties{};
249157467d0SChris Cain     std::string interface;
250157467d0SChris Cain     msg.read(interface, properties);
251157467d0SChris Cain     const auto stateEntry = properties.find("CurrentHostState");
252157467d0SChris Cain     if (stateEntry != properties.end())
253157467d0SChris Cain     {
254157467d0SChris Cain         auto stateEntryValue = stateEntry->second;
255157467d0SChris Cain         auto propVal = std::get<std::string>(stateEntryValue);
256157467d0SChris Cain         if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
257157467d0SChris Cain         {
258157467d0SChris Cain             clearData();
259157467d0SChris Cain         }
260157467d0SChris Cain     }
261157467d0SChris Cain }
262157467d0SChris Cain 
263bae4d07eSChris Cain void Interface::clearData()
264bae4d07eSChris Cain {
26572d01aabSChris Cain     if (!sensorToOCCInstance.empty())
26672d01aabSChris Cain     {
26772d01aabSChris Cain         log<level::INFO>(
26872d01aabSChris Cain             fmt::format("clearData: Clearing sensorToOCCInstance ({} entries)",
26972d01aabSChris Cain                         sensorToOCCInstance.size())
27072d01aabSChris Cain                 .c_str());
27172d01aabSChris Cain         for (auto entry : sensorToOCCInstance)
27272d01aabSChris Cain         {
27372d01aabSChris Cain             log<level::INFO>(
27472d01aabSChris Cain                 fmt::format("clearData: OCC{} / sensorID: 0x{:04X}",
27572d01aabSChris Cain                             entry.second, entry.first)
27672d01aabSChris Cain                     .c_str());
27772d01aabSChris Cain         }
278815f9f55STom Joseph         sensorToOCCInstance.clear();
27972d01aabSChris Cain     }
28072d01aabSChris Cain     if (!occInstanceToEffecter.empty())
28172d01aabSChris Cain     {
28272d01aabSChris Cain         log<level::DEBUG>(
28372d01aabSChris Cain             fmt::format(
28472d01aabSChris Cain                 "clearData: Clearing occInstanceToEffecter ({} entries)",
28572d01aabSChris Cain                 occInstanceToEffecter.size())
28672d01aabSChris Cain                 .c_str());
28700325238STom Joseph         occInstanceToEffecter.clear();
28872d01aabSChris Cain     }
28972d01aabSChris Cain     if (!sensorToSBEInstance.empty())
29072d01aabSChris Cain     {
29172d01aabSChris Cain         log<level::DEBUG>(
29272d01aabSChris Cain             fmt::format("clearData: Clearing sensorToSBEInstance ({} entries)",
29372d01aabSChris Cain                         sensorToSBEInstance.size())
29472d01aabSChris Cain                 .c_str());
295cbad219eSEddie James         sensorToSBEInstance.clear();
29672d01aabSChris Cain     }
29772d01aabSChris Cain     if (!sbeInstanceToEffecter.empty())
29872d01aabSChris Cain     {
29972d01aabSChris Cain         log<level::DEBUG>(
30072d01aabSChris Cain             fmt::format(
30172d01aabSChris Cain                 "clearData: Clearing sbeInstanceToEffecter ({} entries)",
30272d01aabSChris Cain                 sbeInstanceToEffecter.size())
30372d01aabSChris Cain                 .c_str());
304cbad219eSEddie James         sbeInstanceToEffecter.clear();
305815f9f55STom Joseph     }
30672d01aabSChris Cain }
307815f9f55STom Joseph 
308432dc486SEddie James void Interface::fetchEffecterInfo(uint16_t stateSetId,
309cbad219eSEddie James                                   InstanceToEffecter& instanceToEffecterMap,
310cbad219eSEddie James                                   CompositeEffecterCount& effecterCount,
311cbad219eSEddie James                                   uint8_t& stateIdPos)
31200325238STom Joseph {
313cbad219eSEddie James     PdrList pdrs{};
314cbad219eSEddie James 
315cbad219eSEddie James     auto& bus = open_power::occ::utils::getBus();
316cbad219eSEddie James     try
317cbad219eSEddie James     {
318cbad219eSEddie James         auto method = bus.new_method_call(
319cbad219eSEddie James             "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
320cbad219eSEddie James             "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
321bae4d07eSChris Cain         method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
322cbad219eSEddie James 
323cbad219eSEddie James         auto responseMsg = bus.call(method);
324cbad219eSEddie James         responseMsg.read(pdrs);
325cbad219eSEddie James     }
326af40808fSPatrick Williams     catch (const sdbusplus::exception_t& e)
327cbad219eSEddie James     {
328cbad219eSEddie James         log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
329cbad219eSEddie James                         entry("ERROR=%s", e.what()));
330cbad219eSEddie James     }
331cbad219eSEddie James 
332cbad219eSEddie James     if (!pdrs.size())
333cbad219eSEddie James     {
334cbad219eSEddie James         log<level::ERR>("pldm: state effecter PDRs not present");
335cbad219eSEddie James         return;
336cbad219eSEddie James     }
337cbad219eSEddie James 
33800325238STom Joseph     bool offsetFound = false;
339f3a4a69fSGeorge Liu     auto stateEffecterPDR =
34000325238STom Joseph         reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
341f3a4a69fSGeorge Liu     auto possibleStatesPtr = stateEffecterPDR->possible_states;
342f3a4a69fSGeorge Liu     for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
343f3a4a69fSGeorge Liu          offset++)
34400325238STom Joseph     {
34500325238STom Joseph         auto possibleStates =
34600325238STom Joseph             reinterpret_cast<const state_effecter_possible_states*>(
34700325238STom Joseph                 possibleStatesPtr);
34800325238STom Joseph 
349cbad219eSEddie James         if (possibleStates->state_set_id == stateSetId)
35000325238STom Joseph         {
351cbad219eSEddie James             stateIdPos = offset;
352f3a4a69fSGeorge Liu             effecterCount = stateEffecterPDR->composite_effecter_count;
35300325238STom Joseph             offsetFound = true;
35400325238STom Joseph             break;
35500325238STom Joseph         }
35600325238STom Joseph         possibleStatesPtr += sizeof(possibleStates->state_set_id) +
35700325238STom Joseph                              sizeof(possibleStates->possible_states_size) +
35800325238STom Joseph                              possibleStates->possible_states_size;
35900325238STom Joseph     }
36000325238STom Joseph 
36100325238STom Joseph     if (!offsetFound)
36200325238STom Joseph     {
36300325238STom Joseph         return;
36400325238STom Joseph     }
36500325238STom Joseph 
3660f516528SChris Cain     std::map<uint32_t, EffecterID> entityInstMap{};
36700325238STom Joseph     for (auto& pdr : pdrs)
36800325238STom Joseph     {
36900325238STom Joseph         auto pdrPtr =
37000325238STom Joseph             reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
37172d01aabSChris Cain         uint32_t key = pdrPtr->effecter_id;
3721339ab60SMatt Spinler         entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
37300325238STom Joseph     }
37400325238STom Joseph 
37500325238STom Joseph     open_power::occ::instanceID position = start;
37600325238STom Joseph     for (auto const& pair : entityInstMap)
37700325238STom Joseph     {
378cbad219eSEddie James         instanceToEffecterMap.emplace(position, pair.second);
37900325238STom Joseph         position++;
38000325238STom Joseph     }
38100325238STom Joseph }
38200325238STom Joseph 
38300325238STom Joseph std::vector<uint8_t>
3848b508bfbSChris Cain     Interface::prepareSetEffecterReq(EffecterID effecterId,
38500325238STom Joseph                                      CompositeEffecterCount effecterCount,
386cbad219eSEddie James                                      uint8_t stateIdPos, uint8_t stateSetValue)
38700325238STom Joseph {
3888b508bfbSChris Cain     if (!getMctpInstanceId())
3898b508bfbSChris Cain     {
3908b508bfbSChris Cain         return std::vector<uint8_t>();
3918b508bfbSChris Cain     }
3928b508bfbSChris Cain 
39300325238STom Joseph     std::vector<uint8_t> request(
39400325238STom Joseph         sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
39500325238STom Joseph         (effecterCount * sizeof(set_effecter_state_field)));
39600325238STom Joseph     auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
39700325238STom Joseph     std::vector<set_effecter_state_field> stateField;
39800325238STom Joseph 
39900325238STom Joseph     for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
40000325238STom Joseph     {
401cbad219eSEddie James         if (effecterPos == stateIdPos)
40200325238STom Joseph         {
403cbad219eSEddie James             stateField.emplace_back(
404cbad219eSEddie James                 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
40500325238STom Joseph         }
40600325238STom Joseph         else
40700325238STom Joseph         {
40800325238STom Joseph             stateField.emplace_back(
40900325238STom Joseph                 set_effecter_state_field{PLDM_NO_CHANGE, 0});
41000325238STom Joseph         }
41100325238STom Joseph     }
41200325238STom Joseph     auto rc = encode_set_state_effecter_states_req(
4138b508bfbSChris Cain         mctpInstance.value(), effecterId, effecterCount, stateField.data(),
4148b508bfbSChris Cain         requestMsg);
41500325238STom Joseph     if (rc != PLDM_SUCCESS)
41600325238STom Joseph     {
41700325238STom Joseph         log<level::ERR>("encode set effecter states request returned error ",
41800325238STom Joseph                         entry("RC=%d", rc));
41900325238STom Joseph         request.clear();
42000325238STom Joseph     }
42100325238STom Joseph     return request;
42200325238STom Joseph }
42300325238STom Joseph 
42400325238STom Joseph void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
42500325238STom Joseph {
426bae4d07eSChris Cain     if (open_power::occ::utils::isHostRunning())
427bae4d07eSChris Cain     {
42800325238STom Joseph         if (!isPDREffecterCacheValid())
42900325238STom Joseph         {
430432dc486SEddie James             fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
431432dc486SEddie James                               occInstanceToEffecter, OCCEffecterCount,
432432dc486SEddie James                               bootRestartPosition);
43300325238STom Joseph         }
43400325238STom Joseph 
43500325238STom Joseph         // Find the matching effecter for the OCC instance
43600325238STom Joseph         auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
43700325238STom Joseph         if (effecterEntry == occInstanceToEffecter.end())
43800325238STom Joseph         {
43900325238STom Joseph             log<level::ERR>(
4400f516528SChris Cain                 fmt::format(
4410f516528SChris Cain                     "pldm: Failed to find a matching effecter for OCC instance {}",
4420f516528SChris Cain                     occInstanceId)
4430f516528SChris Cain                     .c_str());
44400325238STom Joseph 
44500325238STom Joseph             return;
44600325238STom Joseph         }
44700325238STom Joseph 
448cbad219eSEddie James         // Prepare the SetStateEffecterStates request to reset the OCC
449cbad219eSEddie James         auto request = prepareSetEffecterReq(
4508b508bfbSChris Cain             effecterEntry->second, OCCEffecterCount, bootRestartPosition,
4518b508bfbSChris Cain             PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
452cbad219eSEddie James 
453cbad219eSEddie James         if (request.empty())
454cbad219eSEddie James         {
455bae4d07eSChris Cain             log<level::ERR>(
456bae4d07eSChris Cain                 "pldm: SetStateEffecterStates OCC reset request empty");
457cbad219eSEddie James             return;
458cbad219eSEddie James         }
459cbad219eSEddie James 
460bae4d07eSChris Cain         // Send request to reset the OCCs/PM Complex (ignore response)
461bae4d07eSChris Cain         sendPldm(request, occInstanceId, false);
462bae4d07eSChris Cain     }
463bae4d07eSChris Cain     else
464bae4d07eSChris Cain     {
465bae4d07eSChris Cain         log<level::ERR>(
466bae4d07eSChris Cain             fmt::format("resetOCC: HOST is not running (OCC{})", occInstanceId)
467bae4d07eSChris Cain                 .c_str());
468bae4d07eSChris Cain         clearData();
469bae4d07eSChris Cain     }
470cbad219eSEddie James }
471cbad219eSEddie James 
472cbad219eSEddie James void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
473cbad219eSEddie James {
474bae4d07eSChris Cain     if (open_power::occ::utils::isHostRunning())
475bae4d07eSChris Cain     {
476cbad219eSEddie James         if (sbeInstanceToEffecter.empty())
477cbad219eSEddie James         {
478432dc486SEddie James             fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
479cbad219eSEddie James                               sbeInstanceToEffecter, SBEEffecterCount,
480cbad219eSEddie James                               sbeMaintenanceStatePosition);
481cbad219eSEddie James         }
482cbad219eSEddie James 
483cbad219eSEddie James         auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
484cbad219eSEddie James         if (effecterEntry == sbeInstanceToEffecter.end())
485cbad219eSEddie James         {
486cbad219eSEddie James             log<level::ERR>(
487cbad219eSEddie James                 "pldm: Failed to find a matching effecter for SBE instance",
488cbad219eSEddie James                 entry("SBE=%d", sbeInstanceId));
489cbad219eSEddie James             return;
490cbad219eSEddie James         }
491cbad219eSEddie James 
492cbad219eSEddie James         // Prepare the SetStateEffecterStates request to HRESET the SBE
493cbad219eSEddie James         auto request = prepareSetEffecterReq(
4948b508bfbSChris Cain             effecterEntry->second, SBEEffecterCount,
495cbad219eSEddie James             sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
496cbad219eSEddie James 
497cbad219eSEddie James         if (request.empty())
498cbad219eSEddie James         {
499bae4d07eSChris Cain             log<level::ERR>(
500bae4d07eSChris Cain                 "pldm: SetStateEffecterStates HRESET request empty");
501cbad219eSEddie James             return;
502cbad219eSEddie James         }
503cbad219eSEddie James 
504bae4d07eSChris Cain         // Send request to issue HRESET of SBE (ignore response)
505bae4d07eSChris Cain         sendPldm(request, sbeInstanceId, false);
50612d0b828SChris Cain         outstandingHResets.insert(sbeInstanceId);
507bae4d07eSChris Cain     }
508bae4d07eSChris Cain     else
509bae4d07eSChris Cain     {
510bae4d07eSChris Cain         log<level::ERR>(fmt::format("sendHRESET: HOST is not running (OCC{})",
511bae4d07eSChris Cain                                     sbeInstanceId)
512bae4d07eSChris Cain                             .c_str());
513bae4d07eSChris Cain         clearData();
514bae4d07eSChris Cain     }
515cbad219eSEddie James }
516cbad219eSEddie James 
5178b508bfbSChris Cain bool Interface::getMctpInstanceId()
518cbad219eSEddie James {
5198b508bfbSChris Cain     if (!mctpInstance)
5208b508bfbSChris Cain     {
5218b508bfbSChris Cain         // Request new instance ID
52248330578SChris Cain         auto& bus = open_power::occ::utils::getBus();
52300325238STom Joseph         try
52400325238STom Joseph         {
52500325238STom Joseph             auto method = bus.new_method_call(
52600325238STom Joseph                 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
52700325238STom Joseph                 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
52800325238STom Joseph             method.append(mctpEid);
52900325238STom Joseph             auto reply = bus.call(method);
5308b508bfbSChris Cain             uint8_t newInstanceId;
5318b508bfbSChris Cain             reply.read(newInstanceId);
5328b508bfbSChris Cain             mctpInstance = newInstanceId;
5338b508bfbSChris Cain             log<level::INFO>(fmt::format("pldm: got new InstanceId: {}",
5348b508bfbSChris Cain                                          mctpInstance.value())
5358b508bfbSChris Cain                                  .c_str());
53600325238STom Joseph         }
537af40808fSPatrick Williams         catch (const sdbusplus::exception_t& e)
53800325238STom Joseph         {
539bd551de3SChris Cain             log<level::ERR>(
5408b508bfbSChris Cain                 fmt::format("pldm: GetInstanceId failed: {}", e.what())
5418b508bfbSChris Cain                     .c_str());
542cbad219eSEddie James             return false;
54300325238STom Joseph         }
5448b508bfbSChris Cain     }
54500325238STom Joseph 
546cbad219eSEddie James     return true;
547cbad219eSEddie James }
54800325238STom Joseph 
549bae4d07eSChris Cain void Interface::sendPldm(const std::vector<uint8_t>& request,
550bae4d07eSChris Cain                          const uint8_t instance, const bool rspExpected)
55100325238STom Joseph {
5528b508bfbSChris Cain     if (!mctpInstance)
5538b508bfbSChris Cain     {
5548b508bfbSChris Cain         log<level::ERR>("sendPldm: No MCTP Instance ID found!");
5558b508bfbSChris Cain         return;
5568b508bfbSChris Cain     }
5578b508bfbSChris Cain 
558c9dc4418SChris Cain     // Connect to MCTP socket
559bae4d07eSChris Cain     pldmFd = pldm_open();
560bae4d07eSChris Cain     auto openErrno = errno;
561bae4d07eSChris Cain     if (pldmFd == PLDM_REQUESTER_OPEN_FAIL)
56200325238STom Joseph     {
563d1b6826aSChris Cain         log<level::ERR>(
564bae4d07eSChris Cain             fmt::format(
565bae4d07eSChris Cain                 "sendPldm: Failed to connect to MCTP socket, errno={}/{}",
566bae4d07eSChris Cain                 openErrno, strerror(openErrno))
567d1b6826aSChris Cain                 .c_str());
56800325238STom Joseph         return;
56900325238STom Joseph     }
570cbad219eSEddie James 
57100325238STom Joseph     // Send the PLDM request message to HBRT
572bae4d07eSChris Cain     if (rspExpected)
573d1b6826aSChris Cain     {
574bae4d07eSChris Cain         // Register callback when response is available
575bae4d07eSChris Cain         registerPldmRspCallback();
576bae4d07eSChris Cain 
577bae4d07eSChris Cain         // Send PLDM request
578bae4d07eSChris Cain         log<level::INFO>(
579bae4d07eSChris Cain             fmt::format(
580bae4d07eSChris Cain                 "sendPldm: calling pldm_send(OCC{}, instance:{}, {} bytes)",
5818b508bfbSChris Cain                 instance, mctpInstance.value(), request.size())
582bae4d07eSChris Cain                 .c_str());
583bae4d07eSChris Cain         pldmResponseReceived = false;
584bae4d07eSChris Cain         pldmResponseTimeout = false;
585bae4d07eSChris Cain         pldmResponseOcc = instance;
586bae4d07eSChris Cain         auto pldmRc =
587bae4d07eSChris Cain             pldm_send(mctpEid, pldmFd, request.data(), request.size());
588bae4d07eSChris Cain         auto sendErrno = errno;
589bae4d07eSChris Cain         if (pldmRc != PLDM_REQUESTER_SUCCESS)
590bae4d07eSChris Cain         {
591bae4d07eSChris Cain             log<level::ERR>(
592bae4d07eSChris Cain                 fmt::format(
593bae4d07eSChris Cain                     "sendPldm: pldm_send failed with rc={} and errno={}/{}",
594bae4d07eSChris Cain                     pldmRc, sendErrno, strerror(sendErrno))
595bae4d07eSChris Cain                     .c_str());
596bae4d07eSChris Cain             pldmClose();
597bae4d07eSChris Cain             return;
598bae4d07eSChris Cain         }
599bae4d07eSChris Cain 
600bae4d07eSChris Cain         // start timer waiting for the response
601bae4d07eSChris Cain         using namespace std::literals::chrono_literals;
602bd551de3SChris Cain         pldmRspTimer.restartOnce(8s);
603bae4d07eSChris Cain 
604bae4d07eSChris Cain         // Wait for response/timeout
605bae4d07eSChris Cain     }
606bae4d07eSChris Cain     else // not expecting the response
607bae4d07eSChris Cain     {
608bae4d07eSChris Cain         log<level::INFO>(
609bae4d07eSChris Cain             fmt::format(
610bae4d07eSChris Cain                 "sendPldm: calling pldm_send(mctpID:{}, fd:{}, {} bytes) for OCC{}",
611bae4d07eSChris Cain                 mctpEid, pldmFd, request.size(), instance)
612bae4d07eSChris Cain                 .c_str());
613bae4d07eSChris Cain         auto rc = pldm_send(mctpEid, pldmFd, request.data(), request.size());
614bae4d07eSChris Cain         auto sendErrno = errno;
61500325238STom Joseph         if (rc)
61600325238STom Joseph         {
617d1b6826aSChris Cain             log<level::ERR>(
618d1b6826aSChris Cain                 fmt::format(
619bae4d07eSChris Cain                     "sendPldm: pldm_send(mctpID:{}, fd:{}, {} bytes) failed with rc={} and errno={}/{}",
620bae4d07eSChris Cain                     mctpEid, pldmFd, request.size(), rc, sendErrno,
621bae4d07eSChris Cain                     strerror(sendErrno))
622d1b6826aSChris Cain                     .c_str());
62300325238STom Joseph         }
6248b508bfbSChris Cain         else
6258b508bfbSChris Cain         {
6268b508bfbSChris Cain             // Not waiting for response, instance ID should be freed
6278b508bfbSChris Cain             mctpInstance = std::nullopt;
6288b508bfbSChris Cain         }
629bae4d07eSChris Cain         pldmClose();
630bae4d07eSChris Cain     }
631bae4d07eSChris Cain }
63200325238STom Joseph 
633bae4d07eSChris Cain // Attaches the FD to event loop and registers the callback handler
634bae4d07eSChris Cain void Interface::registerPldmRspCallback()
635bae4d07eSChris Cain {
636bae4d07eSChris Cain     decltype(eventSource.get()) sourcePtr = nullptr;
637bae4d07eSChris Cain     auto rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN,
638bae4d07eSChris Cain                               pldmRspCallback, this);
639bae4d07eSChris Cain     if (rc < 0)
64000325238STom Joseph     {
64100325238STom Joseph         log<level::ERR>(
642d1b6826aSChris Cain             fmt::format(
643bae4d07eSChris Cain                 "registerPldmRspCallback: sd_event_add_io: Error({})={} : fd={}",
644bae4d07eSChris Cain                 rc, strerror(-rc), pldmFd)
645d1b6826aSChris Cain                 .c_str());
646d1b6826aSChris Cain     }
647d1b6826aSChris Cain     else
648d1b6826aSChris Cain     {
649bae4d07eSChris Cain         // puts sourcePtr in the event source.
650bae4d07eSChris Cain         eventSource.reset(sourcePtr);
651bae4d07eSChris Cain     }
652bae4d07eSChris Cain }
653bae4d07eSChris Cain 
654bae4d07eSChris Cain // Add a timer to the event loop, default 30s.
655bae4d07eSChris Cain void Interface::pldmRspExpired()
656bae4d07eSChris Cain {
657bae4d07eSChris Cain     if (!pldmResponseReceived)
658bae4d07eSChris Cain     {
659bae4d07eSChris Cain         log<level::ERR>(
660bae4d07eSChris Cain             fmt::format(
661bae4d07eSChris Cain                 "pldmRspExpired: timerCallback - timeout waiting for pldm response for OCC{}",
662bae4d07eSChris Cain                 pldmResponseOcc)
663d1b6826aSChris Cain                 .c_str());
664bae4d07eSChris Cain         pldmResponseTimeout = true;
665bae4d07eSChris Cain         if (pldmFd)
666bae4d07eSChris Cain         {
667bae4d07eSChris Cain             pldmClose();
668bae4d07eSChris Cain         }
669bae4d07eSChris Cain     }
670bae4d07eSChris Cain     return;
671bae4d07eSChris Cain };
672bae4d07eSChris Cain 
673bae4d07eSChris Cain void Interface::pldmClose()
674bae4d07eSChris Cain {
675bae4d07eSChris Cain     if (pldmRspTimer.isEnabled())
676bae4d07eSChris Cain     {
677bae4d07eSChris Cain         // stop PLDM response timer
678bae4d07eSChris Cain         pldmRspTimer.setEnabled(false);
679bae4d07eSChris Cain     }
680bae4d07eSChris Cain     close(pldmFd);
681bae4d07eSChris Cain     pldmFd = -1;
682bae4d07eSChris Cain     eventSource.reset();
683bae4d07eSChris Cain }
684bae4d07eSChris Cain 
685bae4d07eSChris Cain int Interface::pldmRspCallback(sd_event_source* /*es*/, int fd,
686bae4d07eSChris Cain                                uint32_t revents, void* userData)
687bae4d07eSChris Cain {
688bae4d07eSChris Cain     if (!(revents & EPOLLIN))
689bae4d07eSChris Cain     {
690bae4d07eSChris Cain         log<level::INFO>(
691bae4d07eSChris Cain             fmt::format("pldmRspCallback - revents={:08X}", revents).c_str());
692bae4d07eSChris Cain         return -1;
693bae4d07eSChris Cain     }
694bae4d07eSChris Cain 
695bae4d07eSChris Cain     auto pldmIface = static_cast<Interface*>(userData);
696bae4d07eSChris Cain 
6978b508bfbSChris Cain     if (!pldmIface->mctpInstance)
6988b508bfbSChris Cain     {
6998b508bfbSChris Cain         log<level::ERR>(
7008b508bfbSChris Cain             "pldmRspCallback: No outstanding MCTP Instance ID found");
7018b508bfbSChris Cain         return -1;
7028b508bfbSChris Cain     }
7038b508bfbSChris Cain 
704bae4d07eSChris Cain     uint8_t* responseMsg = nullptr;
705bae4d07eSChris Cain     size_t responseMsgSize{};
706bae4d07eSChris Cain 
707bae4d07eSChris Cain     log<level::INFO>(
708bae4d07eSChris Cain         fmt::format("pldmRspCallback: calling pldm_recv() instance:{}",
7098b508bfbSChris Cain                     pldmIface->mctpInstance.value())
710bae4d07eSChris Cain             .c_str());
7118b508bfbSChris Cain     auto rc = pldm_recv(mctpEid, fd, pldmIface->mctpInstance.value(),
7128b508bfbSChris Cain                         &responseMsg, &responseMsgSize);
713bae4d07eSChris Cain     int lastErrno = errno;
714d1b6826aSChris Cain     if (rc)
715d1b6826aSChris Cain     {
716d1b6826aSChris Cain         log<level::ERR>(
717d1b6826aSChris Cain             fmt::format(
718bae4d07eSChris Cain                 "pldmRspCallback: pldm_recv failed with rc={}, errno={}/{}", rc,
719bae4d07eSChris Cain                 lastErrno, strerror(lastErrno))
720bae4d07eSChris Cain                 .c_str());
721bae4d07eSChris Cain         return -1;
722bae4d07eSChris Cain     }
7238b508bfbSChris Cain 
7248b508bfbSChris Cain     // We got the response for the PLDM request msg that was sent
725bae4d07eSChris Cain     log<level::INFO>(
726bae4d07eSChris Cain         fmt::format("pldmRspCallback: pldm_recv() rsp was {} bytes",
727bae4d07eSChris Cain                     responseMsgSize)
728bae4d07eSChris Cain             .c_str());
729bae4d07eSChris Cain 
730bae4d07eSChris Cain     if (pldmIface->pldmRspTimer.isEnabled())
731bae4d07eSChris Cain     {
732bae4d07eSChris Cain         // stop PLDM response timer
733bae4d07eSChris Cain         pldmIface->pldmRspTimer.setEnabled(false);
734bae4d07eSChris Cain     }
735bae4d07eSChris Cain 
7368b508bfbSChris Cain     // instance ID should be freed
7378b508bfbSChris Cain     pldmIface->mctpInstance = std::nullopt;
7388b508bfbSChris Cain 
739bae4d07eSChris Cain     // Set pointer to autodelete
740bae4d07eSChris Cain     std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
741bae4d07eSChris Cain                                                                   std::free};
742bae4d07eSChris Cain 
743bae4d07eSChris Cain     auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
744bae4d07eSChris Cain     if (response->payload[0] != PLDM_SUCCESS)
745bae4d07eSChris Cain     {
746bae4d07eSChris Cain         log<level::ERR>(
747bae4d07eSChris Cain             fmt::format("pldmRspCallback: payload[0] was not success: {}",
748bae4d07eSChris Cain                         response->payload[0])
749bae4d07eSChris Cain                 .c_str());
750bae4d07eSChris Cain         pldmIface->pldmClose();
751bae4d07eSChris Cain         return -1;
752bae4d07eSChris Cain     }
753bae4d07eSChris Cain 
754bae4d07eSChris Cain     // Decode the response
755bae4d07eSChris Cain     uint8_t compCode = 0, sensorCount = 1;
756bae4d07eSChris Cain     get_sensor_state_field field[6];
757bae4d07eSChris Cain     responseMsgSize -= sizeof(pldm_msg_hdr);
758bae4d07eSChris Cain     auto msgRc = decode_get_state_sensor_readings_resp(
759bae4d07eSChris Cain         response, responseMsgSize, &compCode, &sensorCount, field);
760bae4d07eSChris Cain     if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS))
761bae4d07eSChris Cain     {
762bae4d07eSChris Cain         log<level::ERR>(
763bae4d07eSChris Cain             fmt::format(
764bae4d07eSChris Cain                 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={} and compCode={}",
765bae4d07eSChris Cain                 msgRc, compCode)
766bae4d07eSChris Cain                 .c_str());
767bae4d07eSChris Cain         pldmIface->pldmClose();
768bae4d07eSChris Cain         return -1;
769bae4d07eSChris Cain     }
770bae4d07eSChris Cain 
771bae4d07eSChris Cain     pldmIface->pldmClose();
772bae4d07eSChris Cain 
773bae4d07eSChris Cain     const uint8_t instance = pldmIface->pldmResponseOcc;
774bae4d07eSChris Cain     const uint8_t occSensorState = field[0].present_state;
775bae4d07eSChris Cain     pldmIface->pldmResponseReceived = true;
776bae4d07eSChris Cain 
777bae4d07eSChris Cain     if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)
778bae4d07eSChris Cain     {
779bae4d07eSChris Cain         log<level::INFO>(
780bae4d07eSChris Cain             fmt::format("pldmRspCallback: OCC{} is RUNNING", instance).c_str());
781bae4d07eSChris Cain         pldmIface->callBack(instance, true);
782bae4d07eSChris Cain     }
783733b201fSChris Cain     else if (occSensorState ==
784733b201fSChris Cain              PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT)
785733b201fSChris Cain     {
786733b201fSChris Cain         log<level::INFO>(
787733b201fSChris Cain             fmt::format(
788733b201fSChris Cain                 "pldmRspCallback: OCC{} has now STOPPED and system is in SAFE MODE",
789733b201fSChris Cain                 instance)
790733b201fSChris Cain                 .c_str());
79131a2f13aSSheldon Bailey 
79231a2f13aSSheldon Bailey         // Setting safe mode true
79331a2f13aSSheldon Bailey         pldmIface->safeModeCallBack(true);
79431a2f13aSSheldon Bailey 
795733b201fSChris Cain         pldmIface->callBack(instance, false);
796733b201fSChris Cain     }
797bae4d07eSChris Cain     else
798bae4d07eSChris Cain     {
799bae4d07eSChris Cain         log<level::INFO>(
8008b508bfbSChris Cain             fmt::format(
8018b508bfbSChris Cain                 "pldmRspCallback: OCC{} is not running (sensor state:{})",
802bae4d07eSChris Cain                 instance, occSensorState)
803bae4d07eSChris Cain                 .c_str());
804c9dc4418SChris Cain         if (occSensorState != PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED)
805c9dc4418SChris Cain         {
806c9dc4418SChris Cain             const size_t rspLength = responseMsgSize + sizeof(pldm_msg_hdr);
807c9dc4418SChris Cain             std::vector<std::uint8_t> pldmResponse(rspLength);
808c9dc4418SChris Cain             memcpy(&pldmResponse[0], reinterpret_cast<std::uint8_t*>(response),
809c9dc4418SChris Cain                    rspLength);
810c9dc4418SChris Cain             log<level::ERR>(
811c9dc4418SChris Cain                 fmt::format(
812c9dc4418SChris Cain                     "pldmRspCallback: Bad State - PLDM response ({} bytes) for OCC{}:",
813c9dc4418SChris Cain                     rspLength, instance)
814c9dc4418SChris Cain                     .c_str());
815c9dc4418SChris Cain             dump_hex(pldmResponse);
816c9dc4418SChris Cain         }
817bae4d07eSChris Cain         pldmIface->callBack(instance, false);
818bae4d07eSChris Cain     }
819bae4d07eSChris Cain 
820bae4d07eSChris Cain     return 0;
821bae4d07eSChris Cain };
822bae4d07eSChris Cain 
823bae4d07eSChris Cain std::vector<uint8_t> Interface::encodeGetStateSensorRequest(uint8_t instance,
824bae4d07eSChris Cain                                                             uint16_t sensorId)
825bae4d07eSChris Cain {
8268b508bfbSChris Cain     if (!getMctpInstanceId())
8278b508bfbSChris Cain     {
8288b508bfbSChris Cain         log<level::ERR>(
8298b508bfbSChris Cain             "encodeGetStateSensorRequest: failed to getMctpInstanceId");
8308b508bfbSChris Cain         return std::vector<uint8_t>();
8318b508bfbSChris Cain     }
8328b508bfbSChris Cain 
833bae4d07eSChris Cain     bitfield8_t sRearm = {0};
834bae4d07eSChris Cain     const size_t msgSize =
835bae4d07eSChris Cain         sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES;
836bae4d07eSChris Cain     std::vector<uint8_t> request(msgSize);
8378b508bfbSChris Cain 
838bae4d07eSChris Cain     auto msg = reinterpret_cast<pldm_msg*>(request.data());
8398b508bfbSChris Cain     auto msgRc = encode_get_state_sensor_readings_req(mctpInstance.value(),
8408b508bfbSChris Cain                                                       sensorId, sRearm, 0, msg);
841bae4d07eSChris Cain     if (msgRc != PLDM_SUCCESS)
842bae4d07eSChris Cain     {
843bae4d07eSChris Cain         log<level::ERR>(
844bae4d07eSChris Cain             fmt::format(
845bae4d07eSChris Cain                 "encodeGetStateSensorRequest: Failed to encode sensorId:0x{:08X} for OCC{} (rc={})",
846bae4d07eSChris Cain                 sensorId, instance, msgRc)
847d1b6826aSChris Cain                 .c_str());
848d1b6826aSChris Cain     }
849bae4d07eSChris Cain     return request;
850bae4d07eSChris Cain }
851bae4d07eSChris Cain 
852bae4d07eSChris Cain // Initiate query of the specified OCC Active Sensor
853bae4d07eSChris Cain void Interface::checkActiveSensor(uint8_t instance)
854bae4d07eSChris Cain {
855bae4d07eSChris Cain     static bool tracedOnce = false;
856bae4d07eSChris Cain     if (pldmFd > 0)
857bae4d07eSChris Cain     {
858bae4d07eSChris Cain         if (!tracedOnce)
859bae4d07eSChris Cain         {
860bae4d07eSChris Cain             log<level::ERR>(
861bae4d07eSChris Cain                 fmt::format(
862bae4d07eSChris Cain                     "checkActiveSensor: already waiting on OCC{} (fd={})",
863bae4d07eSChris Cain                     pldmResponseOcc, pldmFd)
864bae4d07eSChris Cain                     .c_str());
865bae4d07eSChris Cain             tracedOnce = true;
866bae4d07eSChris Cain         }
867bae4d07eSChris Cain         return;
868bae4d07eSChris Cain     }
869bae4d07eSChris Cain     tracedOnce = false;
870bae4d07eSChris Cain 
871bae4d07eSChris Cain     if (!isOCCSensorCacheValid())
872bae4d07eSChris Cain     {
873bae4d07eSChris Cain         fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
874bae4d07eSChris Cain                         sensorToOCCInstance, OCCSensorOffset);
875bae4d07eSChris Cain     }
876bae4d07eSChris Cain 
877bae4d07eSChris Cain     // look up sensor id (key) based on instance
878bae4d07eSChris Cain     auto entry = std::find_if(
879bae4d07eSChris Cain         sensorToOCCInstance.begin(), sensorToOCCInstance.end(),
880bae4d07eSChris Cain         [instance](const auto& entry) { return instance == entry.second; });
881bae4d07eSChris Cain     if (entry != sensorToOCCInstance.end())
882bae4d07eSChris Cain     {
883bae4d07eSChris Cain         // Query the OCC Active Sensor state for this instance
884bae4d07eSChris Cain         // SensorID sID = entry->first;
885bae4d07eSChris Cain         log<level::INFO>(
886bae4d07eSChris Cain             fmt::format("checkActiveSensor: OCC{} / sensorID: 0x{:04X}",
887bae4d07eSChris Cain                         instance, entry->first)
888bae4d07eSChris Cain                 .c_str());
889bae4d07eSChris Cain 
890bae4d07eSChris Cain         // Encode GetStateSensorReadings PLDM message
891bae4d07eSChris Cain         auto request = encodeGetStateSensorRequest(instance, entry->first);
892bae4d07eSChris Cain         if (request.empty())
893bae4d07eSChris Cain         {
894bae4d07eSChris Cain             return;
895bae4d07eSChris Cain         }
896bae4d07eSChris Cain 
897bae4d07eSChris Cain         // Send request to PLDM and setup callback for response
898bae4d07eSChris Cain         sendPldm(request, instance, true);
899bae4d07eSChris Cain     }
900bae4d07eSChris Cain     else
901bae4d07eSChris Cain     {
902bae4d07eSChris Cain         log<level::ERR>(
903bae4d07eSChris Cain             fmt::format(
904bae4d07eSChris Cain                 "checkActiveSensor: Unable to find PLDM sensor for OCC{}",
905bae4d07eSChris Cain                 instance)
906bae4d07eSChris Cain                 .c_str());
9078cf7496bSChris Cain         log<level::INFO>(
9088cf7496bSChris Cain             "checkActiveSensor: fetching STATE_SET_OPERATIONAL_RUNNING_STATUS");
9098cf7496bSChris Cain         fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
9108cf7496bSChris Cain                         sensorToOCCInstance, OCCSensorOffset);
91100325238STom Joseph     }
91200325238STom Joseph }
91300325238STom Joseph 
914815f9f55STom Joseph } // namespace pldm
915