xref: /openbmc/pldm/platform-mc/terminus_manager.cpp (revision fdf61cc310dfe7bb56d007bf1026635081f44aca)
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     while (!queuedMctpInfos.empty())
190     {
191         if (manager)
192         {
193             co_await manager->beforeDiscoverTerminus();
194         }
195 
196         const MctpInfos& mctpInfos = queuedMctpInfos.front();
197         for (const auto& mctpInfo : mctpInfos)
198         {
199             auto it = findTerminusPtr(mctpInfo);
200             if (it == termini.end())
201             {
202                 mctpInfoAvailTable[mctpInfo] = true;
203                 co_await initMctpTerminus(mctpInfo);
204             }
205 
206             /* Get TID of initialized terminus */
207             auto tid = toTid(mctpInfo);
208             if (!tid)
209             {
210                 mctpInfoAvailTable.erase(mctpInfo);
211                 co_return PLDM_ERROR;
212             }
213             addedTids.push_back(tid.value());
214         }
215 
216         if (manager)
217         {
218             co_await manager->afterDiscoverTerminus();
219         }
220 
221         queuedMctpInfos.pop();
222     }
223 
224     co_return PLDM_SUCCESS;
225 }
226 
removeMctpTerminus(const MctpInfos & mctpInfos)227 void TerminusManager::removeMctpTerminus(const MctpInfos& mctpInfos)
228 {
229     // remove terminus
230     for (const auto& mctpInfo : mctpInfos)
231     {
232         auto it = findTerminusPtr(mctpInfo);
233         if (it == termini.end())
234         {
235             continue;
236         }
237 
238         if (manager)
239         {
240             manager->stopSensorPolling(it->second->getTid());
241         }
242 
243         unmapTid(it->first);
244         termini.erase(it);
245         mctpInfoAvailTable.erase(mctpInfo);
246     }
247 }
248 
initMctpTerminus(const MctpInfo & mctpInfo)249 exec::task<int> TerminusManager::initMctpTerminus(const MctpInfo& mctpInfo)
250 {
251     mctp_eid_t eid = std::get<0>(mctpInfo);
252     pldm_tid_t tid = 0;
253     bool isMapped = false;
254     auto rc = co_await getTidOverMctp(eid, &tid);
255     if (rc != PLDM_SUCCESS)
256     {
257         lg2::error("Failed to Get Terminus ID, error {ERROR}.", "ERROR", rc);
258         co_return PLDM_ERROR;
259     }
260 
261     if (tid == PLDM_TID_RESERVED)
262     {
263         lg2::error("Terminus responses the reserved {TID}.", "TID", tid);
264         co_return PLDM_ERROR;
265     }
266 
267     /* Terminus already has TID */
268     if (tid != PLDM_TID_UNASSIGNED)
269     {
270         /* TID is used by one discovered terminus */
271         auto it = termini.find(tid);
272         if (it != termini.end())
273         {
274             auto terminusMctpInfo = toMctpInfo(it->first);
275             /* The discovered terminus has the same MCTP Info */
276             if (terminusMctpInfo &&
277                 (std::get<0>(terminusMctpInfo.value()) ==
278                  std::get<0>(mctpInfo)) &&
279                 (std::get<3>(terminusMctpInfo.value()) ==
280                  std::get<3>(mctpInfo)))
281             {
282                 co_return PLDM_SUCCESS;
283             }
284             else
285             {
286                 /* ToDo:
287                  * Maybe the terminus supports multiple medium interfaces
288                  * Or the TID is used by other terminus.
289                  * Check the UUID to confirm.
290                  */
291                 isMapped = false;
292             }
293         }
294         /* Use the terminus TID for mapping */
295         else
296         {
297             auto mappedTid = storeTerminusInfo(mctpInfo, tid);
298             if (!mappedTid)
299             {
300                 lg2::error("Failed to store Terminus Info for terminus {TID}.",
301                            "TID", tid);
302                 co_return PLDM_ERROR;
303             }
304             isMapped = true;
305         }
306     }
307 
308     if (!isMapped)
309     {
310         // Assigning a tid. If it has been mapped, mapTid()
311         // returns the tid assigned before.
312         auto mappedTid = mapTid(mctpInfo);
313         if (!mappedTid)
314         {
315             lg2::error("Failed to store Terminus Info for terminus {TID}.",
316                        "TID", tid);
317             co_return PLDM_ERROR;
318         }
319 
320         tid = mappedTid.value();
321         rc = co_await setTidOverMctp(eid, tid);
322         if (rc != PLDM_SUCCESS)
323         {
324             lg2::error("Failed to Set terminus TID, error{ERROR}.", "ERROR",
325                        rc);
326             unmapTid(tid);
327             co_return rc;
328         }
329 
330         if (rc != PLDM_SUCCESS && rc != PLDM_ERROR_UNSUPPORTED_PLDM_CMD)
331         {
332             lg2::error("Terminus {TID} does not support SetTID command.", "TID",
333                        tid);
334             unmapTid(tid);
335             co_return rc;
336         }
337 
338         if (termini.contains(tid))
339         {
340             // the terminus has been discovered before
341             co_return PLDM_SUCCESS;
342         }
343     }
344     /* Discovery the mapped terminus */
345     uint64_t supportedTypes = 0;
346     rc = co_await getPLDMTypes(tid, supportedTypes);
347     if (rc)
348     {
349         lg2::error("Failed to Get PLDM Types for terminus {TID}, error {ERROR}",
350                    "TID", tid, "ERROR", rc);
351         unmapTid(tid);
352         co_return PLDM_ERROR;
353     }
354 
355     try
356     {
357         termini[tid] = std::make_shared<Terminus>(tid, supportedTypes, event);
358     }
359     catch (const sdbusplus::exception_t& e)
360     {
361         lg2::error("Failed to create terminus manager for terminus {TID}",
362                    "TID", tid);
363         unmapTid(tid);
364         co_return PLDM_ERROR;
365     }
366 
367     uint8_t type = PLDM_BASE;
368     auto size = PLDM_MAX_TYPES * (PLDM_MAX_CMDS_PER_TYPE / 8);
369     std::vector<uint8_t> pldmCmds(size);
370     while ((type < PLDM_MAX_TYPES))
371     {
372         if (!termini[tid]->doesSupportType(type))
373         {
374             type++;
375             continue;
376         }
377 
378         ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
379         auto rc = co_await getPLDMVersion(tid, type, &version);
380         if (rc)
381         {
382             lg2::error(
383                 "Failed to Get PLDM Version for terminus {TID}, PLDM Type {TYPE}, error {ERROR}",
384                 "TID", tid, "TYPE", type, "ERROR", rc);
385         }
386         termini[tid]->setSupportedTypeVersions(type, version);
387         std::vector<bitfield8_t> cmds(PLDM_MAX_CMDS_PER_TYPE / 8);
388         rc = co_await getPLDMCommands(tid, type, version, cmds.data());
389         if (rc)
390         {
391             lg2::error(
392                 "Failed to Get PLDM Commands for terminus {TID}, error {ERROR}",
393                 "TID", tid, "ERROR", rc);
394         }
395 
396         for (size_t i = 0; i < cmds.size(); i++)
397         {
398             auto idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + i;
399             if (idx >= pldmCmds.size())
400             {
401                 lg2::error(
402                     "Calculated index {IDX} out of bounds for pldmCmds, type {TYPE}, command index {CMD_IDX}",
403                     "IDX", idx, "TYPE", type, "CMD_IDX", i);
404                 continue;
405             }
406             pldmCmds[idx] = cmds[i].byte;
407         }
408         type++;
409     }
410     termini[tid]->setSupportedCommands(pldmCmds);
411 
412     co_return PLDM_SUCCESS;
413 }
414 
sendRecvPldmMsgOverMctp(mctp_eid_t eid,Request & request,const pldm_msg ** responseMsg,size_t * responseLen)415 exec::task<int> TerminusManager::sendRecvPldmMsgOverMctp(
416     mctp_eid_t eid, Request& request, const pldm_msg** responseMsg,
417     size_t* responseLen)
418 {
419     int rc = 0;
420     try
421     {
422         std::tie(rc, *responseMsg, *responseLen) =
423             co_await handler.sendRecvMsg(eid, std::move(request));
424     }
425     catch (const sdbusplus::exception_t& e)
426     {
427         lg2::error(
428             "Send and Receive PLDM message over MCTP throw error - {ERROR}.",
429             "ERROR", e);
430         co_return PLDM_ERROR;
431     }
432     catch (const int& e)
433     {
434         lg2::error(
435             "Send and Receive PLDM message over MCTP throw int error - {ERROR}.",
436             "ERROR", e);
437         co_return PLDM_ERROR;
438     }
439 
440     co_return rc;
441 }
442 
getTidOverMctp(mctp_eid_t eid,pldm_tid_t * tid)443 exec::task<int> TerminusManager::getTidOverMctp(mctp_eid_t eid, pldm_tid_t* tid)
444 {
445     auto instanceId = instanceIdDb.next(eid);
446     Request request(sizeof(pldm_msg_hdr));
447     auto requestMsg = new (request.data()) pldm_msg;
448     auto rc = encode_get_tid_req(instanceId, requestMsg);
449     if (rc)
450     {
451         instanceIdDb.free(eid, instanceId);
452         lg2::error(
453             "Failed to encode request GetTID for endpoint ID {EID}, error {RC} ",
454             "EID", eid, "RC", rc);
455         co_return rc;
456     }
457 
458     const pldm_msg* responseMsg = nullptr;
459     size_t responseLen = 0;
460     rc = co_await sendRecvPldmMsgOverMctp(eid, request, &responseMsg,
461                                           &responseLen);
462     if (rc)
463     {
464         lg2::error("Failed to send GetTID for Endpoint {EID}, error {RC}",
465                    "EID", eid, "RC", rc);
466         co_return rc;
467     }
468 
469     uint8_t completionCode = 0;
470     rc = decode_get_tid_resp(responseMsg, responseLen, &completionCode, tid);
471     if (rc)
472     {
473         lg2::error(
474             "Failed to decode response GetTID for Endpoint ID {EID}, error {RC} ",
475             "EID", eid, "RC", rc);
476         co_return rc;
477     }
478 
479     if (completionCode != PLDM_SUCCESS)
480     {
481         lg2::error("Error : GetTID for Endpoint ID {EID}, complete code {CC}.",
482                    "EID", eid, "CC", completionCode);
483         co_return rc;
484     }
485 
486     co_return completionCode;
487 }
488 
setTidOverMctp(mctp_eid_t eid,pldm_tid_t tid)489 exec::task<int> TerminusManager::setTidOverMctp(mctp_eid_t eid, pldm_tid_t tid)
490 {
491     auto instanceId = instanceIdDb.next(eid);
492     Request request(sizeof(pldm_msg_hdr) + sizeof(pldm_set_tid_req));
493     auto requestMsg = new (request.data()) pldm_msg;
494     auto rc = encode_set_tid_req(instanceId, tid, requestMsg);
495     if (rc)
496     {
497         instanceIdDb.free(eid, instanceId);
498         lg2::error(
499             "Failed to encode request SetTID for endpoint ID {EID}, error {RC} ",
500             "EID", eid, "RC", rc);
501         co_return rc;
502     }
503 
504     const pldm_msg* responseMsg = nullptr;
505     size_t responseLen = 0;
506     rc = co_await sendRecvPldmMsgOverMctp(eid, request, &responseMsg,
507                                           &responseLen);
508     if (rc)
509     {
510         lg2::error("Failed to send SetTID for Endpoint {EID}, error {RC}",
511                    "EID", eid, "RC", rc);
512         co_return rc;
513     }
514 
515     if (responseMsg == nullptr || responseLen != PLDM_SET_TID_RESP_BYTES)
516     {
517         lg2::error(
518             "Failed to decode response SetTID for Endpoint ID {EID}, error {RC} ",
519             "EID", eid, "RC", rc);
520         co_return PLDM_ERROR_INVALID_LENGTH;
521     }
522 
523     co_return responseMsg->payload[0];
524 }
525 
getPLDMTypes(pldm_tid_t tid,uint64_t & supportedTypes)526 exec::task<int> TerminusManager::getPLDMTypes(pldm_tid_t tid,
527                                               uint64_t& supportedTypes)
528 {
529     Request request(sizeof(pldm_msg_hdr));
530     auto requestMsg = new (request.data()) pldm_msg;
531     auto rc = encode_get_types_req(0, requestMsg);
532     if (rc)
533     {
534         lg2::error(
535             "Failed to encode request getPLDMTypes for terminus ID {TID}, error {RC} ",
536             "TID", tid, "RC", rc);
537         co_return rc;
538     }
539 
540     const pldm_msg* responseMsg = nullptr;
541     size_t responseLen = 0;
542 
543     rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
544     if (rc)
545     {
546         lg2::error("Failed to send GetPLDMTypes for terminus {TID}, error {RC}",
547                    "TID", tid, "RC", rc);
548         co_return rc;
549     }
550 
551     uint8_t completionCode = 0;
552     bitfield8_t* types = reinterpret_cast<bitfield8_t*>(&supportedTypes);
553     rc =
554         decode_get_types_resp(responseMsg, responseLen, &completionCode, types);
555     if (rc)
556     {
557         lg2::error(
558             "Failed to decode response GetPLDMTypes for terminus ID {TID}, error {RC} ",
559             "TID", tid, "RC", rc);
560         co_return rc;
561     }
562 
563     if (completionCode != PLDM_SUCCESS)
564     {
565         lg2::error(
566             "Error : GetPLDMTypes for terminus ID {TID}, complete code {CC}.",
567             "TID", tid, "CC", completionCode);
568         co_return rc;
569     }
570     co_return completionCode;
571 }
572 
getPLDMCommands(pldm_tid_t tid,uint8_t type,ver32_t version,bitfield8_t * supportedCmds)573 exec::task<int> TerminusManager::getPLDMCommands(
574     pldm_tid_t tid, uint8_t type, ver32_t version, bitfield8_t* supportedCmds)
575 {
576     Request request(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES);
577     auto requestMsg = new (request.data()) pldm_msg;
578 
579     auto rc = encode_get_commands_req(0, type, version, requestMsg);
580     if (rc)
581     {
582         lg2::error(
583             "Failed to encode request GetPLDMCommands for terminus ID {TID}, error {RC} ",
584             "TID", tid, "RC", rc);
585         co_return rc;
586     }
587 
588     const pldm_msg* responseMsg = nullptr;
589     size_t responseLen = 0;
590 
591     rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
592     if (rc)
593     {
594         lg2::error(
595             "Failed to send GetPLDMCommands message for terminus {TID}, error {RC}",
596             "TID", tid, "RC", rc);
597         co_return rc;
598     }
599 
600     /* Process response */
601     uint8_t completionCode = 0;
602     rc = decode_get_commands_resp(responseMsg, responseLen, &completionCode,
603                                   supportedCmds);
604     if (rc)
605     {
606         lg2::error(
607             "Failed to decode response GetPLDMCommands for terminus ID {TID}, error {RC} ",
608             "TID", tid, "RC", rc);
609         co_return rc;
610     }
611 
612     if (completionCode != PLDM_SUCCESS)
613     {
614         lg2::error(
615             "Error : GetPLDMCommands for terminus ID {TID}, complete code {CC}.",
616             "TID", tid, "CC", completionCode);
617         co_return rc;
618     }
619 
620     co_return completionCode;
621 }
622 
sendRecvPldmMsg(pldm_tid_t tid,Request & request,const pldm_msg ** responseMsg,size_t * responseLen)623 exec::task<int> TerminusManager::sendRecvPldmMsg(
624     pldm_tid_t tid, Request& request, const pldm_msg** responseMsg,
625     size_t* responseLen)
626 {
627     /**
628      * Size of tidPool is `std::numeric_limits<pldm_tid_t>::max() + 1`
629      * tidPool[i] always exist
630      */
631     if (!tidPool[tid])
632     {
633         co_return PLDM_ERROR_NOT_READY;
634     }
635 
636     if (!transportLayerTable.contains(tid))
637     {
638         co_return PLDM_ERROR_NOT_READY;
639     }
640 
641     if (transportLayerTable[tid] != SupportedTransportLayer::MCTP)
642     {
643         co_return PLDM_ERROR_NOT_READY;
644     }
645 
646     auto mctpInfo = toMctpInfo(tid);
647     if (!mctpInfo.has_value())
648     {
649         co_return PLDM_ERROR_NOT_READY;
650     }
651 
652     // There's a cost of maintaining another table to hold availability
653     // status as we can't ensure that it always synchronizes with the
654     // mctpInfoTable; std::map operator[] will insert a default of boolean
655     // which is false to the mctpInfoAvailTable if the mctpInfo key doesn't
656     // exist. Once we miss to initialize the availability of an available
657     // endpoint, it will drop all the messages to/from it.
658     if (!mctpInfoAvailTable[mctpInfo.value()])
659     {
660         co_return PLDM_ERROR_NOT_READY;
661     }
662 
663     auto eid = std::get<0>(mctpInfo.value());
664     auto requestMsg = new (request.data()) pldm_msg;
665     requestMsg->hdr.instance_id = instanceIdDb.next(eid);
666     auto rc = co_await sendRecvPldmMsgOverMctp(eid, request, responseMsg,
667                                                responseLen);
668 
669     if (rc == PLDM_ERROR_NOT_READY)
670     {
671         // Call Recover() to check enpoint's availability
672         // Set endpoint's availability in mctpInfoTable to false in advance
673         // to prevent message forwarding through this endpoint while mctpd
674         // is checking the endpoint.
675         std::string endpointObjPath =
676             constructEndpointObjPath(mctpInfo.value());
677         pldm::utils::recoverMctpEndpoint(endpointObjPath);
678         updateMctpEndpointAvailability(mctpInfo.value(), false);
679     }
680 
681     co_return rc;
682 }
683 
getPLDMVersion(pldm_tid_t tid,uint8_t type,ver32_t * version)684 exec::task<int> TerminusManager::getPLDMVersion(pldm_tid_t tid, uint8_t type,
685                                                 ver32_t* version)
686 {
687     Request request(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_REQ_BYTES);
688     auto requestMsg = new (request.data()) pldm_msg;
689 
690     auto rc =
691         encode_get_version_req(0, 0, PLDM_GET_FIRSTPART, type, requestMsg);
692     if (rc)
693     {
694         lg2::error(
695             "Failed to encode request getPLDMVersion for terminus ID {TID}, error {RC} ",
696             "TID", tid, "RC", rc);
697         co_return rc;
698     }
699 
700     const pldm_msg* responseMsg = nullptr;
701     size_t responseLen = 0;
702 
703     rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
704     if (rc)
705     {
706         lg2::error(
707             "Failed to send getPLDMVersion message for terminus {TID}, error {RC}",
708             "TID", tid, "RC", rc);
709         co_return rc;
710     }
711 
712     /* Process response */
713     uint8_t completionCode = 0;
714     uint8_t transferFlag = 0;
715     uint32_t transferHandle = 0;
716     rc = decode_get_version_resp(responseMsg, responseLen, &completionCode,
717                                  &transferHandle, &transferFlag, version);
718     if (rc)
719     {
720         lg2::error(
721             "Failed to decode response getPLDMVersion for terminus ID {TID}, error {RC} ",
722             "TID", tid, "RC", rc);
723         co_return rc;
724     }
725 
726     if (completionCode != PLDM_SUCCESS)
727     {
728         lg2::error(
729             "Error : getPLDMVersion for terminus ID {TID}, complete code {CC}.",
730             "TID", tid, "CC", completionCode);
731         co_return completionCode;
732     }
733 
734     co_return completionCode;
735 }
736 
getActiveEidByName(const std::string & terminusName)737 std::optional<mctp_eid_t> TerminusManager::getActiveEidByName(
738     const std::string& terminusName)
739 {
740     if (!termini.size() || terminusName.empty())
741     {
742         return std::nullopt;
743     }
744 
745     for (auto& [tid, terminus] : termini)
746     {
747         if (!terminus)
748         {
749             continue;
750         }
751 
752         auto tmp = terminus->getTerminusName();
753         if (!tmp || std::empty(*tmp) || *tmp != terminusName)
754         {
755             continue;
756         }
757 
758         try
759         {
760             auto mctpInfo = toMctpInfo(tid);
761             if (!mctpInfo || !mctpInfoAvailTable[*mctpInfo])
762             {
763                 return std::nullopt;
764             }
765 
766             return std::get<0>(*mctpInfo);
767         }
768         catch (const std::exception& e)
769         {
770             return std::nullopt;
771         }
772     }
773 
774     return std::nullopt;
775 }
776 } // namespace platform_mc
777 } // namespace pldm
778