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