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