xref: /openbmc/pldm/platform-mc/terminus_manager.cpp (revision e7b4f07d071fdfc25df0bcbb17cd50b075eb0265)
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             if (rc == PLDM_ERROR_UNSUPPORTED_PLDM_CMD)
347             {
348                 lg2::error("Terminus {TID} does not support SetTID command.",
349                            "TID", tid);
350             }
351             else
352             {
353                 lg2::error(
354                     "Failed to Set terminus TID for terminus {TID}, error {ERROR}.",
355                     "TID", tid, "ERROR", rc);
356             }
357             unmapTid(tid);
358             co_return rc;
359         }
360 
361         if (termini.contains(tid))
362         {
363             // the terminus has been discovered before
364             co_return PLDM_SUCCESS;
365         }
366     }
367     /* Discovery the mapped terminus */
368     uint64_t supportedTypes = 0;
369     rc = co_await getPLDMTypes(tid, supportedTypes);
370     if (rc)
371     {
372         lg2::error("Failed to Get PLDM Types for terminus {TID}, error {ERROR}",
373                    "TID", tid, "ERROR", rc);
374         unmapTid(tid);
375         co_return PLDM_ERROR;
376     }
377 
378     try
379     {
380         termini[tid] = std::make_shared<Terminus>(tid, supportedTypes, event);
381     }
382     catch (const sdbusplus::exception_t& e)
383     {
384         lg2::error("Failed to create terminus manager for terminus {TID}",
385                    "TID", tid);
386         unmapTid(tid);
387         co_return PLDM_ERROR;
388     }
389 
390     uint8_t type = PLDM_BASE;
391     auto size = PLDM_MAX_TYPES * (PLDM_MAX_CMDS_PER_TYPE / 8);
392     std::vector<uint8_t> pldmCmds(size);
393     while ((type < PLDM_MAX_TYPES))
394     {
395         if (!termini[tid]->doesSupportType(type))
396         {
397             type++;
398             continue;
399         }
400 
401         ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
402         auto rc = co_await getPLDMVersion(tid, type, &version);
403         if (rc)
404         {
405             lg2::error(
406                 "Failed to Get PLDM Version for terminus {TID}, PLDM Type {TYPE}, error {ERROR}",
407                 "TID", tid, "TYPE", type, "ERROR", rc);
408         }
409         termini[tid]->setSupportedTypeVersions(type, version);
410         std::vector<bitfield8_t> cmds(PLDM_MAX_CMDS_PER_TYPE / 8);
411         rc = co_await getPLDMCommands(tid, type, version, cmds.data());
412         if (rc)
413         {
414             lg2::error(
415                 "Failed to Get PLDM Commands for terminus {TID}, error {ERROR}",
416                 "TID", tid, "ERROR", rc);
417         }
418 
419         for (size_t i = 0; i < cmds.size(); i++)
420         {
421             auto idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + i;
422             if (idx >= pldmCmds.size())
423             {
424                 lg2::error(
425                     "Calculated index {IDX} out of bounds for pldmCmds, type {TYPE}, command index {CMD_IDX}",
426                     "IDX", idx, "TYPE", type, "CMD_IDX", i);
427                 continue;
428             }
429             pldmCmds[idx] = cmds[i].byte;
430         }
431         type++;
432     }
433     termini[tid]->setSupportedCommands(pldmCmds);
434 
435     /* Use the MCTP target name as the default terminus name */
436     MctpInfoName mctpInfoName = std::get<4>(mctpInfo);
437     if (mctpInfoName.has_value())
438     {
439         lg2::info("Terminus {TID} has default Terminus Name {NAME}", "NAME",
440                   mctpInfoName.value(), "TID", tid);
441         termini[tid]->setTerminusName(mctpInfoName.value());
442     }
443 
444     co_return PLDM_SUCCESS;
445 }
446 
sendRecvPldmMsgOverMctp(mctp_eid_t eid,Request & request,const pldm_msg ** responseMsg,size_t * responseLen)447 exec::task<int> TerminusManager::sendRecvPldmMsgOverMctp(
448     mctp_eid_t eid, Request& request, const pldm_msg** responseMsg,
449     size_t* responseLen)
450 {
451     int rc = 0;
452     try
453     {
454         std::tie(rc, *responseMsg, *responseLen) =
455             co_await handler.sendRecvMsg(eid, std::move(request));
456     }
457     catch (const sdbusplus::exception_t& e)
458     {
459         lg2::error(
460             "Send and Receive PLDM message over MCTP throw error - {ERROR}.",
461             "ERROR", e);
462         co_return PLDM_ERROR;
463     }
464     catch (const int& e)
465     {
466         lg2::error(
467             "Send and Receive PLDM message over MCTP throw int error - {ERROR}.",
468             "ERROR", e);
469         co_return PLDM_ERROR;
470     }
471 
472     co_return rc;
473 }
474 
getTidOverMctp(mctp_eid_t eid,pldm_tid_t * tid)475 exec::task<int> TerminusManager::getTidOverMctp(mctp_eid_t eid, pldm_tid_t* tid)
476 {
477     auto instanceId = instanceIdDb.next(eid);
478     Request request(sizeof(pldm_msg_hdr));
479     auto requestMsg = new (request.data()) pldm_msg;
480     auto rc = encode_get_tid_req(instanceId, requestMsg);
481     if (rc)
482     {
483         instanceIdDb.free(eid, instanceId);
484         lg2::error(
485             "Failed to encode request GetTID for endpoint ID {EID}, error {RC} ",
486             "EID", eid, "RC", rc);
487         co_return rc;
488     }
489 
490     const pldm_msg* responseMsg = nullptr;
491     size_t responseLen = 0;
492     rc = co_await sendRecvPldmMsgOverMctp(eid, request, &responseMsg,
493                                           &responseLen);
494     if (rc)
495     {
496         lg2::error("Failed to send GetTID for Endpoint {EID}, error {RC}",
497                    "EID", eid, "RC", rc);
498         co_return rc;
499     }
500 
501     uint8_t completionCode = 0;
502     rc = decode_get_tid_resp(responseMsg, responseLen, &completionCode, tid);
503     if (rc)
504     {
505         lg2::error(
506             "Failed to decode response GetTID for Endpoint ID {EID}, error {RC} ",
507             "EID", eid, "RC", rc);
508         co_return rc;
509     }
510 
511     if (completionCode != PLDM_SUCCESS)
512     {
513         lg2::error("Error : GetTID for Endpoint ID {EID}, complete code {CC}.",
514                    "EID", eid, "CC", completionCode);
515         co_return rc;
516     }
517 
518     co_return completionCode;
519 }
520 
setTidOverMctp(mctp_eid_t eid,pldm_tid_t tid)521 exec::task<int> TerminusManager::setTidOverMctp(mctp_eid_t eid, pldm_tid_t tid)
522 {
523     auto instanceId = instanceIdDb.next(eid);
524     Request request(sizeof(pldm_msg_hdr) + sizeof(pldm_set_tid_req));
525     auto requestMsg = new (request.data()) pldm_msg;
526     auto rc = encode_set_tid_req(instanceId, tid, requestMsg);
527     if (rc)
528     {
529         instanceIdDb.free(eid, instanceId);
530         lg2::error(
531             "Failed to encode request SetTID for endpoint ID {EID}, error {RC} ",
532             "EID", eid, "RC", rc);
533         co_return rc;
534     }
535 
536     const pldm_msg* responseMsg = nullptr;
537     size_t responseLen = 0;
538     rc = co_await sendRecvPldmMsgOverMctp(eid, request, &responseMsg,
539                                           &responseLen);
540     if (rc)
541     {
542         lg2::error("Failed to send SetTID for Endpoint {EID}, error {RC}",
543                    "EID", eid, "RC", rc);
544         co_return rc;
545     }
546 
547     if (responseMsg == nullptr || responseLen != PLDM_SET_TID_RESP_BYTES)
548     {
549         lg2::error(
550             "Failed to decode response SetTID for Endpoint ID {EID}, error {RC} ",
551             "EID", eid, "RC", rc);
552         co_return PLDM_ERROR_INVALID_LENGTH;
553     }
554 
555     co_return responseMsg->payload[0];
556 }
557 
getPLDMTypes(pldm_tid_t tid,uint64_t & supportedTypes)558 exec::task<int> TerminusManager::getPLDMTypes(pldm_tid_t tid,
559                                               uint64_t& supportedTypes)
560 {
561     Request request(sizeof(pldm_msg_hdr));
562     auto requestMsg = new (request.data()) pldm_msg;
563     auto rc = encode_get_types_req(0, requestMsg);
564     if (rc)
565     {
566         lg2::error(
567             "Failed to encode request getPLDMTypes for terminus ID {TID}, error {RC} ",
568             "TID", tid, "RC", rc);
569         co_return rc;
570     }
571 
572     const pldm_msg* responseMsg = nullptr;
573     size_t responseLen = 0;
574 
575     rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
576     if (rc)
577     {
578         lg2::error("Failed to send GetPLDMTypes for terminus {TID}, error {RC}",
579                    "TID", tid, "RC", rc);
580         co_return rc;
581     }
582 
583     uint8_t completionCode = 0;
584     bitfield8_t* types = reinterpret_cast<bitfield8_t*>(&supportedTypes);
585     rc =
586         decode_get_types_resp(responseMsg, responseLen, &completionCode, types);
587     if (rc)
588     {
589         lg2::error(
590             "Failed to decode response GetPLDMTypes for terminus ID {TID}, error {RC} ",
591             "TID", tid, "RC", rc);
592         co_return rc;
593     }
594 
595     if (completionCode != PLDM_SUCCESS)
596     {
597         lg2::error(
598             "Error : GetPLDMTypes for terminus ID {TID}, complete code {CC}.",
599             "TID", tid, "CC", completionCode);
600         co_return rc;
601     }
602     co_return completionCode;
603 }
604 
getPLDMCommands(pldm_tid_t tid,uint8_t type,ver32_t version,bitfield8_t * supportedCmds)605 exec::task<int> TerminusManager::getPLDMCommands(
606     pldm_tid_t tid, uint8_t type, ver32_t version, bitfield8_t* supportedCmds)
607 {
608     Request request(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES);
609     auto requestMsg = new (request.data()) pldm_msg;
610 
611     auto rc = encode_get_commands_req(0, type, version, requestMsg);
612     if (rc)
613     {
614         lg2::error(
615             "Failed to encode request GetPLDMCommands for terminus ID {TID}, error {RC} ",
616             "TID", tid, "RC", rc);
617         co_return rc;
618     }
619 
620     const pldm_msg* responseMsg = nullptr;
621     size_t responseLen = 0;
622 
623     rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
624     if (rc)
625     {
626         lg2::error(
627             "Failed to send GetPLDMCommands message for terminus {TID}, error {RC}",
628             "TID", tid, "RC", rc);
629         co_return rc;
630     }
631 
632     /* Process response */
633     uint8_t completionCode = 0;
634     rc = decode_get_commands_resp(responseMsg, responseLen, &completionCode,
635                                   supportedCmds);
636     if (rc)
637     {
638         lg2::error(
639             "Failed to decode response GetPLDMCommands for terminus ID {TID}, error {RC} ",
640             "TID", tid, "RC", rc);
641         co_return rc;
642     }
643 
644     if (completionCode != PLDM_SUCCESS)
645     {
646         lg2::error(
647             "Error : GetPLDMCommands for terminus ID {TID}, complete code {CC}.",
648             "TID", tid, "CC", completionCode);
649         co_return rc;
650     }
651 
652     co_return completionCode;
653 }
654 
sendRecvPldmMsg(pldm_tid_t tid,Request & request,const pldm_msg ** responseMsg,size_t * responseLen)655 exec::task<int> TerminusManager::sendRecvPldmMsg(
656     pldm_tid_t tid, Request& request, const pldm_msg** responseMsg,
657     size_t* responseLen)
658 {
659     /**
660      * Size of tidPool is `std::numeric_limits<pldm_tid_t>::max() + 1`
661      * tidPool[i] always exist
662      */
663     if (!tidPool[tid])
664     {
665         co_return PLDM_ERROR_NOT_READY;
666     }
667 
668     if (!transportLayerTable.contains(tid))
669     {
670         co_return PLDM_ERROR_NOT_READY;
671     }
672 
673     if (transportLayerTable[tid] != SupportedTransportLayer::MCTP)
674     {
675         co_return PLDM_ERROR_NOT_READY;
676     }
677 
678     auto mctpInfo = toMctpInfo(tid);
679     if (!mctpInfo.has_value())
680     {
681         co_return PLDM_ERROR_NOT_READY;
682     }
683 
684     // There's a cost of maintaining another table to hold availability
685     // status as we can't ensure that it always synchronizes with the
686     // mctpInfoTable; std::map operator[] will insert a default of boolean
687     // which is false to the mctpInfoAvailTable if the mctpInfo key doesn't
688     // exist. Once we miss to initialize the availability of an available
689     // endpoint, it will drop all the messages to/from it.
690     if (!mctpInfoAvailTable[mctpInfo.value()])
691     {
692         co_return PLDM_ERROR_NOT_READY;
693     }
694 
695     auto eid = std::get<0>(mctpInfo.value());
696     auto requestMsg = new (request.data()) pldm_msg;
697     requestMsg->hdr.instance_id = instanceIdDb.next(eid);
698     auto rc = co_await sendRecvPldmMsgOverMctp(eid, request, responseMsg,
699                                                responseLen);
700 
701     if (rc == PLDM_ERROR_NOT_READY)
702     {
703         // Call Recover() to check enpoint's availability
704         // Set endpoint's availability in mctpInfoTable to false in advance
705         // to prevent message forwarding through this endpoint while mctpd
706         // is checking the endpoint.
707         std::string endpointObjPath =
708             constructEndpointObjPath(mctpInfo.value());
709         pldm::utils::recoverMctpEndpoint(endpointObjPath);
710         updateMctpEndpointAvailability(mctpInfo.value(), false);
711     }
712 
713     co_return rc;
714 }
715 
getPLDMVersion(pldm_tid_t tid,uint8_t type,ver32_t * version)716 exec::task<int> TerminusManager::getPLDMVersion(pldm_tid_t tid, uint8_t type,
717                                                 ver32_t* version)
718 {
719     Request request(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_REQ_BYTES);
720     auto requestMsg = new (request.data()) pldm_msg;
721 
722     auto rc =
723         encode_get_version_req(0, 0, PLDM_GET_FIRSTPART, type, requestMsg);
724     if (rc)
725     {
726         lg2::error(
727             "Failed to encode request getPLDMVersion for terminus ID {TID}, error {RC} ",
728             "TID", tid, "RC", rc);
729         co_return rc;
730     }
731 
732     const pldm_msg* responseMsg = nullptr;
733     size_t responseLen = 0;
734 
735     rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
736     if (rc)
737     {
738         lg2::error(
739             "Failed to send getPLDMVersion message for terminus {TID}, error {RC}",
740             "TID", tid, "RC", rc);
741         co_return rc;
742     }
743 
744     /* Process response */
745     uint8_t completionCode = 0;
746     uint8_t transferFlag = 0;
747     uint32_t transferHandle = 0;
748     rc = decode_get_version_resp(responseMsg, responseLen, &completionCode,
749                                  &transferHandle, &transferFlag, version);
750     if (rc)
751     {
752         lg2::error(
753             "Failed to decode response getPLDMVersion for terminus ID {TID}, error {RC} ",
754             "TID", tid, "RC", rc);
755         co_return rc;
756     }
757 
758     if (completionCode != PLDM_SUCCESS)
759     {
760         lg2::error(
761             "Error : getPLDMVersion for terminus ID {TID}, complete code {CC}.",
762             "TID", tid, "CC", completionCode);
763         co_return completionCode;
764     }
765 
766     co_return completionCode;
767 }
768 
getActiveEidByName(const std::string & terminusName)769 std::optional<mctp_eid_t> TerminusManager::getActiveEidByName(
770     const std::string& terminusName)
771 {
772     if (!termini.size() || terminusName.empty())
773     {
774         return std::nullopt;
775     }
776 
777     for (auto& [tid, terminus] : termini)
778     {
779         if (!terminus)
780         {
781             continue;
782         }
783 
784         auto tmp = terminus->getTerminusName();
785         if (!tmp || std::empty(*tmp) || *tmp != terminusName)
786         {
787             continue;
788         }
789 
790         try
791         {
792             auto mctpInfo = toMctpInfo(tid);
793             if (!mctpInfo || !mctpInfoAvailTable[*mctpInfo])
794             {
795                 return std::nullopt;
796             }
797 
798             return std::get<0>(*mctpInfo);
799         }
800         catch (const std::exception& e)
801         {
802             return std::nullopt;
803         }
804     }
805 
806     return std::nullopt;
807 }
808 } // namespace platform_mc
809 } // namespace pldm
810