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