xref: /openbmc/pldm/platform-mc/event_manager.cpp (revision 378e3f7dda6886dff4ffe9f771af74eb8cf5f281)
1 #include "event_manager.hpp"
2 
3 #include "terminus_manager.hpp"
4 
5 #include <libpldm/platform.h>
6 #include <libpldm/utils.h>
7 
8 #include <phosphor-logging/lg2.hpp>
9 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
10 
11 #include <cerrno>
12 #include <memory>
13 
14 PHOSPHOR_LOG2_USING;
15 
16 namespace pldm
17 {
18 namespace platform_mc
19 {
20 namespace fs = std::filesystem;
21 
handlePlatformEvent(pldm_tid_t tid,uint16_t eventId,uint8_t eventClass,const uint8_t * eventData,size_t eventDataSize)22 int EventManager::handlePlatformEvent(
23     pldm_tid_t tid, uint16_t eventId, uint8_t eventClass,
24     const uint8_t* eventData, size_t eventDataSize)
25 {
26     /* Only handle the event of the discovered termini*/
27     if (!termini.contains(tid))
28     {
29         lg2::error("Terminus ID {TID} is not in the managing list.", "TID",
30                    tid);
31         return PLDM_ERROR;
32     }
33 
34     /* EventClass sensorEvent `Table 11 - PLDM Event Types` DSP0248 */
35     if (eventClass == PLDM_SENSOR_EVENT)
36     {
37         uint16_t sensorId = 0;
38         uint8_t sensorEventClassType = 0;
39         size_t eventClassDataOffset = 0;
40         auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId,
41                                            &sensorEventClassType,
42                                            &eventClassDataOffset);
43         if (rc)
44         {
45             lg2::error(
46                 "Failed to decode sensor event data from terminus ID {TID}, event class {CLASS}, event ID {EVENTID} with return code {RC}.",
47                 "TID", tid, "CLASS", eventClass, "EVENTID", eventId, "RC", rc);
48             return rc;
49         }
50         switch (sensorEventClassType)
51         {
52             case PLDM_NUMERIC_SENSOR_STATE:
53             {
54                 const uint8_t* sensorData = eventData + eventClassDataOffset;
55                 size_t sensorDataLength = eventDataSize - eventClassDataOffset;
56                 return processNumericSensorEvent(tid, sensorId, sensorData,
57                                                  sensorDataLength);
58             }
59             case PLDM_STATE_SENSOR_STATE:
60             case PLDM_SENSOR_OP_STATE:
61             default:
62                 lg2::info(
63                     "Unsupported class type {CLASSTYPE} for the sensor event from terminus ID {TID} sensorId {SID}",
64                     "CLASSTYPE", sensorEventClassType, "TID", tid, "SID",
65                     sensorId);
66                 return PLDM_ERROR;
67         }
68     }
69 
70     /* EventClass CPEREvent as `Table 11 - PLDM Event Types` DSP0248 V1.3.0 */
71     if (eventClass == PLDM_CPER_EVENT)
72     {
73         return processCperEvent(tid, eventId, eventData, eventDataSize);
74     }
75 
76     /* EventClass pldmMessagePollEvent `Table 11 - PLDM Event Types` DSP0248 */
77     if (eventClass == PLDM_MESSAGE_POLL_EVENT)
78     {
79         lg2::info("Received pldmMessagePollEvent for terminus {TID}", "TID",
80                   tid);
81         pldm_message_poll_event poll_event{};
82         auto rc = decode_pldm_message_poll_event_data(eventData, eventDataSize,
83                                                       &poll_event);
84         if (rc)
85         {
86             lg2::error(
87                 "Failed to decode PldmMessagePollEvent event, error {RC} ",
88                 "RC", rc);
89             return rc;
90         }
91 
92         auto it = termini.find(tid);
93         if (it != termini.end())
94         {
95             auto& terminus = it->second; // Reference for clarity
96             terminus->pollEvent = true;
97             terminus->pollEventId = poll_event.event_id;
98             terminus->pollDataTransferHandle = poll_event.data_transfer_handle;
99         }
100 
101         return PLDM_SUCCESS;
102     }
103 
104     lg2::info("Unsupported class type {CLASSTYPE}", "CLASSTYPE", eventClass);
105 
106     return PLDM_ERROR;
107 }
108 
triggerNumericSensorThresholdEvent(NumericSensorThresholdHandler handler,uint8_t previousEventState,uint8_t nextEventState,double value)109 int triggerNumericSensorThresholdEvent(NumericSensorThresholdHandler handler,
110                                        uint8_t previousEventState,
111                                        uint8_t nextEventState, double value)
112 {
113     static const std::map<
114         uint8_t, std::tuple<pldm::utils::Level, pldm::utils::Direction>>
115         sensorEventMap = {
116             {PLDM_SENSOR_UPPERFATAL,
117              {pldm::utils::Level::HARDSHUTDOWN, pldm::utils::Direction::HIGH}},
118             {PLDM_SENSOR_UPPERCRITICAL,
119              {pldm::utils::Level::CRITICAL, pldm::utils::Direction::HIGH}},
120             {PLDM_SENSOR_UPPERWARNING,
121              {pldm::utils::Level::WARNING, pldm::utils::Direction::HIGH}},
122             {PLDM_SENSOR_LOWERWARNING,
123              {pldm::utils::Level::WARNING, pldm::utils::Direction::LOW}},
124             {PLDM_SENSOR_LOWERCRITICAL,
125              {pldm::utils::Level::CRITICAL, pldm::utils::Direction::LOW}},
126             {PLDM_SENSOR_LOWERFATAL,
127              {pldm::utils::Level::HARDSHUTDOWN, pldm::utils::Direction::LOW}},
128         };
129     static const std::array<uint8_t, 7> stateOrder = {
130         PLDM_SENSOR_LOWERFATAL,   PLDM_SENSOR_LOWERCRITICAL,
131         PLDM_SENSOR_LOWERWARNING, PLDM_SENSOR_NORMAL,
132         PLDM_SENSOR_UPPERWARNING, PLDM_SENSOR_UPPERCRITICAL,
133         PLDM_SENSOR_UPPERFATAL};
134     constexpr auto normalIt = stateOrder.begin() + 3;
135     const auto normalState = *normalIt;
136     auto prevIt =
137         std::find(stateOrder.begin(), stateOrder.end(), previousEventState);
138     if (prevIt == stateOrder.end())
139     {
140         lg2::error("Undefined previous threshold event state: {EVENT}", "EVENT",
141                    previousEventState);
142         return PLDM_ERROR;
143     }
144     auto nextIt =
145         std::find(stateOrder.begin(), stateOrder.end(), nextEventState);
146     if (nextIt == stateOrder.end())
147     {
148         lg2::error("Undefined current threshold event state: {EVENT}", "EVENT",
149                    nextEventState);
150         return PLDM_ERROR;
151     }
152     if (prevIt == nextIt)
153     {
154         // Nothing to do. Return success early
155         return PLDM_SUCCESS;
156     }
157 
158     // This is a rare condition. But if we are going wildy across the thresholds
159     // crossing PLDM_SENSOR_NORMAL (Example going from PLDM_SENSOR_LOWERFATAL to
160     // PLDM_SENSOR_UPPERFATAL in one event, then split it up into two)
161     if ((prevIt < normalIt && nextIt > normalIt) ||
162         (prevIt > normalIt && nextIt < normalIt))
163     {
164         int rc = triggerNumericSensorThresholdEvent(handler, *prevIt,
165                                                     normalState, value);
166         if (rc != PLDM_SUCCESS)
167         {
168             lg2::error("Error handling {PREV} to current for numeric sensor",
169                        "PREV", int(*prevIt));
170             return rc;
171         }
172         return triggerNumericSensorThresholdEvent(handler, normalState, *nextIt,
173                                                   value);
174     }
175     bool goingUp = prevIt < nextIt;
176     bool gettingBetter = (prevIt < nextIt && prevIt < normalIt) ||
177                          (prevIt > nextIt && prevIt > normalIt);
178 
179     for (auto currIt = prevIt; currIt != nextIt; goingUp ? ++currIt : --currIt)
180     {
181         if (currIt == normalIt)
182         {
183             continue;
184         }
185         const auto& event = sensorEventMap.at(*currIt);
186 
187         if (gettingBetter)
188         {
189             if (currIt != prevIt)
190             {
191                 // Just trigger an event in case it was missed before
192                 // we deassert. The implementation of triggerThresholdEvent
193                 // should just no-op if it is already triggered.
194                 handler(std::get<0>(event), std::get<1>(event), value, true,
195                         true);
196             }
197             handler(std::get<0>(event), std::get<1>(event), value, false,
198                     false);
199         }
200         else
201         {
202             handler(std::get<0>(event), std::get<1>(event), value, true, true);
203         }
204     }
205     if (nextIt != normalIt)
206     {
207         const auto& event = sensorEventMap.at(*nextIt);
208         return handler(std::get<0>(event), std::get<1>(event), value, true,
209                        true);
210     }
211     return PLDM_SUCCESS;
212 }
213 
processNumericSensorEvent(pldm_tid_t tid,uint16_t sensorId,const uint8_t * sensorData,size_t sensorDataLength)214 int EventManager::processNumericSensorEvent(pldm_tid_t tid, uint16_t sensorId,
215                                             const uint8_t* sensorData,
216                                             size_t sensorDataLength)
217 {
218     uint8_t eventState = 0;
219     uint8_t previousEventState = 0;
220     uint8_t sensorDataSize = 0;
221     uint32_t presentReading;
222     auto rc = decode_numeric_sensor_data(
223         sensorData, sensorDataLength, &eventState, &previousEventState,
224         &sensorDataSize, &presentReading);
225     if (rc)
226     {
227         lg2::error(
228             "Failed to decode numericSensorState event for terminus ID {TID}, error {RC} ",
229             "TID", tid, "RC", rc);
230         return rc;
231     }
232 
233     double value = static_cast<double>(presentReading);
234     lg2::error(
235         "processNumericSensorEvent tid {TID}, sensorID {SID} value {VAL} previousState {PSTATE} eventState {ESTATE}",
236         "TID", tid, "SID", sensorId, "VAL", value, "PSTATE", previousEventState,
237         "ESTATE", eventState);
238 
239     if (!termini.contains(tid) || !termini[tid])
240     {
241         lg2::error("Terminus ID {TID} is not in the managing list.", "TID",
242                    tid);
243         return PLDM_ERROR;
244     }
245 
246     auto& terminus = termini[tid];
247 
248     auto sensor = terminus->getSensorObject(sensorId);
249     if (!sensor)
250     {
251         lg2::error(
252             "Terminus ID {TID} has no sensor object with sensor ID {SID}.",
253             "TID", tid, "SID", sensorId);
254         return PLDM_ERROR;
255     }
256     auto sensorHandler =
257         [&sensor](pldm::utils::Level level, pldm::utils::Direction direction,
258                   double rawValue, bool newAlarm, bool assert) {
259             return sensor->triggerThresholdEvent(level, direction, rawValue,
260                                                  newAlarm, assert);
261         };
262     rc = triggerNumericSensorThresholdEvent(sensorHandler, previousEventState,
263                                             eventState, value);
264     if (rc)
265     {
266         lg2::error(
267             "Terminus ID {TID} sensor {SID} threshold handling had errors",
268             "TID", tid, "SID", sensorId);
269         return rc;
270     }
271     return PLDM_SUCCESS;
272 }
273 
processCperEvent(pldm_tid_t tid,uint16_t eventId,const uint8_t * eventData,const size_t eventDataSize)274 int EventManager::processCperEvent(pldm_tid_t tid, uint16_t eventId,
275                                    const uint8_t* eventData,
276                                    const size_t eventDataSize)
277 {
278     if (eventDataSize < PLDM_PLATFORM_CPER_EVENT_MIN_LENGTH)
279     {
280         lg2::error(
281             "Error : Invalid CPER Event data length for eventId {EVENTID}.",
282             "EVENTID", eventId);
283         return PLDM_ERROR;
284     }
285     const size_t cperEventDataSize =
286         eventDataSize - PLDM_PLATFORM_CPER_EVENT_MIN_LENGTH;
287     const size_t msgDataLen =
288         sizeof(pldm_platform_cper_event) + cperEventDataSize;
289     std::string terminusName = "";
290     auto msgData = std::make_unique<unsigned char[]>(msgDataLen);
291     auto cperEvent = new (msgData.get()) pldm_platform_cper_event;
292 
293     auto rc = decode_pldm_platform_cper_event(eventData, eventDataSize,
294                                               cperEvent, msgDataLen);
295 
296     if (rc)
297     {
298         lg2::error(
299             "Failed to decode CPER event for eventId {EVENTID} of terminus ID {TID} error {RC}.",
300             "EVENTID", eventId, "TID", tid, "RC", rc);
301         return rc;
302     }
303 
304     if (termini.contains(tid) && termini[tid])
305     {
306         auto tmp = termini[tid]->getTerminusName();
307         if (tmp && !tmp.value().empty())
308         {
309             terminusName = static_cast<std::string>(tmp.value());
310         }
311     }
312     else
313     {
314         lg2::error("Terminus ID {TID} is not in the managing list.", "TID",
315                    tid);
316         return PLDM_ERROR;
317     }
318 
319     // Save event data to file
320     std::filesystem::path dirName{"/var/cper"};
321     if (!std::filesystem::exists(dirName))
322     {
323         try
324         {
325             std::filesystem::create_directory(dirName);
326         }
327         catch (const std::filesystem::filesystem_error& e)
328         {
329             lg2::error("Failed to create /var/cper directory: {ERROR}", "ERROR",
330                        e);
331             return PLDM_ERROR;
332         }
333     }
334 
335     std::string fileName{dirName.string() + "/cper-XXXXXX"};
336     auto fd = mkstemp(fileName.data());
337     if (fd < 0)
338     {
339         lg2::error("Failed to generate temp file, error {ERRORNO}", "ERRORNO",
340                    std::strerror(errno));
341         return PLDM_ERROR;
342     }
343     close(fd);
344 
345     std::ofstream ofs;
346     ofs.exceptions(std::ofstream::failbit | std::ofstream::badbit |
347                    std::ofstream::eofbit);
348 
349     try
350     {
351         ofs.open(fileName);
352         ofs.write(reinterpret_cast<const char*>(
353                       pldm_platform_cper_event_event_data(cperEvent)),
354                   cperEvent->event_data_length);
355         if (cperEvent->format_type == PLDM_PLATFORM_CPER_EVENT_WITH_HEADER)
356         {
357             rc = createCperDumpEntry("CPER", fileName, terminusName);
358         }
359         else
360         {
361             rc = createCperDumpEntry("CPERSection", fileName, terminusName);
362         }
363         ofs.close();
364     }
365     catch (const std::ofstream::failure& e)
366     {
367         lg2::error("Failed to save CPER to '{FILENAME}', error - {ERROR}.",
368                    "FILENAME", fileName, "ERROR", e);
369         return PLDM_ERROR;
370     }
371     return rc;
372 }
373 
createCperDumpEntry(const std::string & dataType,const std::string & dataPath,const std::string & typeName)374 int EventManager::createCperDumpEntry(const std::string& dataType,
375                                       const std::string& dataPath,
376                                       const std::string& typeName)
377 {
378     auto createDump =
379         [](std::map<std::string, std::variant<std::string, uint64_t>>&
380                addData) {
381             static constexpr auto dumpObjPath =
382                 "/xyz/openbmc_project/dump/faultlog";
383             static constexpr auto dumpInterface =
384                 "xyz.openbmc_project.Dump.Create";
385             auto& bus = pldm::utils::DBusHandler::getBus();
386 
387             try
388             {
389                 auto service = pldm::utils::DBusHandler().getService(
390                     dumpObjPath, dumpInterface);
391                 auto method = bus.new_method_call(service.c_str(), dumpObjPath,
392                                                   dumpInterface, "CreateDump");
393                 method.append(addData);
394                 bus.call_noreply(method);
395             }
396             catch (const std::exception& e)
397             {
398                 lg2::error(
399                     "Failed to create D-Bus Dump entry, error - {ERROR}.",
400                     "ERROR", e);
401             }
402         };
403 
404     std::map<std::string, std::variant<std::string, uint64_t>> addData;
405     addData["Type"] = dataType;
406     addData["PrimaryLogId"] = dataPath;
407     addData["AdditionalTypeName"] = typeName;
408     createDump(addData);
409     return PLDM_SUCCESS;
410 }
411 
getNextPartParameters(uint16_t eventId,std::vector<uint8_t> eventMessage,uint8_t transferFlag,uint32_t eventDataIntegrityChecksum,uint32_t nextDataTransferHandle,uint8_t * transferOperationFlag,uint32_t * dataTransferHandle,uint32_t * eventIdToAcknowledge)412 int EventManager::getNextPartParameters(
413     uint16_t eventId, std::vector<uint8_t> eventMessage, uint8_t transferFlag,
414     uint32_t eventDataIntegrityChecksum, uint32_t nextDataTransferHandle,
415     uint8_t* transferOperationFlag, uint32_t* dataTransferHandle,
416     uint32_t* eventIdToAcknowledge)
417 {
418     if (transferFlag != PLDM_PLATFORM_TRANSFER_START_AND_END &&
419         transferFlag != PLDM_PLATFORM_TRANSFER_END)
420     {
421         *transferOperationFlag = PLDM_GET_NEXTPART;
422         *dataTransferHandle = nextDataTransferHandle;
423         *eventIdToAcknowledge = PLDM_PLATFORM_EVENT_ID_FRAGMENT;
424         return PLDM_SUCCESS;
425     }
426 
427     if (transferFlag == PLDM_PLATFORM_TRANSFER_END)
428     {
429         if (eventDataIntegrityChecksum !=
430             pldm_edac_crc32(eventMessage.data(), eventMessage.size()))
431         {
432             lg2::error("pollForPlatformEventMessage invalid checksum.");
433             return PLDM_ERROR_INVALID_DATA;
434         }
435     }
436 
437     /* End of one event. Set request transfer flag to ACK */
438     *transferOperationFlag = PLDM_ACKNOWLEDGEMENT_ONLY;
439     *dataTransferHandle = 0;
440     *eventIdToAcknowledge = eventId;
441 
442     return PLDM_SUCCESS;
443 }
444 
callPolledEventHandlers(pldm_tid_t tid,uint8_t eventClass,uint16_t eventId,std::vector<uint8_t> & eventMessage)445 void EventManager::callPolledEventHandlers(pldm_tid_t tid, uint8_t eventClass,
446                                            uint16_t eventId,
447                                            std::vector<uint8_t>& eventMessage)
448 {
449     try
450     {
451         const auto& handlers = eventHandlers.at(eventClass);
452         for (const auto& handler : handlers)
453         {
454             auto rc =
455                 handler(tid, eventId, eventMessage.data(), eventMessage.size());
456             if (rc != PLDM_SUCCESS)
457             {
458                 lg2::error(
459                     "Failed to handle platform event msg for terminus {TID}, event {EVENTID} return {RET}",
460                     "TID", tid, "EVENTID", eventId, "RET", rc);
461             }
462         }
463     }
464     catch (const std::out_of_range& e)
465     {
466         lg2::error(
467             "Failed to handle platform event msg for terminus {TID}, event {EVENTID} error - {ERROR}",
468             "TID", tid, "EVENTID", eventId, "ERROR", e);
469     }
470 }
471 
pollForPlatformEventTask(pldm_tid_t tid,uint32_t pollDataTransferHandle)472 exec::task<int> EventManager::pollForPlatformEventTask(
473     pldm_tid_t tid, uint32_t pollDataTransferHandle)
474 {
475     uint8_t rc = 0;
476     // Set once, doesn't need resetting
477     uint8_t transferOperationFlag = PLDM_GET_FIRSTPART;
478     uint32_t dataTransferHandle = pollDataTransferHandle;
479     uint32_t eventIdToAcknowledge = PLDM_PLATFORM_EVENT_ID_NULL;
480     uint8_t formatVersion = 0x1; // Constant, no need to reset
481     uint16_t eventId = PLDM_PLATFORM_EVENT_ID_ACK;
482     uint16_t polledEventId = PLDM_PLATFORM_EVENT_ID_NONE;
483     pldm_tid_t polledEventTid = 0;
484     uint8_t polledEventClass = 0;
485 
486     std::vector<uint8_t> eventMessage{};
487 
488     // Reset and mark terminus as available
489     updateAvailableState(tid, true);
490 
491     while (eventId != PLDM_PLATFORM_EVENT_ID_NONE)
492     {
493         uint8_t completionCode = 0;
494         pldm_tid_t eventTid = PLDM_PLATFORM_EVENT_ID_NONE;
495         eventId = PLDM_PLATFORM_EVENT_ID_NONE;
496         uint32_t nextDataTransferHandle = 0;
497         uint8_t transferFlag = 0;
498         uint8_t eventClass = 0;
499         uint32_t eventDataSize = 0;
500         uint8_t* eventData = nullptr;
501         uint32_t eventDataIntegrityChecksum = 0;
502 
503         /* Stop event polling */
504         if (!getAvailableState(tid))
505         {
506             lg2::info(
507                 "Terminus ID {TID} is not available for PLDM request from {NOW}.",
508                 "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
509             co_await stdexec::just_stopped();
510         }
511 
512         rc = co_await pollForPlatformEventMessage(
513             tid, formatVersion, transferOperationFlag, dataTransferHandle,
514             eventIdToAcknowledge, completionCode, eventTid, eventId,
515             nextDataTransferHandle, transferFlag, eventClass, eventDataSize,
516             eventData, eventDataIntegrityChecksum);
517         if (rc || completionCode != PLDM_SUCCESS)
518         {
519             lg2::error(
520                 "Failed to pollForPlatformEventMessage for terminus {TID}, event {EVENTID}, error {RC}, complete code {CC}",
521                 "TID", tid, "EVENTID", eventId, "RC", rc, "CC", completionCode);
522             co_return rc;
523         }
524 
525         if (eventDataSize > 0)
526         {
527             eventMessage.insert(eventMessage.end(), eventData,
528                                 eventData + eventDataSize);
529         }
530 
531         if (transferOperationFlag == PLDM_ACKNOWLEDGEMENT_ONLY)
532         {
533             /* Handle the polled event after finish ACK it */
534             if (eventHandlers.contains(polledEventClass))
535             {
536                 callPolledEventHandlers(polledEventTid, polledEventClass,
537                                         polledEventId, eventMessage);
538             }
539             eventMessage.clear();
540 
541             if (eventId == PLDM_PLATFORM_EVENT_ID_ACK)
542             {
543                 transferOperationFlag = PLDM_GET_FIRSTPART;
544                 dataTransferHandle = 0;
545                 eventIdToAcknowledge = PLDM_PLATFORM_EVENT_ID_NULL;
546             }
547         }
548         else
549         {
550             auto ret = getNextPartParameters(
551                 eventId, eventMessage, transferFlag, eventDataIntegrityChecksum,
552                 nextDataTransferHandle, &transferOperationFlag,
553                 &dataTransferHandle, &eventIdToAcknowledge);
554             if (ret)
555             {
556                 lg2::error(
557                     "Failed to process data of pollForPlatformEventMessage for terminus {TID}, event {EVENTID} return {RET}",
558                     "TID", tid, "EVENTID", eventId, "RET", ret);
559                 co_return PLDM_ERROR_INVALID_DATA;
560             }
561 
562             /* Store the polled event INFO to handle after ACK */
563             if ((transferFlag == PLDM_PLATFORM_TRANSFER_START_AND_END) ||
564                 (transferFlag == PLDM_PLATFORM_TRANSFER_END))
565             {
566                 polledEventTid = eventTid;
567                 polledEventId = eventId;
568                 polledEventClass = eventClass;
569             }
570         }
571     }
572 
573     co_return PLDM_SUCCESS;
574 }
575 
pollForPlatformEventMessage(pldm_tid_t tid,uint8_t formatVersion,uint8_t transferOperationFlag,uint32_t dataTransferHandle,uint16_t eventIdToAcknowledge,uint8_t & completionCode,uint8_t & eventTid,uint16_t & eventId,uint32_t & nextDataTransferHandle,uint8_t & transferFlag,uint8_t & eventClass,uint32_t & eventDataSize,uint8_t * & eventData,uint32_t & eventDataIntegrityChecksum)576 exec::task<int> EventManager::pollForPlatformEventMessage(
577     pldm_tid_t tid, uint8_t formatVersion, uint8_t transferOperationFlag,
578     uint32_t dataTransferHandle, uint16_t eventIdToAcknowledge,
579     uint8_t& completionCode, uint8_t& eventTid, uint16_t& eventId,
580     uint32_t& nextDataTransferHandle, uint8_t& transferFlag,
581     uint8_t& eventClass, uint32_t& eventDataSize, uint8_t*& eventData,
582     uint32_t& eventDataIntegrityChecksum)
583 {
584     Request request(
585         sizeof(pldm_msg_hdr) + PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES);
586     auto requestMsg = new (request.data()) pldm_msg;
587     auto rc = encode_poll_for_platform_event_message_req(
588         0, formatVersion, transferOperationFlag, dataTransferHandle,
589         eventIdToAcknowledge, requestMsg, request.size());
590     if (rc)
591     {
592         lg2::error(
593             "Failed to encode request PollForPlatformEventMessage for terminus ID {TID}, error {RC} ",
594             "TID", tid, "RC", rc);
595         co_return rc;
596     }
597 
598     /* Stop event polling */
599     if (!getAvailableState(tid))
600     {
601         lg2::info(
602             "Terminus ID {TID} is not available for PLDM request from {NOW}.",
603             "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
604         co_await stdexec::just_stopped();
605     }
606 
607     const pldm_msg* responseMsg = nullptr;
608     size_t responseLen = 0;
609     rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
610                                                   &responseLen);
611     if (rc)
612     {
613         lg2::error(
614             "Failed to send PollForPlatformEventMessage message for terminus {TID}, error {RC}",
615             "TID", tid, "RC", rc);
616         co_return rc;
617     }
618 
619     rc = decode_poll_for_platform_event_message_resp(
620         responseMsg, responseLen, &completionCode, &eventTid, &eventId,
621         &nextDataTransferHandle, &transferFlag, &eventClass, &eventDataSize,
622         (void**)&eventData, &eventDataIntegrityChecksum);
623     if (rc)
624     {
625         lg2::error(
626             "Failed to decode response PollForPlatformEventMessage for terminus ID {TID}, error {RC} ",
627             "TID", tid, "RC", rc);
628         co_return rc;
629     }
630     if (completionCode != PLDM_SUCCESS)
631     {
632         lg2::error(
633             "Error : PollForPlatformEventMessage for terminus ID {TID}, complete code {CC}.",
634             "TID", tid, "CC", completionCode);
635         co_return rc;
636     }
637 
638     co_return completionCode;
639 }
640 
641 } // namespace platform_mc
642 } // namespace pldm
643