xref: /openbmc/pldm/platform-mc/terminus_manager.cpp (revision 502bd60f0b6f1b065363c0625fe7c6d4c0367523)
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 
toMctpInfo(const pldm_tid_t & tid)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 
toTid(const MctpInfo & mctpInfo) const36 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 
storeTerminusInfo(const MctpInfo & mctpInfo,pldm_tid_t tid)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 
mapTid(const MctpInfo & mctpInfo)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 
unmapTid(const pldm_tid_t & tid)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 
updateMctpEndpointAvailability(const MctpInfo & mctpInfo,Availability availability)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 
constructEndpointObjPath(const MctpInfo & mctpInfo)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 
discoverMctpTerminus(const MctpInfos & mctpInfos)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 
findTerminusPtr(const MctpInfo & mctpInfo)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 
discoverMctpTerminusTask()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 
removeMctpTerminus(const MctpInfos & mctpInfos)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 
initMctpTerminus(const MctpInfo & mctpInfo)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 
sendRecvPldmMsgOverMctp(mctp_eid_t eid,Request & request,const pldm_msg ** responseMsg,size_t * responseLen)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 
getTidOverMctp(mctp_eid_t eid,pldm_tid_t * tid)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 
setTidOverMctp(mctp_eid_t eid,pldm_tid_t tid)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 
getPLDMTypes(pldm_tid_t tid,uint64_t & supportedTypes)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 
getPLDMCommands(pldm_tid_t tid,uint8_t type,ver32_t version,bitfield8_t * supportedCmds)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 
sendRecvPldmMsg(pldm_tid_t tid,Request & request,const pldm_msg ** responseMsg,size_t * responseLen)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 
getPLDMVersion(pldm_tid_t tid,uint8_t type,ver32_t * version)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 
getActiveEidByName(const std::string & terminusName)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