1 #include "terminus_manager.hpp" 2 3 #include "manager.hpp" 4 5 #include <phosphor-logging/lg2.hpp> 6 7 PHOSPHOR_LOG2_USING; 8 9 namespace pldm 10 { 11 namespace platform_mc 12 { 13 14 std::optional<MctpInfo> TerminusManager::toMctpInfo(const pldm_tid_t& tid) 15 { 16 if (tid == PLDM_TID_UNASSIGNED || tid == PLDM_TID_RESERVED) 17 { 18 return std::nullopt; 19 } 20 21 if ((!this->transportLayerTable.contains(tid)) || 22 (this->transportLayerTable[tid] != SupportedTransportLayer::MCTP)) 23 { 24 return std::nullopt; 25 } 26 27 auto mctpInfoIt = mctpInfoTable.find(tid); 28 if (mctpInfoIt == mctpInfoTable.end()) 29 { 30 return std::nullopt; 31 } 32 33 return mctpInfoIt->second; 34 } 35 36 std::optional<pldm_tid_t> TerminusManager::toTid(const MctpInfo& mctpInfo) const 37 { 38 if (!pldm::utils::isValidEID(std::get<0>(mctpInfo))) 39 { 40 return std::nullopt; 41 } 42 43 auto mctpInfoTableIt = std::find_if( 44 mctpInfoTable.begin(), mctpInfoTable.end(), [&mctpInfo](auto& v) { 45 return (std::get<0>(v.second) == std::get<0>(mctpInfo)) && 46 (std::get<3>(v.second) == std::get<3>(mctpInfo)); 47 }); 48 if (mctpInfoTableIt == mctpInfoTable.end()) 49 { 50 return std::nullopt; 51 } 52 return mctpInfoTableIt->first; 53 } 54 55 std::optional<pldm_tid_t> TerminusManager::storeTerminusInfo( 56 const MctpInfo& mctpInfo, pldm_tid_t tid) 57 { 58 if (tid == PLDM_TID_UNASSIGNED || tid == PLDM_TID_RESERVED) 59 { 60 return std::nullopt; 61 } 62 63 if (!pldm::utils::isValidEID(std::get<0>(mctpInfo))) 64 { 65 return std::nullopt; 66 } 67 68 if (tidPool[tid]) 69 { 70 return std::nullopt; 71 } 72 73 tidPool[tid] = true; 74 transportLayerTable[tid] = SupportedTransportLayer::MCTP; 75 mctpInfoTable[tid] = mctpInfo; 76 77 return tid; 78 } 79 80 std::optional<pldm_tid_t> TerminusManager::mapTid(const MctpInfo& mctpInfo) 81 { 82 if (!pldm::utils::isValidEID(std::get<0>(mctpInfo))) 83 { 84 return std::nullopt; 85 } 86 87 auto mctpInfoTableIt = std::find_if( 88 mctpInfoTable.begin(), mctpInfoTable.end(), [&mctpInfo](auto& v) { 89 return (std::get<0>(v.second) == std::get<0>(mctpInfo)) && 90 (std::get<3>(v.second) == std::get<3>(mctpInfo)); 91 }); 92 if (mctpInfoTableIt != mctpInfoTable.end()) 93 { 94 return mctpInfoTableIt->first; 95 } 96 97 auto tidPoolIt = std::find(tidPool.begin(), tidPool.end(), false); 98 if (tidPoolIt == tidPool.end()) 99 { 100 return std::nullopt; 101 } 102 103 pldm_tid_t tid = std::distance(tidPool.begin(), tidPoolIt); 104 return storeTerminusInfo(mctpInfo, tid); 105 } 106 107 bool TerminusManager::unmapTid(const pldm_tid_t& tid) 108 { 109 if (tid == PLDM_TID_UNASSIGNED || tid == PLDM_TID_RESERVED) 110 { 111 return false; 112 } 113 tidPool[tid] = false; 114 115 if (transportLayerTable.contains(tid)) 116 { 117 transportLayerTable.erase(tid); 118 } 119 120 if (mctpInfoTable.contains(tid)) 121 { 122 mctpInfoTable.erase(tid); 123 } 124 125 return true; 126 } 127 128 void TerminusManager::updateMctpEndpointAvailability(const MctpInfo& mctpInfo, 129 Availability availability) 130 { 131 mctpInfoAvailTable.insert_or_assign(mctpInfo, availability); 132 133 if (manager) 134 { 135 auto tid = toTid(mctpInfo); 136 if (tid) 137 { 138 manager->updateAvailableState(tid.value(), availability); 139 } 140 } 141 } 142 143 std::string TerminusManager::constructEndpointObjPath(const MctpInfo& mctpInfo) 144 { 145 std::string eidStr = std::to_string(std::get<0>(mctpInfo)); 146 std::string networkIDStr = std::to_string(std::get<3>(mctpInfo)); 147 return std::format("{}/networks/{}/endpoints/{}", MCTPPath, networkIDStr, 148 eidStr); 149 } 150 151 void TerminusManager::discoverMctpTerminus(const MctpInfos& mctpInfos) 152 { 153 queuedMctpInfos.emplace(mctpInfos); 154 if (discoverMctpTerminusTaskHandle.has_value()) 155 { 156 auto& [scope, rcOpt] = *discoverMctpTerminusTaskHandle; 157 if (!rcOpt.has_value()) 158 { 159 return; 160 } 161 stdexec::sync_wait(scope.on_empty()); 162 discoverMctpTerminusTaskHandle.reset(); 163 } 164 auto& [scope, rcOpt] = discoverMctpTerminusTaskHandle.emplace(); 165 scope.spawn(discoverMctpTerminusTask() | 166 stdexec::then([&](int rc) { rcOpt.emplace(rc); }), 167 exec::default_task_context<void>(exec::inline_scheduler{})); 168 } 169 170 TerminiMapper::iterator TerminusManager::findTerminusPtr( 171 const MctpInfo& mctpInfo) 172 { 173 auto foundIter = std::find_if( 174 termini.begin(), termini.end(), [&](const auto& terminusPair) { 175 auto terminusMctpInfo = toMctpInfo(terminusPair.first); 176 return (terminusMctpInfo && 177 (std::get<0>(terminusMctpInfo.value()) == 178 std::get<0>(mctpInfo)) && 179 (std::get<3>(terminusMctpInfo.value()) == 180 std::get<3>(mctpInfo))); 181 }); 182 183 return foundIter; 184 } 185 186 exec::task<int> TerminusManager::discoverMctpTerminusTask() 187 { 188 std::vector<pldm_tid_t> addedTids; 189 190 while (!queuedMctpInfos.empty()) 191 { 192 bool terminusInitFailed = false; 193 if (manager) 194 { 195 co_await manager->beforeDiscoverTerminus(); 196 } 197 198 const MctpInfos& mctpInfos = queuedMctpInfos.front(); 199 for (const auto& mctpInfo : mctpInfos) 200 { 201 auto it = findTerminusPtr(mctpInfo); 202 if (it == termini.end()) 203 { 204 mctpInfoAvailTable[mctpInfo] = true; 205 auto rc = co_await initMctpTerminus(mctpInfo); 206 if (rc != PLDM_SUCCESS) 207 { 208 lg2::error( 209 "Failed to initialize terminus with EID {EID}, networkId {NETWORK}, response code {RC}.", 210 "EID", std::get<0>(mctpInfo), "NETWORK", 211 std::get<3>(mctpInfo), "RC", rc); 212 mctpInfoAvailTable.erase(mctpInfo); 213 terminusInitFailed = true; 214 continue; 215 } 216 } 217 218 /* Get TID of initialized terminus */ 219 auto tid = toTid(mctpInfo); 220 if (!tid) 221 { 222 lg2::error( 223 "Failed to get TID for terminus with EID {EID}, networkId {NETWORK}.", 224 "EID", std::get<0>(mctpInfo), "NETWORK", 225 std::get<3>(mctpInfo)); 226 mctpInfoAvailTable.erase(mctpInfo); 227 terminusInitFailed = true; 228 continue; 229 } 230 addedTids.push_back(tid.value()); 231 } 232 233 if (manager) 234 { 235 co_await manager->afterDiscoverTerminus(); 236 } 237 238 if (terminusInitFailed) 239 { 240 co_return PLDM_ERROR; 241 } 242 243 queuedMctpInfos.pop(); 244 } 245 246 co_return PLDM_SUCCESS; 247 } 248 249 void TerminusManager::removeMctpTerminus(const MctpInfos& mctpInfos) 250 { 251 // remove terminus 252 for (const auto& mctpInfo : mctpInfos) 253 { 254 auto it = findTerminusPtr(mctpInfo); 255 if (it == termini.end()) 256 { 257 continue; 258 } 259 260 if (manager) 261 { 262 manager->stopSensorPolling(it->second->getTid()); 263 } 264 265 unmapTid(it->first); 266 termini.erase(it); 267 mctpInfoAvailTable.erase(mctpInfo); 268 } 269 } 270 271 exec::task<int> TerminusManager::initMctpTerminus(const MctpInfo& mctpInfo) 272 { 273 mctp_eid_t eid = std::get<0>(mctpInfo); 274 pldm_tid_t tid = 0; 275 bool isMapped = false; 276 auto rc = co_await getTidOverMctp(eid, &tid); 277 if (rc != PLDM_SUCCESS) 278 { 279 lg2::error("Failed to Get Terminus ID, error {ERROR}.", "ERROR", rc); 280 co_return PLDM_ERROR; 281 } 282 283 if (tid == PLDM_TID_RESERVED) 284 { 285 lg2::error("Terminus responses the reserved {TID}.", "TID", tid); 286 co_return PLDM_ERROR; 287 } 288 289 /* Terminus already has TID */ 290 if (tid != PLDM_TID_UNASSIGNED) 291 { 292 /* TID is used by one discovered terminus */ 293 auto it = termini.find(tid); 294 if (it != termini.end()) 295 { 296 auto terminusMctpInfo = toMctpInfo(it->first); 297 /* The discovered terminus has the same MCTP Info */ 298 if (terminusMctpInfo && 299 (std::get<0>(terminusMctpInfo.value()) == 300 std::get<0>(mctpInfo)) && 301 (std::get<3>(terminusMctpInfo.value()) == 302 std::get<3>(mctpInfo))) 303 { 304 co_return PLDM_SUCCESS; 305 } 306 else 307 { 308 /* ToDo: 309 * Maybe the terminus supports multiple medium interfaces 310 * Or the TID is used by other terminus. 311 * Check the UUID to confirm. 312 */ 313 isMapped = false; 314 } 315 } 316 /* Use the terminus TID for mapping */ 317 else 318 { 319 auto mappedTid = storeTerminusInfo(mctpInfo, tid); 320 if (!mappedTid) 321 { 322 lg2::error("Failed to store Terminus Info for terminus {TID}.", 323 "TID", tid); 324 co_return PLDM_ERROR; 325 } 326 isMapped = true; 327 } 328 } 329 330 if (!isMapped) 331 { 332 // Assigning a tid. If it has been mapped, mapTid() 333 // returns the tid assigned before. 334 auto mappedTid = mapTid(mctpInfo); 335 if (!mappedTid) 336 { 337 lg2::error("Failed to store Terminus Info for terminus {TID}.", 338 "TID", tid); 339 co_return PLDM_ERROR; 340 } 341 342 tid = mappedTid.value(); 343 rc = co_await setTidOverMctp(eid, tid); 344 if (rc != PLDM_SUCCESS) 345 { 346 lg2::error("Failed to Set terminus TID, error{ERROR}.", "ERROR", 347 rc); 348 unmapTid(tid); 349 co_return rc; 350 } 351 352 if (rc != PLDM_SUCCESS && rc != PLDM_ERROR_UNSUPPORTED_PLDM_CMD) 353 { 354 lg2::error("Terminus {TID} does not support SetTID command.", "TID", 355 tid); 356 unmapTid(tid); 357 co_return rc; 358 } 359 360 if (termini.contains(tid)) 361 { 362 // the terminus has been discovered before 363 co_return PLDM_SUCCESS; 364 } 365 } 366 /* Discovery the mapped terminus */ 367 uint64_t supportedTypes = 0; 368 rc = co_await getPLDMTypes(tid, supportedTypes); 369 if (rc) 370 { 371 lg2::error("Failed to Get PLDM Types for terminus {TID}, error {ERROR}", 372 "TID", tid, "ERROR", rc); 373 unmapTid(tid); 374 co_return PLDM_ERROR; 375 } 376 377 try 378 { 379 termini[tid] = std::make_shared<Terminus>(tid, supportedTypes, event); 380 } 381 catch (const sdbusplus::exception_t& e) 382 { 383 lg2::error("Failed to create terminus manager for terminus {TID}", 384 "TID", tid); 385 unmapTid(tid); 386 co_return PLDM_ERROR; 387 } 388 389 uint8_t type = PLDM_BASE; 390 auto size = PLDM_MAX_TYPES * (PLDM_MAX_CMDS_PER_TYPE / 8); 391 std::vector<uint8_t> pldmCmds(size); 392 while ((type < PLDM_MAX_TYPES)) 393 { 394 if (!termini[tid]->doesSupportType(type)) 395 { 396 type++; 397 continue; 398 } 399 400 ver32_t version{0xFF, 0xFF, 0xFF, 0xFF}; 401 auto rc = co_await getPLDMVersion(tid, type, &version); 402 if (rc) 403 { 404 lg2::error( 405 "Failed to Get PLDM Version for terminus {TID}, PLDM Type {TYPE}, error {ERROR}", 406 "TID", tid, "TYPE", type, "ERROR", rc); 407 } 408 termini[tid]->setSupportedTypeVersions(type, version); 409 std::vector<bitfield8_t> cmds(PLDM_MAX_CMDS_PER_TYPE / 8); 410 rc = co_await getPLDMCommands(tid, type, version, cmds.data()); 411 if (rc) 412 { 413 lg2::error( 414 "Failed to Get PLDM Commands for terminus {TID}, error {ERROR}", 415 "TID", tid, "ERROR", rc); 416 } 417 418 for (size_t i = 0; i < cmds.size(); i++) 419 { 420 auto idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + i; 421 if (idx >= pldmCmds.size()) 422 { 423 lg2::error( 424 "Calculated index {IDX} out of bounds for pldmCmds, type {TYPE}, command index {CMD_IDX}", 425 "IDX", idx, "TYPE", type, "CMD_IDX", i); 426 continue; 427 } 428 pldmCmds[idx] = cmds[i].byte; 429 } 430 type++; 431 } 432 termini[tid]->setSupportedCommands(pldmCmds); 433 434 /* Use the MCTP target name as the default terminus name */ 435 MctpInfoName mctpInfoName = std::get<4>(mctpInfo); 436 if (mctpInfoName.has_value()) 437 { 438 lg2::info("Terminus {TID} has default Terminus Name {NAME}", "NAME", 439 mctpInfoName.value(), "TID", tid); 440 termini[tid]->setTerminusName(mctpInfoName.value()); 441 } 442 443 co_return PLDM_SUCCESS; 444 } 445 446 exec::task<int> TerminusManager::sendRecvPldmMsgOverMctp( 447 mctp_eid_t eid, Request& request, const pldm_msg** responseMsg, 448 size_t* responseLen) 449 { 450 int rc = 0; 451 try 452 { 453 std::tie(rc, *responseMsg, *responseLen) = 454 co_await handler.sendRecvMsg(eid, std::move(request)); 455 } 456 catch (const sdbusplus::exception_t& e) 457 { 458 lg2::error( 459 "Send and Receive PLDM message over MCTP throw error - {ERROR}.", 460 "ERROR", e); 461 co_return PLDM_ERROR; 462 } 463 catch (const int& e) 464 { 465 lg2::error( 466 "Send and Receive PLDM message over MCTP throw int error - {ERROR}.", 467 "ERROR", e); 468 co_return PLDM_ERROR; 469 } 470 471 co_return rc; 472 } 473 474 exec::task<int> TerminusManager::getTidOverMctp(mctp_eid_t eid, pldm_tid_t* tid) 475 { 476 auto instanceId = instanceIdDb.next(eid); 477 Request request(sizeof(pldm_msg_hdr)); 478 auto requestMsg = new (request.data()) pldm_msg; 479 auto rc = encode_get_tid_req(instanceId, requestMsg); 480 if (rc) 481 { 482 instanceIdDb.free(eid, instanceId); 483 lg2::error( 484 "Failed to encode request GetTID for endpoint ID {EID}, error {RC} ", 485 "EID", eid, "RC", rc); 486 co_return rc; 487 } 488 489 const pldm_msg* responseMsg = nullptr; 490 size_t responseLen = 0; 491 rc = co_await sendRecvPldmMsgOverMctp(eid, request, &responseMsg, 492 &responseLen); 493 if (rc) 494 { 495 lg2::error("Failed to send GetTID for Endpoint {EID}, error {RC}", 496 "EID", eid, "RC", rc); 497 co_return rc; 498 } 499 500 uint8_t completionCode = 0; 501 rc = decode_get_tid_resp(responseMsg, responseLen, &completionCode, tid); 502 if (rc) 503 { 504 lg2::error( 505 "Failed to decode response GetTID for Endpoint ID {EID}, error {RC} ", 506 "EID", eid, "RC", rc); 507 co_return rc; 508 } 509 510 if (completionCode != PLDM_SUCCESS) 511 { 512 lg2::error("Error : GetTID for Endpoint ID {EID}, complete code {CC}.", 513 "EID", eid, "CC", completionCode); 514 co_return rc; 515 } 516 517 co_return completionCode; 518 } 519 520 exec::task<int> TerminusManager::setTidOverMctp(mctp_eid_t eid, pldm_tid_t tid) 521 { 522 auto instanceId = instanceIdDb.next(eid); 523 Request request(sizeof(pldm_msg_hdr) + sizeof(pldm_set_tid_req)); 524 auto requestMsg = new (request.data()) pldm_msg; 525 auto rc = encode_set_tid_req(instanceId, tid, requestMsg); 526 if (rc) 527 { 528 instanceIdDb.free(eid, instanceId); 529 lg2::error( 530 "Failed to encode request SetTID for endpoint ID {EID}, error {RC} ", 531 "EID", eid, "RC", rc); 532 co_return rc; 533 } 534 535 const pldm_msg* responseMsg = nullptr; 536 size_t responseLen = 0; 537 rc = co_await sendRecvPldmMsgOverMctp(eid, request, &responseMsg, 538 &responseLen); 539 if (rc) 540 { 541 lg2::error("Failed to send SetTID for Endpoint {EID}, error {RC}", 542 "EID", eid, "RC", rc); 543 co_return rc; 544 } 545 546 if (responseMsg == nullptr || responseLen != PLDM_SET_TID_RESP_BYTES) 547 { 548 lg2::error( 549 "Failed to decode response SetTID for Endpoint ID {EID}, error {RC} ", 550 "EID", eid, "RC", rc); 551 co_return PLDM_ERROR_INVALID_LENGTH; 552 } 553 554 co_return responseMsg->payload[0]; 555 } 556 557 exec::task<int> TerminusManager::getPLDMTypes(pldm_tid_t tid, 558 uint64_t& supportedTypes) 559 { 560 Request request(sizeof(pldm_msg_hdr)); 561 auto requestMsg = new (request.data()) pldm_msg; 562 auto rc = encode_get_types_req(0, requestMsg); 563 if (rc) 564 { 565 lg2::error( 566 "Failed to encode request getPLDMTypes for terminus ID {TID}, error {RC} ", 567 "TID", tid, "RC", rc); 568 co_return rc; 569 } 570 571 const pldm_msg* responseMsg = nullptr; 572 size_t responseLen = 0; 573 574 rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen); 575 if (rc) 576 { 577 lg2::error("Failed to send GetPLDMTypes for terminus {TID}, error {RC}", 578 "TID", tid, "RC", rc); 579 co_return rc; 580 } 581 582 uint8_t completionCode = 0; 583 bitfield8_t* types = reinterpret_cast<bitfield8_t*>(&supportedTypes); 584 rc = 585 decode_get_types_resp(responseMsg, responseLen, &completionCode, types); 586 if (rc) 587 { 588 lg2::error( 589 "Failed to decode response GetPLDMTypes for terminus ID {TID}, error {RC} ", 590 "TID", tid, "RC", rc); 591 co_return rc; 592 } 593 594 if (completionCode != PLDM_SUCCESS) 595 { 596 lg2::error( 597 "Error : GetPLDMTypes for terminus ID {TID}, complete code {CC}.", 598 "TID", tid, "CC", completionCode); 599 co_return rc; 600 } 601 co_return completionCode; 602 } 603 604 exec::task<int> TerminusManager::getPLDMCommands( 605 pldm_tid_t tid, uint8_t type, ver32_t version, bitfield8_t* supportedCmds) 606 { 607 Request request(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES); 608 auto requestMsg = new (request.data()) pldm_msg; 609 610 auto rc = encode_get_commands_req(0, type, version, requestMsg); 611 if (rc) 612 { 613 lg2::error( 614 "Failed to encode request GetPLDMCommands for terminus ID {TID}, error {RC} ", 615 "TID", tid, "RC", rc); 616 co_return rc; 617 } 618 619 const pldm_msg* responseMsg = nullptr; 620 size_t responseLen = 0; 621 622 rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen); 623 if (rc) 624 { 625 lg2::error( 626 "Failed to send GetPLDMCommands message for terminus {TID}, error {RC}", 627 "TID", tid, "RC", rc); 628 co_return rc; 629 } 630 631 /* Process response */ 632 uint8_t completionCode = 0; 633 rc = decode_get_commands_resp(responseMsg, responseLen, &completionCode, 634 supportedCmds); 635 if (rc) 636 { 637 lg2::error( 638 "Failed to decode response GetPLDMCommands for terminus ID {TID}, error {RC} ", 639 "TID", tid, "RC", rc); 640 co_return rc; 641 } 642 643 if (completionCode != PLDM_SUCCESS) 644 { 645 lg2::error( 646 "Error : GetPLDMCommands for terminus ID {TID}, complete code {CC}.", 647 "TID", tid, "CC", completionCode); 648 co_return rc; 649 } 650 651 co_return completionCode; 652 } 653 654 exec::task<int> TerminusManager::sendRecvPldmMsg( 655 pldm_tid_t tid, Request& request, const pldm_msg** responseMsg, 656 size_t* responseLen) 657 { 658 /** 659 * Size of tidPool is `std::numeric_limits<pldm_tid_t>::max() + 1` 660 * tidPool[i] always exist 661 */ 662 if (!tidPool[tid]) 663 { 664 co_return PLDM_ERROR_NOT_READY; 665 } 666 667 if (!transportLayerTable.contains(tid)) 668 { 669 co_return PLDM_ERROR_NOT_READY; 670 } 671 672 if (transportLayerTable[tid] != SupportedTransportLayer::MCTP) 673 { 674 co_return PLDM_ERROR_NOT_READY; 675 } 676 677 auto mctpInfo = toMctpInfo(tid); 678 if (!mctpInfo.has_value()) 679 { 680 co_return PLDM_ERROR_NOT_READY; 681 } 682 683 // There's a cost of maintaining another table to hold availability 684 // status as we can't ensure that it always synchronizes with the 685 // mctpInfoTable; std::map operator[] will insert a default of boolean 686 // which is false to the mctpInfoAvailTable if the mctpInfo key doesn't 687 // exist. Once we miss to initialize the availability of an available 688 // endpoint, it will drop all the messages to/from it. 689 if (!mctpInfoAvailTable[mctpInfo.value()]) 690 { 691 co_return PLDM_ERROR_NOT_READY; 692 } 693 694 auto eid = std::get<0>(mctpInfo.value()); 695 auto requestMsg = new (request.data()) pldm_msg; 696 requestMsg->hdr.instance_id = instanceIdDb.next(eid); 697 auto rc = co_await sendRecvPldmMsgOverMctp(eid, request, responseMsg, 698 responseLen); 699 700 if (rc == PLDM_ERROR_NOT_READY) 701 { 702 // Call Recover() to check enpoint's availability 703 // Set endpoint's availability in mctpInfoTable to false in advance 704 // to prevent message forwarding through this endpoint while mctpd 705 // is checking the endpoint. 706 std::string endpointObjPath = 707 constructEndpointObjPath(mctpInfo.value()); 708 pldm::utils::recoverMctpEndpoint(endpointObjPath); 709 updateMctpEndpointAvailability(mctpInfo.value(), false); 710 } 711 712 co_return rc; 713 } 714 715 exec::task<int> TerminusManager::getPLDMVersion(pldm_tid_t tid, uint8_t type, 716 ver32_t* version) 717 { 718 Request request(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_REQ_BYTES); 719 auto requestMsg = new (request.data()) pldm_msg; 720 721 auto rc = 722 encode_get_version_req(0, 0, PLDM_GET_FIRSTPART, type, requestMsg); 723 if (rc) 724 { 725 lg2::error( 726 "Failed to encode request getPLDMVersion for terminus ID {TID}, error {RC} ", 727 "TID", tid, "RC", rc); 728 co_return rc; 729 } 730 731 const pldm_msg* responseMsg = nullptr; 732 size_t responseLen = 0; 733 734 rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen); 735 if (rc) 736 { 737 lg2::error( 738 "Failed to send getPLDMVersion message for terminus {TID}, error {RC}", 739 "TID", tid, "RC", rc); 740 co_return rc; 741 } 742 743 /* Process response */ 744 uint8_t completionCode = 0; 745 uint8_t transferFlag = 0; 746 uint32_t transferHandle = 0; 747 rc = decode_get_version_resp(responseMsg, responseLen, &completionCode, 748 &transferHandle, &transferFlag, version); 749 if (rc) 750 { 751 lg2::error( 752 "Failed to decode response getPLDMVersion for terminus ID {TID}, error {RC} ", 753 "TID", tid, "RC", rc); 754 co_return rc; 755 } 756 757 if (completionCode != PLDM_SUCCESS) 758 { 759 lg2::error( 760 "Error : getPLDMVersion for terminus ID {TID}, complete code {CC}.", 761 "TID", tid, "CC", completionCode); 762 co_return completionCode; 763 } 764 765 co_return completionCode; 766 } 767 768 std::optional<mctp_eid_t> TerminusManager::getActiveEidByName( 769 const std::string& terminusName) 770 { 771 if (!termini.size() || terminusName.empty()) 772 { 773 return std::nullopt; 774 } 775 776 for (auto& [tid, terminus] : termini) 777 { 778 if (!terminus) 779 { 780 continue; 781 } 782 783 auto tmp = terminus->getTerminusName(); 784 if (!tmp || std::empty(*tmp) || *tmp != terminusName) 785 { 786 continue; 787 } 788 789 try 790 { 791 auto mctpInfo = toMctpInfo(tid); 792 if (!mctpInfo || !mctpInfoAvailTable[*mctpInfo]) 793 { 794 return std::nullopt; 795 } 796 797 return std::get<0>(*mctpInfo); 798 } 799 catch (const std::exception& e) 800 { 801 return std::nullopt; 802 } 803 } 804 805 return std::nullopt; 806 } 807 } // namespace platform_mc 808 } // namespace pldm 809