xref: /openbmc/pldm/platform-mc/terminus_manager.cpp (revision 366507c82a4781c4a893ab9b9ca7b38f2157a353)
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  
discoverMctpTerminus(const MctpInfos & mctpInfos)128  void TerminusManager::discoverMctpTerminus(const MctpInfos& mctpInfos)
129  {
130      queuedMctpInfos.emplace(mctpInfos);
131      if (discoverMctpTerminusTaskHandle.has_value())
132      {
133          auto& [scope, rcOpt] = *discoverMctpTerminusTaskHandle;
134          if (!rcOpt.has_value())
135          {
136              return;
137          }
138          stdexec::sync_wait(scope.on_empty());
139          discoverMctpTerminusTaskHandle.reset();
140      }
141      auto& [scope, rcOpt] = discoverMctpTerminusTaskHandle.emplace();
142      scope.spawn(discoverMctpTerminusTask() |
143                      stdexec::then([&](int rc) { rcOpt.emplace(rc); }),
144                  exec::default_task_context<void>(exec::inline_scheduler{}));
145  }
146  
findTerminusPtr(const MctpInfo & mctpInfo)147  TerminiMapper::iterator TerminusManager::findTerminusPtr(
148      const MctpInfo& mctpInfo)
149  {
150      auto foundIter = std::find_if(
151          termini.begin(), termini.end(), [&](const auto& terminusPair) {
152              auto terminusMctpInfo = toMctpInfo(terminusPair.first);
153              return (terminusMctpInfo &&
154                      (std::get<0>(terminusMctpInfo.value()) ==
155                       std::get<0>(mctpInfo)) &&
156                      (std::get<3>(terminusMctpInfo.value()) ==
157                       std::get<3>(mctpInfo)));
158          });
159  
160      return foundIter;
161  }
162  
discoverMctpTerminusTask()163  exec::task<int> TerminusManager::discoverMctpTerminusTask()
164  {
165      std::vector<pldm_tid_t> addedTids;
166      while (!queuedMctpInfos.empty())
167      {
168          if (manager)
169          {
170              co_await manager->beforeDiscoverTerminus();
171          }
172  
173          const MctpInfos& mctpInfos = queuedMctpInfos.front();
174          for (const auto& mctpInfo : mctpInfos)
175          {
176              auto it = findTerminusPtr(mctpInfo);
177              if (it == termini.end())
178              {
179                  co_await initMctpTerminus(mctpInfo);
180              }
181  
182              /* Get TID of initialized terminus */
183              auto tid = toTid(mctpInfo);
184              if (!tid)
185              {
186                  co_return PLDM_ERROR;
187              }
188              addedTids.push_back(tid.value());
189          }
190  
191          if (manager)
192          {
193              co_await manager->afterDiscoverTerminus();
194              for (const auto& tid : addedTids)
195              {
196                  manager->startSensorPolling(tid);
197              }
198          }
199  
200          queuedMctpInfos.pop();
201      }
202  
203      co_return PLDM_SUCCESS;
204  }
205  
removeMctpTerminus(const MctpInfos & mctpInfos)206  void TerminusManager::removeMctpTerminus(const MctpInfos& mctpInfos)
207  {
208      // remove terminus
209      for (const auto& mctpInfo : mctpInfos)
210      {
211          auto it = findTerminusPtr(mctpInfo);
212          if (it == termini.end())
213          {
214              continue;
215          }
216  
217          if (manager)
218          {
219              manager->stopSensorPolling(it->second->getTid());
220          }
221  
222          unmapTid(it->first);
223          termini.erase(it);
224      }
225  }
226  
initMctpTerminus(const MctpInfo & mctpInfo)227  exec::task<int> TerminusManager::initMctpTerminus(const MctpInfo& mctpInfo)
228  {
229      mctp_eid_t eid = std::get<0>(mctpInfo);
230      pldm_tid_t tid = 0;
231      bool isMapped = false;
232      auto rc = co_await getTidOverMctp(eid, &tid);
233      if (rc != PLDM_SUCCESS)
234      {
235          lg2::error("Failed to Get Terminus ID, error {ERROR}.", "ERROR", rc);
236          co_return PLDM_ERROR;
237      }
238  
239      if (tid == PLDM_TID_RESERVED)
240      {
241          lg2::error("Terminus responses the reserved {TID}.", "TID", tid);
242          co_return PLDM_ERROR;
243      }
244  
245      /* Terminus already has TID */
246      if (tid != PLDM_TID_UNASSIGNED)
247      {
248          /* TID is used by one discovered terminus */
249          auto it = termini.find(tid);
250          if (it != termini.end())
251          {
252              auto terminusMctpInfo = toMctpInfo(it->first);
253              /* The discovered terminus has the same MCTP Info */
254              if (terminusMctpInfo &&
255                  (std::get<0>(terminusMctpInfo.value()) ==
256                   std::get<0>(mctpInfo)) &&
257                  (std::get<3>(terminusMctpInfo.value()) ==
258                   std::get<3>(mctpInfo)))
259              {
260                  co_return PLDM_SUCCESS;
261              }
262              else
263              {
264                  /* ToDo:
265                   * Maybe the terminus supports multiple medium interfaces
266                   * Or the TID is used by other terminus.
267                   * Check the UUID to confirm.
268                   */
269                  isMapped = false;
270              }
271          }
272          /* Use the terminus TID for mapping */
273          else
274          {
275              auto mappedTid = storeTerminusInfo(mctpInfo, tid);
276              if (!mappedTid)
277              {
278                  lg2::error("Failed to store Terminus Info for terminus {TID}.",
279                             "TID", tid);
280                  co_return PLDM_ERROR;
281              }
282              isMapped = true;
283          }
284      }
285  
286      if (!isMapped)
287      {
288          // Assigning a tid. If it has been mapped, mapTid()
289          // returns the tid assigned before.
290          auto mappedTid = mapTid(mctpInfo);
291          if (!mappedTid)
292          {
293              lg2::error("Failed to store Terminus Info for terminus {TID}.",
294                         "TID", tid);
295              co_return PLDM_ERROR;
296          }
297  
298          tid = mappedTid.value();
299          rc = co_await setTidOverMctp(eid, tid);
300          if (rc != PLDM_SUCCESS)
301          {
302              lg2::error("Failed to Set terminus TID, error{ERROR}.", "ERROR",
303                         rc);
304              unmapTid(tid);
305              co_return rc;
306          }
307  
308          if (rc != PLDM_SUCCESS && rc != PLDM_ERROR_UNSUPPORTED_PLDM_CMD)
309          {
310              lg2::error("Terminus {TID} does not support SetTID command.", "TID",
311                         tid);
312              unmapTid(tid);
313              co_return rc;
314          }
315  
316          if (termini.contains(tid))
317          {
318              // the terminus has been discovered before
319              co_return PLDM_SUCCESS;
320          }
321      }
322      /* Discovery the mapped terminus */
323      uint64_t supportedTypes = 0;
324      rc = co_await getPLDMTypes(tid, supportedTypes);
325      if (rc)
326      {
327          lg2::error("Failed to Get PLDM Types for terminus {TID}, error {ERROR}",
328                     "TID", tid, "ERROR", rc);
329          unmapTid(tid);
330          co_return PLDM_ERROR;
331      }
332  
333      try
334      {
335          termini[tid] = std::make_shared<Terminus>(tid, supportedTypes);
336      }
337      catch (const sdbusplus::exception_t& e)
338      {
339          lg2::error("Failed to create terminus manager for terminus {TID}",
340                     "TID", tid);
341          unmapTid(tid);
342          co_return PLDM_ERROR;
343      }
344  
345      uint8_t type = PLDM_BASE;
346      auto size = PLDM_MAX_TYPES * (PLDM_MAX_CMDS_PER_TYPE / 8);
347      std::vector<uint8_t> pldmCmds(size);
348      while ((type < PLDM_MAX_TYPES))
349      {
350          if (!termini[tid]->doesSupportType(type))
351          {
352              type++;
353              continue;
354          }
355  
356          ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
357          auto rc = co_await getPLDMVersion(tid, type, &version);
358          if (rc)
359          {
360              lg2::error(
361                  "Failed to Get PLDM Version for terminus {TID}, PLDM Type {TYPE}, error {ERROR}",
362                  "TID", tid, "TYPE", type, "ERROR", rc);
363          }
364          termini[tid]->setSupportedTypeVersions(type, version);
365          std::vector<bitfield8_t> cmds(PLDM_MAX_CMDS_PER_TYPE / 8);
366          rc = co_await getPLDMCommands(tid, type, version, cmds.data());
367          if (rc)
368          {
369              lg2::error(
370                  "Failed to Get PLDM Commands for terminus {TID}, error {ERROR}",
371                  "TID", tid, "ERROR", rc);
372          }
373  
374          for (size_t i = 0; i < cmds.size(); i++)
375          {
376              auto idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + i;
377              if (idx >= pldmCmds.size())
378              {
379                  lg2::error(
380                      "Calculated index {IDX} out of bounds for pldmCmds, type {TYPE}, command index {CMD_IDX}",
381                      "IDX", idx, "TYPE", type, "CMD_IDX", i);
382                  continue;
383              }
384              pldmCmds[idx] = cmds[i].byte;
385          }
386          type++;
387      }
388      termini[tid]->setSupportedCommands(pldmCmds);
389  
390      co_return PLDM_SUCCESS;
391  }
392  
sendRecvPldmMsgOverMctp(mctp_eid_t eid,Request & request,const pldm_msg ** responseMsg,size_t * responseLen)393  exec::task<int> TerminusManager::sendRecvPldmMsgOverMctp(
394      mctp_eid_t eid, Request& request, const pldm_msg** responseMsg,
395      size_t* responseLen)
396  {
397      int rc = 0;
398      try
399      {
400          std::tie(rc, *responseMsg, *responseLen) =
401              co_await handler.sendRecvMsg(eid, std::move(request));
402      }
403      catch (const sdbusplus::exception_t& e)
404      {
405          lg2::error(
406              "Send and Receive PLDM message over MCTP throw error - {ERROR}.",
407              "ERROR", e);
408          co_return PLDM_ERROR;
409      }
410      catch (const int& e)
411      {
412          lg2::error(
413              "Send and Receive PLDM message over MCTP throw int error - {ERROR}.",
414              "ERROR", e);
415          co_return PLDM_ERROR;
416      }
417  
418      co_return rc;
419  }
420  
getTidOverMctp(mctp_eid_t eid,pldm_tid_t * tid)421  exec::task<int> TerminusManager::getTidOverMctp(mctp_eid_t eid, pldm_tid_t* tid)
422  {
423      auto instanceId = instanceIdDb.next(eid);
424      Request request(sizeof(pldm_msg_hdr));
425      auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
426      auto rc = encode_get_tid_req(instanceId, requestMsg);
427      if (rc)
428      {
429          instanceIdDb.free(eid, instanceId);
430          lg2::error(
431              "Failed to encode request GetTID for endpoint ID {EID}, error {RC} ",
432              "EID", eid, "RC", rc);
433          co_return rc;
434      }
435  
436      const pldm_msg* responseMsg = nullptr;
437      size_t responseLen = 0;
438      rc = co_await sendRecvPldmMsgOverMctp(eid, request, &responseMsg,
439                                            &responseLen);
440      if (rc)
441      {
442          lg2::error("Failed to send GetTID for Endpoint {EID}, error {RC}",
443                     "EID", eid, "RC", rc);
444          co_return rc;
445      }
446  
447      uint8_t completionCode = 0;
448      rc = decode_get_tid_resp(responseMsg, responseLen, &completionCode, tid);
449      if (rc)
450      {
451          lg2::error(
452              "Failed to decode response GetTID for Endpoint ID {EID}, error {RC} ",
453              "EID", eid, "RC", rc);
454          co_return rc;
455      }
456  
457      if (completionCode != PLDM_SUCCESS)
458      {
459          lg2::error("Error : GetTID for Endpoint ID {EID}, complete code {CC}.",
460                     "EID", eid, "CC", completionCode);
461          co_return rc;
462      }
463  
464      co_return completionCode;
465  }
466  
setTidOverMctp(mctp_eid_t eid,pldm_tid_t tid)467  exec::task<int> TerminusManager::setTidOverMctp(mctp_eid_t eid, pldm_tid_t tid)
468  {
469      auto instanceId = instanceIdDb.next(eid);
470      Request request(sizeof(pldm_msg_hdr) + sizeof(pldm_set_tid_req));
471      auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
472      auto rc = encode_set_tid_req(instanceId, tid, requestMsg);
473      if (rc)
474      {
475          instanceIdDb.free(eid, instanceId);
476          lg2::error(
477              "Failed to encode request SetTID for endpoint ID {EID}, error {RC} ",
478              "EID", eid, "RC", rc);
479          co_return rc;
480      }
481  
482      const pldm_msg* responseMsg = nullptr;
483      size_t responseLen = 0;
484      rc = co_await sendRecvPldmMsgOverMctp(eid, request, &responseMsg,
485                                            &responseLen);
486      if (rc)
487      {
488          lg2::error("Failed to send SetTID for Endpoint {EID}, error {RC}",
489                     "EID", eid, "RC", rc);
490          co_return rc;
491      }
492  
493      if (responseMsg == nullptr || responseLen != PLDM_SET_TID_RESP_BYTES)
494      {
495          lg2::error(
496              "Failed to decode response SetTID for Endpoint ID {EID}, error {RC} ",
497              "EID", eid, "RC", rc);
498          co_return PLDM_ERROR_INVALID_LENGTH;
499      }
500  
501      co_return responseMsg->payload[0];
502  }
503  
getPLDMTypes(pldm_tid_t tid,uint64_t & supportedTypes)504  exec::task<int> TerminusManager::getPLDMTypes(pldm_tid_t tid,
505                                                uint64_t& supportedTypes)
506  {
507      Request request(sizeof(pldm_msg_hdr));
508      auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
509      auto rc = encode_get_types_req(0, requestMsg);
510      if (rc)
511      {
512          lg2::error(
513              "Failed to encode request getPLDMTypes for terminus ID {TID}, error {RC} ",
514              "TID", tid, "RC", rc);
515          co_return rc;
516      }
517  
518      const pldm_msg* responseMsg = nullptr;
519      size_t responseLen = 0;
520  
521      rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
522      if (rc)
523      {
524          lg2::error("Failed to send GetPLDMTypes for terminus {TID}, error {RC}",
525                     "TID", tid, "RC", rc);
526          co_return rc;
527      }
528  
529      uint8_t completionCode = 0;
530      bitfield8_t* types = reinterpret_cast<bitfield8_t*>(&supportedTypes);
531      rc =
532          decode_get_types_resp(responseMsg, responseLen, &completionCode, types);
533      if (rc)
534      {
535          lg2::error(
536              "Failed to decode response GetPLDMTypes for terminus ID {TID}, error {RC} ",
537              "TID", tid, "RC", rc);
538          co_return rc;
539      }
540  
541      if (completionCode != PLDM_SUCCESS)
542      {
543          lg2::error(
544              "Error : GetPLDMTypes for terminus ID {TID}, complete code {CC}.",
545              "TID", tid, "CC", completionCode);
546          co_return rc;
547      }
548      co_return completionCode;
549  }
550  
getPLDMCommands(pldm_tid_t tid,uint8_t type,ver32_t version,bitfield8_t * supportedCmds)551  exec::task<int> TerminusManager::getPLDMCommands(
552      pldm_tid_t tid, uint8_t type, ver32_t version, bitfield8_t* supportedCmds)
553  {
554      Request request(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES);
555      auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
556  
557      auto rc = encode_get_commands_req(0, type, version, requestMsg);
558      if (rc)
559      {
560          lg2::error(
561              "Failed to encode request GetPLDMCommands for terminus ID {TID}, error {RC} ",
562              "TID", tid, "RC", rc);
563          co_return rc;
564      }
565  
566      const pldm_msg* responseMsg = nullptr;
567      size_t responseLen = 0;
568  
569      rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
570      if (rc)
571      {
572          lg2::error(
573              "Failed to send GetPLDMCommands message for terminus {TID}, error {RC}",
574              "TID", tid, "RC", rc);
575          co_return rc;
576      }
577  
578      /* Process response */
579      uint8_t completionCode = 0;
580      rc = decode_get_commands_resp(responseMsg, responseLen, &completionCode,
581                                    supportedCmds);
582      if (rc)
583      {
584          lg2::error(
585              "Failed to decode response GetPLDMCommands for terminus ID {TID}, error {RC} ",
586              "TID", tid, "RC", rc);
587          co_return rc;
588      }
589  
590      if (completionCode != PLDM_SUCCESS)
591      {
592          lg2::error(
593              "Error : GetPLDMCommands for terminus ID {TID}, complete code {CC}.",
594              "TID", tid, "CC", completionCode);
595          co_return rc;
596      }
597  
598      co_return completionCode;
599  }
600  
sendRecvPldmMsg(pldm_tid_t tid,Request & request,const pldm_msg ** responseMsg,size_t * responseLen)601  exec::task<int> TerminusManager::sendRecvPldmMsg(
602      pldm_tid_t tid, Request& request, const pldm_msg** responseMsg,
603      size_t* responseLen)
604  {
605      /**
606       * Size of tidPool is `std::numeric_limits<pldm_tid_t>::max() + 1`
607       * tidPool[i] always exist
608       */
609      if (!tidPool[tid])
610      {
611          co_return PLDM_ERROR_NOT_READY;
612      }
613  
614      if (!transportLayerTable.contains(tid))
615      {
616          co_return PLDM_ERROR_NOT_READY;
617      }
618  
619      if (transportLayerTable[tid] != SupportedTransportLayer::MCTP)
620      {
621          co_return PLDM_ERROR_NOT_READY;
622      }
623  
624      auto mctpInfo = toMctpInfo(tid);
625      if (!mctpInfo.has_value())
626      {
627          co_return PLDM_ERROR_NOT_READY;
628      }
629  
630      auto eid = std::get<0>(mctpInfo.value());
631      auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
632      requestMsg->hdr.instance_id = instanceIdDb.next(eid);
633      auto rc = co_await sendRecvPldmMsgOverMctp(eid, request, responseMsg,
634                                                 responseLen);
635  
636      co_return rc;
637  }
638  
getPLDMVersion(pldm_tid_t tid,uint8_t type,ver32_t * version)639  exec::task<int> TerminusManager::getPLDMVersion(pldm_tid_t tid, uint8_t type,
640                                                  ver32_t* version)
641  {
642      Request request(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_REQ_BYTES);
643      auto requestMsg = new (request.data()) pldm_msg;
644  
645      auto rc =
646          encode_get_version_req(0, 0, PLDM_GET_FIRSTPART, type, requestMsg);
647      if (rc)
648      {
649          lg2::error(
650              "Failed to encode request getPLDMVersion for terminus ID {TID}, error {RC} ",
651              "TID", tid, "RC", rc);
652          co_return rc;
653      }
654  
655      const pldm_msg* responseMsg = nullptr;
656      size_t responseLen = 0;
657  
658      rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
659      if (rc)
660      {
661          lg2::error(
662              "Failed to send getPLDMVersion message for terminus {TID}, error {RC}",
663              "TID", tid, "RC", rc);
664          co_return rc;
665      }
666  
667      /* Process response */
668      uint8_t completionCode = 0;
669      uint8_t transferFlag = 0;
670      uint32_t transferHandle = 0;
671      rc = decode_get_version_resp(responseMsg, responseLen, &completionCode,
672                                   &transferHandle, &transferFlag, version);
673      if (rc)
674      {
675          lg2::error(
676              "Failed to decode response getPLDMVersion for terminus ID {TID}, error {RC} ",
677              "TID", tid, "RC", rc);
678          co_return rc;
679      }
680  
681      if (completionCode != PLDM_SUCCESS)
682      {
683          lg2::error(
684              "Error : getPLDMVersion for terminus ID {TID}, complete code {CC}.",
685              "TID", tid, "CC", completionCode);
686          co_return completionCode;
687      }
688  
689      co_return completionCode;
690  }
691  
692  } // namespace platform_mc
693  } // namespace pldm
694