xref: /openbmc/pldm/platform-mc/platform_manager.cpp (revision 36b36938a4eedcf87d3918acc10b07a28e7f1e9d)
1 #include "platform_manager.hpp"
2 
3 #include "manager.hpp"
4 #include "terminus_manager.hpp"
5 
6 #include <phosphor-logging/lg2.hpp>
7 
8 #include <ranges>
9 
10 PHOSPHOR_LOG2_USING;
11 
12 namespace pldm
13 {
14 namespace platform_mc
15 {
16 
initTerminus()17 exec::task<int> PlatformManager::initTerminus()
18 {
19     for (auto& [tid, terminus] : termini)
20     {
21         if (terminus->initialized)
22         {
23             continue;
24         }
25 
26         /* Get Fru */
27         uint16_t totalTableRecords = 0;
28         if (terminus->doesSupportCommand(PLDM_FRU,
29                                          PLDM_GET_FRU_RECORD_TABLE_METADATA))
30         {
31             auto rc =
32                 co_await getFRURecordTableMetadata(tid, &totalTableRecords);
33             if (rc)
34             {
35                 lg2::error(
36                     "Failed to get FRU Metadata for terminus {TID}, error {ERROR}",
37                     "TID", tid, "ERROR", rc);
38             }
39             if (!totalTableRecords)
40             {
41                 lg2::info("Fru record table meta data has 0 records");
42             }
43         }
44 
45         std::vector<uint8_t> fruData{};
46         if ((totalTableRecords != 0) &&
47             terminus->doesSupportCommand(PLDM_FRU, PLDM_GET_FRU_RECORD_TABLE))
48         {
49             auto rc =
50                 co_await getFRURecordTables(tid, totalTableRecords, fruData);
51             if (rc)
52             {
53                 lg2::error(
54                     "Failed to get Fru Record table for terminus {TID}, error {ERROR}",
55                     "TID", tid, "ERROR", rc);
56             }
57         }
58 
59         if (terminus->doesSupportCommand(PLDM_PLATFORM, PLDM_GET_PDR))
60         {
61             auto rc = co_await getPDRs(terminus);
62             if (rc)
63             {
64                 lg2::error(
65                     "Failed to fetch PDRs for terminus with TID: {TID}, error: {ERROR}",
66                     "TID", tid, "ERROR", rc);
67                 continue; // Continue to next terminus
68             }
69 
70             terminus->parseTerminusPDRs();
71         }
72 
73         /**
74          * Need terminus name from PDRs before updating Inventory object with
75          * Fru data
76          */
77         if (fruData.size())
78         {
79             updateInventoryWithFru(tid, fruData.data(), fruData.size());
80         }
81 
82         uint16_t terminusMaxBufferSize = terminus->maxBufferSize;
83         if (!terminus->doesSupportCommand(PLDM_PLATFORM,
84                                           PLDM_EVENT_MESSAGE_BUFFER_SIZE))
85         {
86             terminusMaxBufferSize = PLDM_PLATFORM_DEFAULT_MESSAGE_BUFFER_SIZE;
87         }
88         else
89         {
90             /* Get maxBufferSize use PLDM command eventMessageBufferSize */
91             auto rc = co_await eventMessageBufferSize(
92                 tid, terminus->maxBufferSize, terminusMaxBufferSize);
93             if (rc != PLDM_SUCCESS)
94             {
95                 lg2::error(
96                     "Failed to get message buffer size for terminus with TID: {TID}, error: {ERROR}",
97                     "TID", tid, "ERROR", rc);
98                 terminusMaxBufferSize =
99                     PLDM_PLATFORM_DEFAULT_MESSAGE_BUFFER_SIZE;
100             }
101         }
102         terminus->maxBufferSize =
103             std::min(terminus->maxBufferSize, terminusMaxBufferSize);
104 
105         auto rc = co_await configEventReceiver(tid);
106         if (rc)
107         {
108             lg2::error(
109                 "Failed to config event receiver for terminus with TID: {TID}, error: {ERROR}",
110                 "TID", tid, "ERROR", rc);
111         }
112         terminus->initialized = true;
113         if (manager)
114         {
115             manager->startSensorPolling(tid);
116         }
117         else
118         {
119             lg2::error(
120                 "Cannot start sensor polling for TID: {TID} because the manager is not initialized.",
121                 "TID", tid);
122         }
123     }
124 
125     co_return PLDM_SUCCESS;
126 }
127 
configEventReceiver(pldm_tid_t tid)128 exec::task<int> PlatformManager::configEventReceiver(pldm_tid_t tid)
129 {
130     if (!termini.contains(tid))
131     {
132         co_return PLDM_ERROR;
133     }
134 
135     auto& terminus = termini[tid];
136     if (!terminus->doesSupportCommand(PLDM_PLATFORM,
137                                       PLDM_EVENT_MESSAGE_SUPPORTED))
138     {
139         terminus->synchronyConfigurationSupported.byte =
140             1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE;
141     }
142     else
143     {
144         /**
145          *  Get synchronyConfigurationSupported use PLDM command
146          *  eventMessageBufferSize
147          */
148         uint8_t synchronyConfiguration = 0;
149         uint8_t numberEventClassReturned = 0;
150         std::vector<uint8_t> eventClass{};
151         auto rc = co_await eventMessageSupported(
152             tid, 1, synchronyConfiguration,
153             terminus->synchronyConfigurationSupported, numberEventClassReturned,
154             eventClass);
155         if (rc != PLDM_SUCCESS)
156         {
157             lg2::error(
158                 "Failed to get event message supported for terminus with TID: {TID}, error: {ERROR}",
159                 "TID", tid, "ERROR", rc);
160             terminus->synchronyConfigurationSupported.byte = 0;
161         }
162     }
163 
164     if (!terminus->doesSupportCommand(PLDM_PLATFORM, PLDM_SET_EVENT_RECEIVER))
165     {
166         lg2::error("Terminus {TID} does not support Event", "TID", tid);
167         co_return PLDM_ERROR;
168     }
169 
170     /**
171      *  Set Event receiver base on synchronyConfigurationSupported data
172      *  use PLDM command SetEventReceiver
173      */
174     pldm_event_message_global_enable eventMessageGlobalEnable =
175         PLDM_EVENT_MESSAGE_GLOBAL_DISABLE;
176     uint16_t heartbeatTimer = 0;
177 
178     /* Use PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE when
179      * for eventMessageGlobalEnable when the terminus supports that type
180      */
181     if (terminus->synchronyConfigurationSupported.byte &
182         (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE))
183     {
184         heartbeatTimer = HEARTBEAT_TIMEOUT;
185         eventMessageGlobalEnable =
186             PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE;
187     }
188     /* Use PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC when
189      * for eventMessageGlobalEnable when the terminus does not support
190      * PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE
191      * and supports PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC type
192      */
193     else if (terminus->synchronyConfigurationSupported.byte &
194              (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC))
195     {
196         eventMessageGlobalEnable = PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC;
197     }
198     /* Only use PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING
199      * for eventMessageGlobalEnable when the terminus only supports
200      * this type
201      */
202     else if (terminus->synchronyConfigurationSupported.byte &
203              (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING))
204     {
205         eventMessageGlobalEnable = PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING;
206     }
207 
208     if (eventMessageGlobalEnable != PLDM_EVENT_MESSAGE_GLOBAL_DISABLE)
209     {
210         auto rc = co_await setEventReceiver(tid, eventMessageGlobalEnable,
211                                             PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP,
212                                             heartbeatTimer);
213         if (rc != PLDM_SUCCESS)
214         {
215             lg2::error(
216                 "Failed to set event receiver for terminus with TID: {TID}, error: {ERROR}",
217                 "TID", tid, "ERROR", rc);
218         }
219     }
220 
221     co_return PLDM_SUCCESS;
222 }
223 
getPDRs(std::shared_ptr<Terminus> terminus)224 exec::task<int> PlatformManager::getPDRs(std::shared_ptr<Terminus> terminus)
225 {
226     pldm_tid_t tid = terminus->getTid();
227 
228     /* Setting default values when getPDRRepositoryInfo fails or does not
229      * support */
230     uint8_t repositoryState = PLDM_AVAILABLE;
231     uint32_t recordCount = std::numeric_limits<uint32_t>::max();
232     uint32_t repositorySize = 0;
233     uint32_t largestRecordSize = std::numeric_limits<uint32_t>::max();
234     if (terminus->doesSupportCommand(PLDM_PLATFORM,
235                                      PLDM_GET_PDR_REPOSITORY_INFO))
236     {
237         auto rc =
238             co_await getPDRRepositoryInfo(tid, repositoryState, recordCount,
239                                           repositorySize, largestRecordSize);
240         if (rc)
241         {
242             lg2::error(
243                 "Failed to get PDR Repository Info for terminus with TID: {TID}, error: {ERROR}",
244                 "TID", tid, "ERROR", rc);
245         }
246         else
247         {
248             recordCount =
249                 std::min(recordCount + 1, std::numeric_limits<uint32_t>::max());
250             largestRecordSize = std::min(largestRecordSize + 1,
251                                          std::numeric_limits<uint32_t>::max());
252         }
253     }
254 
255     if (repositoryState != PLDM_AVAILABLE)
256     {
257         co_return PLDM_ERROR_NOT_READY;
258     }
259 
260     uint32_t recordHndl = 0;
261     uint32_t nextRecordHndl = 0;
262     uint32_t nextDataTransferHndl = 0;
263     uint8_t transferFlag = 0;
264     uint16_t responseCnt = 0;
265     constexpr uint16_t recvBufSize = PLDM_PLATFORM_GETPDR_MAX_RECORD_BYTES;
266     std::vector<uint8_t> recvBuf(recvBufSize);
267     uint8_t transferCrc = 0;
268 
269     terminus->pdrs.clear();
270     uint32_t receivedRecordCount = 0;
271 
272     do
273     {
274         auto rc =
275             co_await getPDR(tid, recordHndl, 0, PLDM_GET_FIRSTPART, recvBufSize,
276                             0, nextRecordHndl, nextDataTransferHndl,
277                             transferFlag, responseCnt, recvBuf, transferCrc);
278 
279         if (rc)
280         {
281             lg2::error(
282                 "Failed to get PDRs for terminus {TID}, error: {RC}, first part of record handle {RECORD}",
283                 "TID", tid, "RC", rc, "RECORD", recordHndl);
284             terminus->pdrs.clear();
285             co_return rc;
286         }
287 
288         if (transferFlag == PLDM_PLATFORM_TRANSFER_START_AND_END)
289         {
290             // single-part
291             terminus->pdrs.emplace_back(std::vector<uint8_t>(
292                 recvBuf.begin(), recvBuf.begin() + responseCnt));
293             recordHndl = nextRecordHndl;
294         }
295         else
296         {
297             // multipart transfer
298             uint32_t receivedRecordSize = responseCnt;
299             auto pdrHdr = new (recvBuf.data()) pldm_pdr_hdr;
300             uint16_t recordChgNum = le16toh(pdrHdr->record_change_num);
301             std::vector<uint8_t> receivedPdr(recvBuf.begin(),
302                                              recvBuf.begin() + responseCnt);
303             do
304             {
305                 rc = co_await getPDR(
306                     tid, recordHndl, nextDataTransferHndl, PLDM_GET_NEXTPART,
307                     recvBufSize, recordChgNum, nextRecordHndl,
308                     nextDataTransferHndl, transferFlag, responseCnt, recvBuf,
309                     transferCrc);
310                 if (rc)
311                 {
312                     lg2::error(
313                         "Failed to get PDRs for terminus {TID}, error: {RC}, get middle part of record handle {RECORD}",
314                         "TID", tid, "RC", rc, "RECORD", recordHndl);
315                     terminus->pdrs.clear();
316                     co_return rc;
317                 }
318 
319                 receivedPdr.insert(receivedPdr.end(), recvBuf.begin(),
320                                    recvBuf.begin() + responseCnt);
321                 receivedRecordSize += responseCnt;
322 
323                 if (transferFlag == PLDM_PLATFORM_TRANSFER_END)
324                 {
325                     terminus->pdrs.emplace_back(std::move(receivedPdr));
326                     recordHndl = nextRecordHndl;
327                 }
328             } while (nextDataTransferHndl != 0 &&
329                      receivedRecordSize < largestRecordSize);
330         }
331         receivedRecordCount++;
332     } while (nextRecordHndl != 0 && receivedRecordCount < recordCount);
333 
334     co_return PLDM_SUCCESS;
335 }
336 
getPDR(const pldm_tid_t tid,const uint32_t recordHndl,const uint32_t dataTransferHndl,const uint8_t transferOpFlag,const uint16_t requestCnt,const uint16_t recordChgNum,uint32_t & nextRecordHndl,uint32_t & nextDataTransferHndl,uint8_t & transferFlag,uint16_t & responseCnt,std::vector<uint8_t> & recordData,uint8_t & transferCrc)337 exec::task<int> PlatformManager::getPDR(
338     const pldm_tid_t tid, const uint32_t recordHndl,
339     const uint32_t dataTransferHndl, const uint8_t transferOpFlag,
340     const uint16_t requestCnt, const uint16_t recordChgNum,
341     uint32_t& nextRecordHndl, uint32_t& nextDataTransferHndl,
342     uint8_t& transferFlag, uint16_t& responseCnt,
343     std::vector<uint8_t>& recordData, uint8_t& transferCrc)
344 {
345     Request request(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES);
346     auto requestMsg = new (request.data()) pldm_msg;
347     auto rc = encode_get_pdr_req(0, recordHndl, dataTransferHndl,
348                                  transferOpFlag, requestCnt, recordChgNum,
349                                  requestMsg, PLDM_GET_PDR_REQ_BYTES);
350     if (rc)
351     {
352         lg2::error(
353             "Failed to encode request GetPDR for terminus ID {TID}, error {RC} ",
354             "TID", tid, "RC", rc);
355         co_return rc;
356     }
357 
358     const pldm_msg* responseMsg = nullptr;
359     size_t responseLen = 0;
360     rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
361                                                   &responseLen);
362     if (rc)
363     {
364         lg2::error(
365             "Failed to send GetPDR message for terminus {TID}, error {RC}",
366             "TID", tid, "RC", rc);
367         co_return rc;
368     }
369 
370     uint8_t completionCode;
371     rc = decode_get_pdr_resp(responseMsg, responseLen, &completionCode,
372                              &nextRecordHndl, &nextDataTransferHndl,
373                              &transferFlag, &responseCnt, recordData.data(),
374                              recordData.size(), &transferCrc);
375     if (rc)
376     {
377         lg2::error(
378             "Failed to decode response GetPDR for terminus ID {TID}, error {RC} ",
379             "TID", tid, "RC", rc);
380         co_return rc;
381     }
382 
383     if (completionCode != PLDM_SUCCESS)
384     {
385         lg2::error("Error : GetPDR for terminus ID {TID}, complete code {CC}.",
386                    "TID", tid, "CC", completionCode);
387         co_return rc;
388     }
389 
390     co_return completionCode;
391 }
392 
getPDRRepositoryInfo(const pldm_tid_t tid,uint8_t & repositoryState,uint32_t & recordCount,uint32_t & repositorySize,uint32_t & largestRecordSize)393 exec::task<int> PlatformManager::getPDRRepositoryInfo(
394     const pldm_tid_t tid, uint8_t& repositoryState, uint32_t& recordCount,
395     uint32_t& repositorySize, uint32_t& largestRecordSize)
396 {
397     Request request(sizeof(pldm_msg_hdr) + sizeof(uint8_t));
398     auto requestMsg = new (request.data()) pldm_msg;
399     auto rc = encode_pldm_header_only(PLDM_REQUEST, 0, PLDM_PLATFORM,
400                                       PLDM_GET_PDR_REPOSITORY_INFO, requestMsg);
401     if (rc)
402     {
403         lg2::error(
404             "Failed to encode request GetPDRRepositoryInfo for terminus ID {TID}, error {RC} ",
405             "TID", tid, "RC", rc);
406         co_return rc;
407     }
408 
409     const pldm_msg* responseMsg = nullptr;
410     size_t responseLen = 0;
411     rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
412                                                   &responseLen);
413     if (rc)
414     {
415         lg2::error(
416             "Failed to send GetPDRRepositoryInfo message for terminus {TID}, error {RC}",
417             "TID", tid, "RC", rc);
418         co_return rc;
419     }
420 
421     uint8_t completionCode = 0;
422     std::array<uint8_t, PLDM_TIMESTAMP104_SIZE> updateTime = {};
423     std::array<uint8_t, PLDM_TIMESTAMP104_SIZE> oemUpdateTime = {};
424     uint8_t dataTransferHandleTimeout = 0;
425 
426     rc = decode_get_pdr_repository_info_resp(
427         responseMsg, responseLen, &completionCode, &repositoryState,
428         updateTime.data(), oemUpdateTime.data(), &recordCount, &repositorySize,
429         &largestRecordSize, &dataTransferHandleTimeout);
430     if (rc)
431     {
432         lg2::error(
433             "Failed to decode response GetPDRRepositoryInfo for terminus ID {TID}, error {RC} ",
434             "TID", tid, "RC", rc);
435         co_return rc;
436     }
437 
438     if (completionCode != PLDM_SUCCESS)
439     {
440         lg2::error(
441             "Error : GetPDRRepositoryInfo for terminus ID {TID}, complete code {CC}.",
442             "TID", tid, "CC", completionCode);
443         co_return rc;
444     }
445 
446     co_return completionCode;
447 }
448 
eventMessageBufferSize(pldm_tid_t tid,uint16_t receiverMaxBufferSize,uint16_t & terminusBufferSize)449 exec::task<int> PlatformManager::eventMessageBufferSize(
450     pldm_tid_t tid, uint16_t receiverMaxBufferSize,
451     uint16_t& terminusBufferSize)
452 {
453     Request request(
454         sizeof(pldm_msg_hdr) + PLDM_EVENT_MESSAGE_BUFFER_SIZE_REQ_BYTES);
455     auto requestMsg = new (request.data()) pldm_msg;
456     auto rc = encode_event_message_buffer_size_req(0, receiverMaxBufferSize,
457                                                    requestMsg);
458     if (rc)
459     {
460         lg2::error(
461             "Failed to encode request GetPDRRepositoryInfo for terminus ID {TID}, error {RC} ",
462             "TID", tid, "RC", rc);
463         co_return rc;
464     }
465 
466     const pldm_msg* responseMsg = nullptr;
467     size_t responseLen = 0;
468     rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
469                                                   &responseLen);
470     if (rc)
471     {
472         lg2::error(
473             "Failed to send EventMessageBufferSize message for terminus {TID}, error {RC}",
474             "TID", tid, "RC", rc);
475         co_return rc;
476     }
477 
478     uint8_t completionCode;
479     rc = decode_event_message_buffer_size_resp(
480         responseMsg, responseLen, &completionCode, &terminusBufferSize);
481     if (rc)
482     {
483         lg2::error(
484             "Failed to decode response EventMessageBufferSize for terminus ID {TID}, error {RC} ",
485             "TID", tid, "RC", rc);
486         co_return rc;
487     }
488 
489     if (completionCode != PLDM_SUCCESS)
490     {
491         lg2::error(
492             "Error : EventMessageBufferSize for terminus ID {TID}, complete code {CC}.",
493             "TID", tid, "CC", completionCode);
494         co_return completionCode;
495     }
496 
497     co_return completionCode;
498 }
499 
setEventReceiver(pldm_tid_t tid,pldm_event_message_global_enable eventMessageGlobalEnable,pldm_transport_protocol_type protocolType,uint16_t heartbeatTimer)500 exec::task<int> PlatformManager::setEventReceiver(
501     pldm_tid_t tid, pldm_event_message_global_enable eventMessageGlobalEnable,
502     pldm_transport_protocol_type protocolType, uint16_t heartbeatTimer)
503 {
504     size_t requestBytes = PLDM_SET_EVENT_RECEIVER_REQ_BYTES;
505     /**
506      * Ignore heartbeatTimer bytes when eventMessageGlobalEnable is not
507      * ENABLE_ASYNC_KEEP_ALIVE
508      */
509     if (eventMessageGlobalEnable !=
510         PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE)
511     {
512         requestBytes = requestBytes - sizeof(heartbeatTimer);
513     }
514     Request request(sizeof(pldm_msg_hdr) + requestBytes);
515     auto requestMsg = new (request.data()) pldm_msg;
516     auto rc = encode_set_event_receiver_req(
517         0, eventMessageGlobalEnable, protocolType,
518         terminusManager.getLocalEid(), heartbeatTimer, requestMsg);
519     if (rc)
520     {
521         lg2::error(
522             "Failed to encode request SetEventReceiver for terminus ID {TID}, error {RC} ",
523             "TID", tid, "RC", rc);
524         co_return rc;
525     }
526 
527     const pldm_msg* responseMsg = nullptr;
528     size_t responseLen = 0;
529     rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
530                                                   &responseLen);
531     if (rc)
532     {
533         lg2::error(
534             "Failed to send SetEventReceiver message for terminus {TID}, error {RC}",
535             "TID", tid, "RC", rc);
536         co_return rc;
537     }
538 
539     uint8_t completionCode;
540     rc = decode_set_event_receiver_resp(responseMsg, responseLen,
541                                         &completionCode);
542     if (rc)
543     {
544         lg2::error(
545             "Failed to decode response SetEventReceiver for terminus ID {TID}, error {RC} ",
546             "TID", tid, "RC", rc);
547         co_return rc;
548     }
549 
550     if (completionCode != PLDM_SUCCESS)
551     {
552         lg2::error(
553             "Error : SetEventReceiver for terminus ID {TID}, complete code {CC}.",
554             "TID", tid, "CC", completionCode);
555         co_return completionCode;
556     }
557 
558     co_return completionCode;
559 }
560 
eventMessageSupported(pldm_tid_t tid,uint8_t formatVersion,uint8_t & synchronyConfiguration,bitfield8_t & synchronyConfigurationSupported,uint8_t & numberEventClassReturned,std::vector<uint8_t> & eventClass)561 exec::task<int> PlatformManager::eventMessageSupported(
562     pldm_tid_t tid, uint8_t formatVersion, uint8_t& synchronyConfiguration,
563     bitfield8_t& synchronyConfigurationSupported,
564     uint8_t& numberEventClassReturned, std::vector<uint8_t>& eventClass)
565 {
566     Request request(
567         sizeof(pldm_msg_hdr) + PLDM_EVENT_MESSAGE_SUPPORTED_REQ_BYTES);
568     auto requestMsg = new (request.data()) pldm_msg;
569     auto rc = encode_event_message_supported_req(0, formatVersion, requestMsg);
570     if (rc)
571     {
572         lg2::error(
573             "Failed to encode request EventMessageSupported for terminus ID {TID}, error {RC} ",
574             "TID", tid, "RC", rc);
575         co_return rc;
576     }
577 
578     const pldm_msg* responseMsg = nullptr;
579     size_t responseLen = 0;
580     rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
581                                                   &responseLen);
582     if (rc)
583     {
584         lg2::error(
585             "Failed to send EventMessageSupported message for terminus {TID}, error {RC}",
586             "TID", tid, "RC", rc);
587         co_return rc;
588     }
589 
590     uint8_t completionCode = 0;
591     uint8_t eventClassCount = static_cast<uint8_t>(responseLen) -
592                               PLDM_EVENT_MESSAGE_SUPPORTED_MIN_RESP_BYTES;
593     eventClass.resize(eventClassCount);
594 
595     rc = decode_event_message_supported_resp(
596         responseMsg, responseLen, &completionCode, &synchronyConfiguration,
597         &synchronyConfigurationSupported, &numberEventClassReturned,
598         eventClass.data(), eventClassCount);
599     if (rc)
600     {
601         lg2::error(
602             "Failed to decode response EventMessageSupported for terminus ID {TID}, error {RC} ",
603             "TID", tid, "RC", rc);
604         co_return rc;
605     }
606 
607     if (completionCode != PLDM_SUCCESS)
608     {
609         lg2::error(
610             "Error : EventMessageSupported for terminus ID {TID}, complete code {CC}.",
611             "TID", tid, "CC", completionCode);
612         co_return completionCode;
613     }
614 
615     co_return completionCode;
616 }
617 
getFRURecordTableMetadata(pldm_tid_t tid,uint16_t * total)618 exec::task<int> PlatformManager::getFRURecordTableMetadata(pldm_tid_t tid,
619                                                            uint16_t* total)
620 {
621     Request request(
622         sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES);
623     auto requestMsg = new (request.data()) pldm_msg;
624 
625     auto rc = encode_get_fru_record_table_metadata_req(
626         0, requestMsg, PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES);
627     if (rc)
628     {
629         lg2::error(
630             "Failed to encode request GetFRURecordTableMetadata for terminus ID {TID}, error {RC} ",
631             "TID", tid, "RC", rc);
632         co_return rc;
633     }
634 
635     const pldm_msg* responseMsg = nullptr;
636     size_t responseLen = 0;
637 
638     rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
639                                                   &responseLen);
640     if (rc)
641     {
642         lg2::error(
643             "Failed to send GetFRURecordTableMetadata message for terminus {TID}, error {RC}",
644             "TID", tid, "RC", rc);
645         co_return rc;
646     }
647 
648     uint8_t completionCode = 0;
649     if (responseMsg == nullptr || !responseLen)
650     {
651         lg2::error(
652             "No response data for GetFRURecordTableMetadata for terminus {TID}",
653             "TID", tid);
654         co_return rc;
655     }
656 
657     uint8_t fru_data_major_version, fru_data_minor_version;
658     uint32_t fru_table_maximum_size, fru_table_length;
659     uint16_t total_record_set_identifiers;
660     uint32_t checksum;
661     rc = decode_get_fru_record_table_metadata_resp(
662         responseMsg, responseLen, &completionCode, &fru_data_major_version,
663         &fru_data_minor_version, &fru_table_maximum_size, &fru_table_length,
664         &total_record_set_identifiers, total, &checksum);
665 
666     if (rc)
667     {
668         lg2::error(
669             "Failed to decode response GetFRURecordTableMetadata for terminus ID {TID}, error {RC} ",
670             "TID", tid, "RC", rc);
671         co_return rc;
672     }
673 
674     if (completionCode != PLDM_SUCCESS)
675     {
676         lg2::error(
677             "Error : GetFRURecordTableMetadata for terminus ID {TID}, complete code {CC}.",
678             "TID", tid, "CC", completionCode);
679         co_return rc;
680     }
681 
682     co_return rc;
683 }
684 
getFRURecordTable(pldm_tid_t tid,const uint32_t dataTransferHndl,const uint8_t transferOpFlag,uint32_t * nextDataTransferHndl,uint8_t * transferFlag,size_t * responseCnt,std::vector<uint8_t> & recordData)685 exec::task<int> PlatformManager::getFRURecordTable(
686     pldm_tid_t tid, const uint32_t dataTransferHndl,
687     const uint8_t transferOpFlag, uint32_t* nextDataTransferHndl,
688     uint8_t* transferFlag, size_t* responseCnt,
689     std::vector<uint8_t>& recordData)
690 {
691     Request request(sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES);
692     auto requestMsg = new (request.data()) pldm_msg;
693 
694     auto rc = encode_get_fru_record_table_req(
695         0, dataTransferHndl, transferOpFlag, requestMsg,
696         PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES);
697     if (rc != PLDM_SUCCESS)
698     {
699         lg2::error(
700             "Failed to encode request GetFRURecordTable for terminus ID {TID}, error {RC} ",
701             "TID", tid, "RC", rc);
702         co_return rc;
703     }
704 
705     const pldm_msg* responseMsg = nullptr;
706     size_t responseLen = 0;
707 
708     rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
709                                                   &responseLen);
710     if (rc)
711     {
712         lg2::error(
713             "Failed to send GetFRURecordTable message for terminus {TID}, error {RC}",
714             "TID", tid, "RC", rc);
715         co_return rc;
716     }
717 
718     uint8_t completionCode = 0;
719     if (responseMsg == nullptr || !responseLen)
720     {
721         lg2::error("No response data for GetFRURecordTable for terminus {TID}",
722                    "TID", tid);
723         co_return rc;
724     }
725 
726     auto responsePtr = reinterpret_cast<const struct pldm_msg*>(responseMsg);
727     rc = decode_get_fru_record_table_resp(
728         responsePtr, responseLen - sizeof(pldm_msg_hdr), &completionCode,
729         nextDataTransferHndl, transferFlag, recordData.data(), responseCnt);
730 
731     if (rc)
732     {
733         lg2::error(
734             "Failed to decode response GetFRURecordTable for terminus ID {TID}, error {RC} ",
735             "TID", tid, "RC", rc);
736         co_return rc;
737     }
738 
739     if (completionCode != PLDM_SUCCESS)
740     {
741         lg2::error(
742             "Error : GetFRURecordTable for terminus ID {TID}, complete code {CC}.",
743             "TID", tid, "CC", completionCode);
744         co_return rc;
745     }
746 
747     co_return rc;
748 }
749 
updateInventoryWithFru(pldm_tid_t tid,const uint8_t * fruData,const size_t fruLen)750 void PlatformManager::updateInventoryWithFru(
751     pldm_tid_t tid, const uint8_t* fruData, const size_t fruLen)
752 {
753     if (tid == PLDM_TID_RESERVED || !termini.contains(tid) || !termini[tid])
754     {
755         lg2::error("Invalid terminus {TID}", "TID", tid);
756         return;
757     }
758 
759     termini[tid]->updateInventoryWithFru(fruData, fruLen);
760 }
761 
getFRURecordTables(pldm_tid_t tid,const uint16_t & totalTableRecords,std::vector<uint8_t> & fruData)762 exec::task<int> PlatformManager::getFRURecordTables(
763     pldm_tid_t tid, const uint16_t& totalTableRecords,
764     std::vector<uint8_t>& fruData)
765 {
766     if (!totalTableRecords)
767     {
768         lg2::info("Fru record table has 0 records");
769         co_return PLDM_ERROR;
770     }
771 
772     uint32_t dataTransferHndl = 0;
773     uint32_t nextDataTransferHndl = 0;
774     uint8_t transferFlag = 0;
775     uint8_t transferOpFlag = PLDM_GET_FIRSTPART;
776     size_t responseCnt = 0;
777     std::vector<uint8_t> recvBuf(PLDM_PLATFORM_GETPDR_MAX_RECORD_BYTES);
778 
779     size_t fruLength = 0;
780     std::vector<uint8_t> receivedFru(0);
781     do
782     {
783         auto rc = co_await getFRURecordTable(
784             tid, dataTransferHndl, transferOpFlag, &nextDataTransferHndl,
785             &transferFlag, &responseCnt, recvBuf);
786 
787         if (rc)
788         {
789             lg2::error(
790                 "Failed to get Fru Record Data for terminus {TID}, error: {RC}, first part of data handle {RECORD}",
791                 "TID", tid, "RC", rc, "RECORD", dataTransferHndl);
792             co_return rc;
793         }
794 
795         receivedFru.insert(receivedFru.end(), recvBuf.begin(),
796                            recvBuf.begin() + responseCnt);
797         fruLength += responseCnt;
798         if (transferFlag == PLDM_PLATFORM_TRANSFER_START_AND_END ||
799             transferFlag == PLDM_PLATFORM_TRANSFER_END)
800         {
801             break;
802         }
803 
804         // multipart transfer
805         dataTransferHndl = nextDataTransferHndl;
806         transferOpFlag = PLDM_GET_NEXTPART;
807 
808     } while (nextDataTransferHndl != 0);
809 
810     if (fruLength != receivedFru.size())
811     {
812         lg2::error(
813             "Size of Fru Record Data {SIZE} for terminus {TID} is different the responded size {RSPSIZE}.",
814             "SIZE", receivedFru.size(), "RSPSIZE", fruLength);
815         co_return PLDM_ERROR_INVALID_LENGTH;
816     }
817 
818     fruData = receivedFru;
819 
820     co_return PLDM_SUCCESS;
821 }
822 
823 } // namespace platform_mc
824 } // namespace pldm
825