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