xref: /openbmc/openpower-occ-control/pldm.cpp (revision a937491b)
1 #include "pldm.hpp"
2 
3 #include "file.hpp"
4 
5 #include <fmt/core.h>
6 #include <libpldm/entity.h>
7 #include <libpldm/platform.h>
8 #include <libpldm/state_set.h>
9 #include <libpldm/state_set_oem_ibm.h>
10 
11 #include <phosphor-logging/log.hpp>
12 #include <sdbusplus/bus.hpp>
13 #include <sdeventplus/clock.hpp>
14 #include <sdeventplus/exception.hpp>
15 #include <sdeventplus/source/io.hpp>
16 #include <sdeventplus/source/time.hpp>
17 
18 #include <algorithm>
19 
20 namespace pldm
21 {
22 
23 using namespace phosphor::logging;
24 
25 using namespace sdeventplus;
26 using namespace sdeventplus::source;
27 constexpr auto clockId = sdeventplus::ClockId::RealTime;
28 using Clock = sdeventplus::Clock<clockId>;
29 using Timer = Time<clockId>;
30 
31 void Interface::fetchSensorInfo(uint16_t stateSetId,
32                                 SensorToInstance& sensorInstanceMap,
33                                 SensorOffset& sensorOffset)
34 {
35     PdrList pdrs{};
36     static bool tracedError = false;
37 
38     auto& bus = open_power::occ::utils::getBus();
39     try
40     {
41         auto method = bus.new_method_call(
42             "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
43             "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
44         method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
45 
46         auto responseMsg = bus.call(method);
47         responseMsg.read(pdrs);
48     }
49     catch (const sdbusplus::exception_t& e)
50     {
51         if (!tracedError)
52         {
53             log<level::ERR>(
54                 fmt::format(
55                     "fetchSensorInfo: Failed to find stateSetID:{} PDR: {}",
56                     stateSetId, e.what())
57                     .c_str());
58             tracedError = true;
59         }
60     }
61 
62     if (pdrs.empty())
63     {
64         if (!tracedError)
65         {
66             log<level::ERR>(
67                 fmt::format(
68                     "fetchSensorInfo: state sensor PDRs ({}) not present",
69                     stateSetId)
70                     .c_str());
71             tracedError = true;
72         }
73         return;
74     }
75 
76     // Found PDR
77     if (tracedError)
78     {
79         log<level::INFO>(
80             fmt::format("fetchSensorInfo: found {} PDRs", pdrs.size()).c_str());
81         tracedError = false;
82     }
83 
84     bool offsetFound = false;
85     auto stateSensorPDR =
86         reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
87     auto possibleStatesPtr = stateSensorPDR->possible_states;
88     for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count;
89          offset++)
90     {
91         auto possibleStates =
92             reinterpret_cast<const state_sensor_possible_states*>(
93                 possibleStatesPtr);
94 
95         if (possibleStates->state_set_id == stateSetId)
96         {
97             sensorOffset = offset;
98             offsetFound = true;
99             break;
100         }
101         possibleStatesPtr += sizeof(possibleStates->state_set_id) +
102                              sizeof(possibleStates->possible_states_size) +
103                              possibleStates->possible_states_size;
104     }
105 
106     if (!offsetFound)
107     {
108         log<level::ERR>("pldm: state sensor PDR not found");
109         return;
110     }
111 
112     // To order SensorID based on the EntityInstance.
113     // Note that when a proc is on a DCM, the PDRs for these sensors
114     // could have the same instance IDs but different container IDs.
115     std::map<uint32_t, SensorID> entityInstMap{};
116     for (auto& pdr : pdrs)
117     {
118         auto pdrPtr =
119             reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
120         uint32_t key = pdrPtr->sensor_id;
121         entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->sensor_id));
122     }
123 
124     open_power::occ::instanceID count = start;
125     for (const auto& pair : entityInstMap)
126     {
127         sensorInstanceMap.emplace(pair.second, count);
128         count++;
129     }
130 }
131 
132 void Interface::sensorEvent(sdbusplus::message_t& msg)
133 {
134     if (!isOCCSensorCacheValid())
135     {
136         fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
137                         sensorToOCCInstance, OCCSensorOffset);
138     }
139 
140     if (sensorToSBEInstance.empty())
141     {
142         fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSBEInstance,
143                         SBESensorOffset);
144     }
145 
146     TerminusID sensorTid{};
147     SensorID sensorId{};
148     SensorOffset msgSensorOffset{};
149     EventState eventState{};
150     EventState previousEventState{};
151 
152     msg.read(sensorTid, sensorId, msgSensorOffset, eventState,
153              previousEventState);
154 
155     if (msgSensorOffset == OCCSensorOffset)
156     {
157         auto sensorEntry = sensorToOCCInstance.find(sensorId);
158 
159         if (sensorEntry != sensorToOCCInstance.end())
160         {
161             const uint8_t instance = sensorEntry->second;
162             bool isRunning = false;
163             if (eventState ==
164                 static_cast<EventState>(
165                     PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
166             {
167                 log<level::INFO>(
168                     fmt::format("PLDM: OCC{} is RUNNING", instance).c_str());
169                 isRunning = true;
170             }
171             else if (eventState ==
172                      static_cast<EventState>(
173                          PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
174             {
175                 log<level::INFO>(
176                     fmt::format("PLDM: OCC{} has now STOPPED", instance)
177                         .c_str());
178             }
179             else if (eventState ==
180                      static_cast<EventState>(
181                          PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT))
182             {
183                 log<level::INFO>(
184                     fmt::format(
185                         "PLDM: OCC{} has now STOPPED and system is in SAFE MODE",
186                         instance)
187                         .c_str());
188 
189                 // Setting safe mode true
190                 safeModeCallBack(true);
191             }
192             else
193             {
194                 log<level::INFO>(
195                     fmt::format("PLDM: Unexpected PLDM state {} for OCC{}",
196                                 eventState, instance)
197                         .c_str());
198             }
199 
200             callBack(instance, isRunning);
201 
202             return;
203         }
204     }
205 
206     if (msgSensorOffset == SBESensorOffset)
207     {
208         auto sensorEntry = sensorToSBEInstance.find(sensorId);
209 
210         if (sensorEntry != sensorToSBEInstance.end())
211         {
212             const uint8_t instance = sensorEntry->second;
213             auto match = std::find(outstandingHResets.begin(),
214                                    outstandingHResets.end(), instance);
215             if (match != outstandingHResets.end())
216             {
217                 outstandingHResets.erase(match);
218                 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
219                 {
220                     log<level::INFO>(
221                         fmt::format("pldm: HRESET is NOT READY (OCC{})",
222                                     instance)
223                             .c_str());
224                 }
225                 else if (eventState ==
226                          static_cast<EventState>(SBE_HRESET_READY))
227                 {
228                     sbeCallBack(instance, true);
229                 }
230                 else if (eventState ==
231                          static_cast<EventState>(SBE_HRESET_FAILED))
232                 {
233                     sbeCallBack(instance, false);
234                 }
235             }
236             // else request was not from us
237         }
238     }
239 }
240 
241 void Interface::hostStateEvent(sdbusplus::message_t& msg)
242 {
243     std::map<std::string, std::variant<std::string>> properties{};
244     std::string interface;
245     msg.read(interface, properties);
246     const auto stateEntry = properties.find("CurrentHostState");
247     if (stateEntry != properties.end())
248     {
249         auto stateEntryValue = stateEntry->second;
250         auto propVal = std::get<std::string>(stateEntryValue);
251         if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
252         {
253             clearData();
254         }
255     }
256 }
257 
258 void Interface::clearData()
259 {
260     if (!sensorToOCCInstance.empty())
261     {
262         log<level::INFO>(
263             fmt::format("clearData: Clearing sensorToOCCInstance ({} entries)",
264                         sensorToOCCInstance.size())
265                 .c_str());
266         for (auto entry : sensorToOCCInstance)
267         {
268             log<level::INFO>(
269                 fmt::format("clearData: OCC{} / sensorID: 0x{:04X}",
270                             entry.second, entry.first)
271                     .c_str());
272             callBack(entry.second, false);
273         }
274         sensorToOCCInstance.clear();
275     }
276     if (!occInstanceToEffecter.empty())
277     {
278         log<level::DEBUG>(
279             fmt::format(
280                 "clearData: Clearing occInstanceToEffecter ({} entries)",
281                 occInstanceToEffecter.size())
282                 .c_str());
283         occInstanceToEffecter.clear();
284     }
285     if (!sensorToSBEInstance.empty())
286     {
287         log<level::DEBUG>(
288             fmt::format("clearData: Clearing sensorToSBEInstance ({} entries)",
289                         sensorToSBEInstance.size())
290                 .c_str());
291         sensorToSBEInstance.clear();
292     }
293     if (!sbeInstanceToEffecter.empty())
294     {
295         log<level::DEBUG>(
296             fmt::format(
297                 "clearData: Clearing sbeInstanceToEffecter ({} entries)",
298                 sbeInstanceToEffecter.size())
299                 .c_str());
300         sbeInstanceToEffecter.clear();
301     }
302 }
303 
304 void Interface::fetchEffecterInfo(uint16_t stateSetId,
305                                   InstanceToEffecter& instanceToEffecterMap,
306                                   CompositeEffecterCount& effecterCount,
307                                   uint8_t& stateIdPos)
308 {
309     PdrList pdrs{};
310 
311     auto& bus = open_power::occ::utils::getBus();
312     try
313     {
314         auto method = bus.new_method_call(
315             "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
316             "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
317         method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
318 
319         auto responseMsg = bus.call(method);
320         responseMsg.read(pdrs);
321     }
322     catch (const sdbusplus::exception_t& e)
323     {
324         log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
325                         entry("ERROR=%s", e.what()));
326     }
327 
328     if (!pdrs.size())
329     {
330         log<level::ERR>("pldm: state effecter PDRs not present");
331         return;
332     }
333 
334     bool offsetFound = false;
335     auto stateEffecterPDR =
336         reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
337     auto possibleStatesPtr = stateEffecterPDR->possible_states;
338     for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
339          offset++)
340     {
341         auto possibleStates =
342             reinterpret_cast<const state_effecter_possible_states*>(
343                 possibleStatesPtr);
344 
345         if (possibleStates->state_set_id == stateSetId)
346         {
347             stateIdPos = offset;
348             effecterCount = stateEffecterPDR->composite_effecter_count;
349             offsetFound = true;
350             break;
351         }
352         possibleStatesPtr += sizeof(possibleStates->state_set_id) +
353                              sizeof(possibleStates->possible_states_size) +
354                              possibleStates->possible_states_size;
355     }
356 
357     if (!offsetFound)
358     {
359         return;
360     }
361 
362     std::map<uint32_t, EffecterID> entityInstMap{};
363     for (auto& pdr : pdrs)
364     {
365         auto pdrPtr =
366             reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
367         uint32_t key = pdrPtr->effecter_id;
368         entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
369     }
370 
371     open_power::occ::instanceID position = start;
372     for (const auto& pair : entityInstMap)
373     {
374         instanceToEffecterMap.emplace(position, pair.second);
375         position++;
376     }
377 }
378 
379 std::vector<uint8_t>
380     Interface::prepareSetEffecterReq(EffecterID effecterId,
381                                      CompositeEffecterCount effecterCount,
382                                      uint8_t stateIdPos, uint8_t stateSetValue)
383 {
384     if (!getMctpInstanceId())
385     {
386         return std::vector<uint8_t>();
387     }
388 
389     std::vector<uint8_t> request(
390         sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
391         (effecterCount * sizeof(set_effecter_state_field)));
392     auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
393     std::vector<set_effecter_state_field> stateField;
394 
395     for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
396     {
397         if (effecterPos == stateIdPos)
398         {
399             stateField.emplace_back(
400                 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
401         }
402         else
403         {
404             stateField.emplace_back(
405                 set_effecter_state_field{PLDM_NO_CHANGE, 0});
406         }
407     }
408     auto rc = encode_set_state_effecter_states_req(
409         mctpInstance.value(), effecterId, effecterCount, stateField.data(),
410         requestMsg);
411     if (rc != PLDM_SUCCESS)
412     {
413         log<level::ERR>("encode set effecter states request returned error ",
414                         entry("RC=%d", rc));
415         request.clear();
416     }
417     return request;
418 }
419 
420 void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
421 {
422     if (open_power::occ::utils::isHostRunning())
423     {
424         if (!isPDREffecterCacheValid())
425         {
426             fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
427                               occInstanceToEffecter, OCCEffecterCount,
428                               bootRestartPosition);
429         }
430 
431         // Find the matching effecter for the OCC instance
432         auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
433         if (effecterEntry == occInstanceToEffecter.end())
434         {
435             log<level::ERR>(
436                 fmt::format(
437                     "pldm: Failed to find a matching effecter for OCC instance {}",
438                     occInstanceId)
439                     .c_str());
440 
441             return;
442         }
443 
444         // Prepare the SetStateEffecterStates request to reset the OCC
445         auto request = prepareSetEffecterReq(
446             effecterEntry->second, OCCEffecterCount, bootRestartPosition,
447             PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
448 
449         if (request.empty())
450         {
451             log<level::ERR>(
452                 "pldm: SetStateEffecterStates OCC reset request empty");
453             return;
454         }
455 
456         // Send request to reset the OCCs/PM Complex (ignore response)
457         sendPldm(request, occInstanceId, false);
458     }
459     else
460     {
461         log<level::ERR>(
462             fmt::format("resetOCC: HOST is not running (OCC{})", occInstanceId)
463                 .c_str());
464         clearData();
465     }
466 }
467 
468 void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
469 {
470     if (open_power::occ::utils::isHostRunning())
471     {
472         if (sbeInstanceToEffecter.empty())
473         {
474             fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
475                               sbeInstanceToEffecter, SBEEffecterCount,
476                               sbeMaintenanceStatePosition);
477         }
478 
479         auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
480         if (effecterEntry == sbeInstanceToEffecter.end())
481         {
482             log<level::ERR>(
483                 "pldm: Failed to find a matching effecter for SBE instance",
484                 entry("SBE=%d", sbeInstanceId));
485             return;
486         }
487 
488         // Prepare the SetStateEffecterStates request to HRESET the SBE
489         auto request = prepareSetEffecterReq(
490             effecterEntry->second, SBEEffecterCount,
491             sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
492 
493         if (request.empty())
494         {
495             log<level::ERR>(
496                 "pldm: SetStateEffecterStates HRESET request empty");
497             return;
498         }
499 
500         // Send request to issue HRESET of SBE (ignore response)
501         sendPldm(request, sbeInstanceId, false);
502         outstandingHResets.insert(sbeInstanceId);
503     }
504     else
505     {
506         log<level::ERR>(fmt::format("sendHRESET: HOST is not running (OCC{})",
507                                     sbeInstanceId)
508                             .c_str());
509         clearData();
510     }
511 }
512 
513 bool Interface::getMctpInstanceId()
514 {
515     if (!mctpInstance)
516     {
517         // Request new instance ID
518         auto& bus = open_power::occ::utils::getBus();
519         try
520         {
521             auto method = bus.new_method_call(
522                 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
523                 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
524             method.append(mctpEid);
525             auto reply = bus.call(method);
526             uint8_t newInstanceId;
527             reply.read(newInstanceId);
528             mctpInstance = newInstanceId;
529             log<level::INFO>(fmt::format("pldm: got new InstanceId: {}",
530                                          mctpInstance.value())
531                                  .c_str());
532         }
533         catch (const sdbusplus::exception_t& e)
534         {
535             log<level::ERR>(
536                 fmt::format("pldm: GetInstanceId failed: {}", e.what())
537                     .c_str());
538             return false;
539         }
540     }
541 
542     return true;
543 }
544 
545 void Interface::sendPldm(const std::vector<uint8_t>& request,
546                          const uint8_t instance, const bool rspExpected)
547 {
548     if (!mctpInstance)
549     {
550         log<level::ERR>("sendPldm: No MCTP Instance ID found!");
551         return;
552     }
553 
554     // Connect to MCTP socket
555     pldmFd = pldm_open();
556     auto openErrno = errno;
557     if (pldmFd == PLDM_REQUESTER_OPEN_FAIL)
558     {
559         log<level::ERR>(
560             fmt::format(
561                 "sendPldm: Failed to connect to MCTP socket, errno={}/{}",
562                 openErrno, strerror(openErrno))
563                 .c_str());
564         return;
565     }
566 
567     // Send the PLDM request message to HBRT
568     if (rspExpected)
569     {
570         // Register callback when response is available
571         registerPldmRspCallback();
572 
573         // Send PLDM request
574         log<level::INFO>(
575             fmt::format(
576                 "sendPldm: calling pldm_send(OCC{}, instance:{}, {} bytes)",
577                 instance, mctpInstance.value(), request.size())
578                 .c_str());
579         pldmResponseReceived = false;
580         pldmResponseTimeout = false;
581         pldmResponseOcc = instance;
582         auto pldmRc = pldm_send(mctpEid, pldmFd, request.data(),
583                                 request.size());
584         auto sendErrno = errno;
585         if (pldmRc != PLDM_REQUESTER_SUCCESS)
586         {
587             log<level::ERR>(
588                 fmt::format(
589                     "sendPldm: pldm_send failed with rc={} and errno={}/{}",
590                     static_cast<
591                         std::underlying_type_t<pldm_requester_error_codes>>(
592                         pldmRc),
593                     sendErrno, strerror(sendErrno))
594                     .c_str());
595             pldmClose();
596             return;
597         }
598 
599         // start timer waiting for the response
600         using namespace std::literals::chrono_literals;
601         pldmRspTimer.restartOnce(8s);
602 
603         // Wait for response/timeout
604     }
605     else // not expecting the response
606     {
607         log<level::INFO>(
608             fmt::format(
609                 "sendPldm: calling pldm_send(mctpID:{}, fd:{}, {} bytes) for OCC{}",
610                 mctpEid, pldmFd, request.size(), instance)
611                 .c_str());
612         auto rc = pldm_send(mctpEid, pldmFd, request.data(), request.size());
613         auto sendErrno = errno;
614         if (rc)
615         {
616             log<level::ERR>(
617                 fmt::format(
618                     "sendPldm: pldm_send(mctpID:{}, fd:{}, {} bytes) failed with rc={} and errno={}/{}",
619                     mctpEid, pldmFd, request.size(),
620                     static_cast<
621                         std::underlying_type_t<pldm_requester_error_codes>>(rc),
622                     sendErrno, strerror(sendErrno))
623                     .c_str());
624         }
625         else
626         {
627             // Not waiting for response, instance ID should be freed
628             mctpInstance = std::nullopt;
629         }
630         pldmClose();
631     }
632 }
633 
634 // Attaches the FD to event loop and registers the callback handler
635 void Interface::registerPldmRspCallback()
636 {
637     decltype(eventSource.get()) sourcePtr = nullptr;
638     auto rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN,
639                               pldmRspCallback, this);
640     if (rc < 0)
641     {
642         log<level::ERR>(
643             fmt::format(
644                 "registerPldmRspCallback: sd_event_add_io: Error({})={} : fd={}",
645                 rc, strerror(-rc), pldmFd)
646                 .c_str());
647     }
648     else
649     {
650         // puts sourcePtr in the event source.
651         eventSource.reset(sourcePtr);
652     }
653 }
654 
655 // Add a timer to the event loop, default 30s.
656 void Interface::pldmRspExpired()
657 {
658     if (!pldmResponseReceived)
659     {
660         log<level::WARNING>(
661             fmt::format(
662                 "pldmRspExpired: timerCallback - timeout waiting for pldm response for OCC{}",
663                 pldmResponseOcc)
664                 .c_str());
665         pldmResponseTimeout = true;
666         if (pldmFd)
667         {
668             pldmClose();
669         }
670     }
671     return;
672 };
673 
674 void Interface::pldmClose()
675 {
676     if (pldmRspTimer.isEnabled())
677     {
678         // stop PLDM response timer
679         pldmRspTimer.setEnabled(false);
680     }
681     pldm_close();
682     pldmFd = -1;
683     eventSource.reset();
684 }
685 
686 int Interface::pldmRspCallback(sd_event_source* /*es*/, int fd,
687                                uint32_t revents, void* userData)
688 {
689     if (!(revents & EPOLLIN))
690     {
691         log<level::INFO>(
692             fmt::format("pldmRspCallback - revents={:08X}", revents).c_str());
693         return -1;
694     }
695 
696     auto pldmIface = static_cast<Interface*>(userData);
697 
698     if (!pldmIface->mctpInstance)
699     {
700         log<level::ERR>(
701             "pldmRspCallback: No outstanding MCTP Instance ID found");
702         return -1;
703     }
704 
705     uint8_t* responseMsg = nullptr;
706     size_t responseMsgSize{};
707 
708     log<level::INFO>(
709         fmt::format("pldmRspCallback: calling pldm_recv() instance:{}",
710                     pldmIface->mctpInstance.value())
711             .c_str());
712     auto rc = pldm_recv(mctpEid, fd, pldmIface->mctpInstance.value(),
713                         &responseMsg, &responseMsgSize);
714     int lastErrno = errno;
715     if (rc)
716     {
717         log<level::ERR>(
718             fmt::format(
719                 "pldmRspCallback: pldm_recv failed with rc={}, errno={}/{}",
720                 static_cast<std::underlying_type_t<pldm_requester_error_codes>>(
721                     rc),
722                 lastErrno, strerror(lastErrno))
723                 .c_str());
724         return -1;
725     }
726 
727     // We got the response for the PLDM request msg that was sent
728     log<level::INFO>(
729         fmt::format("pldmRspCallback: pldm_recv() rsp was {} bytes",
730                     responseMsgSize)
731             .c_str());
732 
733     if (pldmIface->pldmRspTimer.isEnabled())
734     {
735         // stop PLDM response timer
736         pldmIface->pldmRspTimer.setEnabled(false);
737     }
738 
739     // instance ID should be freed
740     pldmIface->mctpInstance = std::nullopt;
741 
742     // Set pointer to autodelete
743     std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
744                                                                   std::free};
745 
746     auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
747     if (response->payload[0] != PLDM_SUCCESS)
748     {
749         log<level::ERR>(
750             fmt::format("pldmRspCallback: payload[0] was not success: {}",
751                         response->payload[0])
752                 .c_str());
753         pldmIface->pldmClose();
754         return -1;
755     }
756 
757     // Decode the response
758     uint8_t compCode = 0, sensorCount = 1;
759     get_sensor_state_field field[6];
760     responseMsgSize -= sizeof(pldm_msg_hdr);
761     auto msgRc = decode_get_state_sensor_readings_resp(
762         response, responseMsgSize, &compCode, &sensorCount, field);
763     if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS))
764     {
765         log<level::ERR>(
766             fmt::format(
767                 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={} and compCode={}",
768                 msgRc, compCode)
769                 .c_str());
770         pldmIface->pldmClose();
771         return -1;
772     }
773 
774     pldmIface->pldmClose();
775 
776     const uint8_t instance = pldmIface->pldmResponseOcc;
777     const uint8_t occSensorState = field[0].present_state;
778     pldmIface->pldmResponseReceived = true;
779 
780     if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)
781     {
782         log<level::INFO>(
783             fmt::format("pldmRspCallback: OCC{} is RUNNING", instance).c_str());
784         pldmIface->callBack(instance, true);
785     }
786     else if (occSensorState ==
787              PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT)
788     {
789         log<level::INFO>(
790             fmt::format(
791                 "pldmRspCallback: OCC{} has now STOPPED and system is in SAFE MODE",
792                 instance)
793                 .c_str());
794 
795         // Setting safe mode true
796         pldmIface->safeModeCallBack(true);
797 
798         pldmIface->callBack(instance, false);
799     }
800     else
801     {
802         log<level::INFO>(
803             fmt::format(
804                 "pldmRspCallback: OCC{} is not running (sensor state:{})",
805                 instance, occSensorState)
806                 .c_str());
807         if (occSensorState != PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED)
808         {
809             const size_t rspLength = responseMsgSize + sizeof(pldm_msg_hdr);
810             std::vector<std::uint8_t> pldmResponse(rspLength);
811             memcpy(&pldmResponse[0], reinterpret_cast<std::uint8_t*>(response),
812                    rspLength);
813             log<level::ERR>(
814                 fmt::format(
815                     "pldmRspCallback: Bad State - PLDM response ({} bytes) for OCC{}:",
816                     rspLength, instance)
817                     .c_str());
818             dump_hex(pldmResponse);
819         }
820         pldmIface->callBack(instance, false);
821     }
822 
823     return 0;
824 };
825 
826 std::vector<uint8_t> Interface::encodeGetStateSensorRequest(uint8_t instance,
827                                                             uint16_t sensorId)
828 {
829     if (!getMctpInstanceId())
830     {
831         log<level::ERR>(
832             "encodeGetStateSensorRequest: failed to getMctpInstanceId");
833         return std::vector<uint8_t>();
834     }
835 
836     bitfield8_t sRearm = {0};
837     const size_t msgSize = sizeof(pldm_msg_hdr) +
838                            PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES;
839     std::vector<uint8_t> request(msgSize);
840 
841     auto msg = reinterpret_cast<pldm_msg*>(request.data());
842     auto msgRc = encode_get_state_sensor_readings_req(mctpInstance.value(),
843                                                       sensorId, sRearm, 0, msg);
844     if (msgRc != PLDM_SUCCESS)
845     {
846         log<level::ERR>(
847             fmt::format(
848                 "encodeGetStateSensorRequest: Failed to encode sensorId:0x{:08X} for OCC{} (rc={})",
849                 sensorId, instance, msgRc)
850                 .c_str());
851     }
852     return request;
853 }
854 
855 // Initiate query of the specified OCC Active Sensor
856 void Interface::checkActiveSensor(uint8_t instance)
857 {
858     static bool tracedOnce = false;
859     if (pldmFd > 0)
860     {
861         if (!tracedOnce)
862         {
863             log<level::ERR>(
864                 fmt::format(
865                     "checkActiveSensor: already waiting on OCC{} (fd={})",
866                     pldmResponseOcc, pldmFd)
867                     .c_str());
868             tracedOnce = true;
869         }
870         return;
871     }
872     tracedOnce = false;
873 
874     if (!isOCCSensorCacheValid())
875     {
876         fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
877                         sensorToOCCInstance, OCCSensorOffset);
878     }
879 
880     // look up sensor id (key) based on instance
881     auto entry = std::find_if(
882         sensorToOCCInstance.begin(), sensorToOCCInstance.end(),
883         [instance](const auto& entry) { return instance == entry.second; });
884     if (entry != sensorToOCCInstance.end())
885     {
886         // Query the OCC Active Sensor state for this instance
887         // SensorID sID = entry->first;
888         log<level::INFO>(
889             fmt::format("checkActiveSensor: OCC{} / sensorID: 0x{:04X}",
890                         instance, entry->first)
891                 .c_str());
892 
893         // Encode GetStateSensorReadings PLDM message
894         auto request = encodeGetStateSensorRequest(instance, entry->first);
895         if (request.empty())
896         {
897             return;
898         }
899 
900         // Send request to PLDM and setup callback for response
901         sendPldm(request, instance, true);
902     }
903     else
904     {
905         log<level::ERR>(
906             fmt::format(
907                 "checkActiveSensor: Unable to find PLDM sensor for OCC{}",
908                 instance)
909                 .c_str());
910         log<level::INFO>(
911             "checkActiveSensor: fetching STATE_SET_OPERATIONAL_RUNNING_STATUS");
912         fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
913                         sensorToOCCInstance, OCCSensorOffset);
914     }
915 }
916 
917 } // namespace pldm
918