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