blob: 7567d893301dbae68d7874d28964708ebd4ff37f [file] [log] [blame]
Gilbert Chen6c7fed42022-02-22 15:40:17 +00001#include "terminus_manager.hpp"
2
3#include "manager.hpp"
4
5#include <phosphor-logging/lg2.hpp>
6
7PHOSPHOR_LOG2_USING;
8
9namespace pldm
10{
11namespace platform_mc
12{
13
14std::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
36std::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) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -040045 return (std::get<0>(v.second) == std::get<0>(mctpInfo)) &&
46 (std::get<3>(v.second) == std::get<3>(mctpInfo));
47 });
Gilbert Chen6c7fed42022-02-22 15:40:17 +000048 if (mctpInfoTableIt == mctpInfoTable.end())
49 {
50 return std::nullopt;
51 }
52 return mctpInfoTableIt->first;
53}
54
55std::optional<pldm_tid_t>
56 TerminusManager::storeTerminusInfo(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
80std::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) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -040089 return (std::get<0>(v.second) == std::get<0>(mctpInfo)) &&
90 (std::get<3>(v.second) == std::get<3>(mctpInfo));
91 });
Gilbert Chen6c7fed42022-02-22 15:40:17 +000092 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
107bool 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
128void 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); }),
Patrick Williams61be7342024-07-30 16:55:33 -0500144 exec::default_task_context<void>(exec::inline_scheduler{}));
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000145}
146
Manojkiran Edaef5c4eb2024-07-25 22:36:41 +0530147TerminiMapper::iterator
148 TerminusManager::findTerminusPtr(const MctpInfo& mctpInfo)
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000149{
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400150 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 });
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000159
160 return foundIter;
161}
162
163exec::task<int> TerminusManager::discoverMctpTerminusTask()
164{
165 while (!queuedMctpInfos.empty())
166 {
167 if (manager)
168 {
169 co_await manager->beforeDiscoverTerminus();
170 }
171
172 const MctpInfos& mctpInfos = queuedMctpInfos.front();
173 for (const auto& mctpInfo : mctpInfos)
174 {
Patrick Williams29d2f4a2024-07-13 16:44:15 -0500175 auto it = findTerminusPtr(mctpInfo);
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000176 if (it == termini.end())
177 {
178 co_await initMctpTerminus(mctpInfo);
179 }
180 }
181
182 if (manager)
183 {
184 co_await manager->afterDiscoverTerminus();
185 }
186
187 queuedMctpInfos.pop();
188 }
189
190 co_return PLDM_SUCCESS;
191}
192
193void TerminusManager::removeMctpTerminus(const MctpInfos& mctpInfos)
194{
195 // remove terminus
196 for (const auto& mctpInfo : mctpInfos)
197 {
Patrick Williams29d2f4a2024-07-13 16:44:15 -0500198 auto it = findTerminusPtr(mctpInfo);
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000199 if (it == termini.end())
200 {
201 continue;
202 }
203
204 unmapTid(it->first);
205 termini.erase(it);
206 }
207}
208
209exec::task<int> TerminusManager::initMctpTerminus(const MctpInfo& mctpInfo)
210{
211 mctp_eid_t eid = std::get<0>(mctpInfo);
212 pldm_tid_t tid = 0;
213 bool isMapped = false;
214 auto rc = co_await getTidOverMctp(eid, &tid);
215 if (rc != PLDM_SUCCESS)
216 {
217 lg2::error("Failed to Get Terminus ID, error {ERROR}.", "ERROR", rc);
218 co_return PLDM_ERROR;
219 }
220
221 if (tid == PLDM_TID_RESERVED)
222 {
223 lg2::error("Terminus responses the reserved {TID}.", "TID", tid);
224 co_return PLDM_ERROR;
225 }
226
227 /* Terminus already has TID */
228 if (tid != PLDM_TID_UNASSIGNED)
229 {
230 /* TID is used by one discovered terminus */
231 auto it = termini.find(tid);
232 if (it != termini.end())
233 {
234 auto terminusMctpInfo = toMctpInfo(it->first);
235 /* The discovered terminus has the same MCTP Info */
236 if (terminusMctpInfo &&
237 (std::get<0>(terminusMctpInfo.value()) ==
238 std::get<0>(mctpInfo)) &&
239 (std::get<3>(terminusMctpInfo.value()) ==
240 std::get<3>(mctpInfo)))
241 {
242 co_return PLDM_SUCCESS;
243 }
244 else
245 {
246 /* ToDo:
247 * Maybe the terminus supports multiple medium interfaces
248 * Or the TID is used by other terminus.
249 * Check the UUID to confirm.
250 */
251 isMapped = false;
252 }
253 }
254 /* Use the terminus TID for mapping */
255 else
256 {
257 auto mappedTid = storeTerminusInfo(mctpInfo, tid);
258 if (!mappedTid)
259 {
260 lg2::error("Failed to store Terminus Info for terminus {TID}.",
261 "TID", tid);
262 co_return PLDM_ERROR;
263 }
264 isMapped = true;
265 }
266 }
267
268 if (!isMapped)
269 {
270 // Assigning a tid. If it has been mapped, mapTid()
271 // returns the tid assigned before.
272 auto mappedTid = mapTid(mctpInfo);
273 if (!mappedTid)
274 {
275 lg2::error("Failed to store Terminus Info for terminus {TID}.",
276 "TID", tid);
277 co_return PLDM_ERROR;
278 }
279
280 tid = mappedTid.value();
281 rc = co_await setTidOverMctp(eid, tid);
282 if (rc != PLDM_SUCCESS)
283 {
284 lg2::error("Failed to Set terminus TID, error{ERROR}.", "ERROR",
285 rc);
286 unmapTid(tid);
287 co_return rc;
288 }
289
290 if (rc != PLDM_SUCCESS && rc != PLDM_ERROR_UNSUPPORTED_PLDM_CMD)
291 {
292 lg2::error("Terminus {TID} does not support SetTID command.", "TID",
293 tid);
294 unmapTid(tid);
295 co_return rc;
296 }
297
298 if (termini.contains(tid))
299 {
300 // the terminus has been discovered before
301 co_return PLDM_SUCCESS;
302 }
303 }
304 /* Discovery the mapped terminus */
305 uint64_t supportedTypes = 0;
306 rc = co_await getPLDMTypes(tid, supportedTypes);
307 if (rc)
308 {
309 lg2::error("Failed to Get PLDM Types for terminus {TID}, error {ERROR}",
310 "TID", tid, "ERROR", rc);
311 co_return PLDM_ERROR;
312 }
313
314 try
315 {
316 termini[tid] = std::make_shared<Terminus>(tid, supportedTypes);
317 }
318 catch (const sdbusplus::exception_t& e)
319 {
320 lg2::error("Failed to create terminus manager for terminus {TID}",
321 "TID", tid);
322 co_return PLDM_ERROR;
323 }
324
325 uint8_t type = PLDM_BASE;
326 auto size = PLDM_MAX_TYPES * (PLDM_MAX_CMDS_PER_TYPE / 8);
327 std::vector<uint8_t> pldmCmds(size);
328 while ((type < PLDM_MAX_TYPES))
329 {
330 if (!termini[tid]->doesSupportType(type))
331 {
332 type++;
333 continue;
334 }
335 std::vector<bitfield8_t> cmds(PLDM_MAX_CMDS_PER_TYPE / 8);
336 auto rc = co_await getPLDMCommands(tid, type, cmds.data());
337 if (rc)
338 {
339 lg2::error(
340 "Failed to Get PLDM Commands for terminus {TID}, error {ERROR}",
341 "TID", tid, "ERROR", rc);
342 }
343
344 for (size_t i = 0; i < cmds.size(); i++)
345 {
346 auto idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + i;
347 if (idx >= pldmCmds.size())
348 {
349 lg2::error(
350 "Calculated index {IDX} out of bounds for pldmCmds, type {TYPE}, command index {CMD_IDX}",
351 "IDX", idx, "TYPE", type, "CMD_IDX", i);
352 continue;
353 }
354 pldmCmds[idx] = cmds[i].byte;
355 }
356 type++;
357 }
358 termini[tid]->setSupportedCommands(pldmCmds);
359
360 co_return PLDM_SUCCESS;
361}
362
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400363exec::task<int> TerminusManager::sendRecvPldmMsgOverMctp(
364 mctp_eid_t eid, Request& request, const pldm_msg** responseMsg,
365 size_t* responseLen)
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000366{
Thu Nguyen6b901e42024-07-10 15:21:10 +0700367 int rc = 0;
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000368 try
369 {
Thu Nguyen6b901e42024-07-10 15:21:10 +0700370 std::tie(rc, *responseMsg, *responseLen) =
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000371 co_await handler.sendRecvMsg(eid, std::move(request));
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000372 }
373 catch (const sdbusplus::exception_t& e)
374 {
375 lg2::error(
Thu Nguyen6b901e42024-07-10 15:21:10 +0700376 "Send and Receive PLDM message over MCTP throw error - {ERROR}.",
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000377 "ERROR", e);
378 co_return PLDM_ERROR;
379 }
Thu Nguyen6b901e42024-07-10 15:21:10 +0700380 catch (const int& e)
Jerry C Chen2da113f2024-07-09 16:02:23 +0800381 {
Thu Nguyen6b901e42024-07-10 15:21:10 +0700382 lg2::error(
383 "Send and Receive PLDM message over MCTP throw int error - {ERROR}.",
384 "ERROR", e);
Jerry C Chen2da113f2024-07-09 16:02:23 +0800385 co_return PLDM_ERROR;
386 }
Thu Nguyen6b901e42024-07-10 15:21:10 +0700387
388 co_return rc;
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000389}
390
391exec::task<int> TerminusManager::getTidOverMctp(mctp_eid_t eid, pldm_tid_t* tid)
392{
393 auto instanceId = instanceIdDb.next(eid);
394 Request request(sizeof(pldm_msg_hdr));
395 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
396 auto rc = encode_get_tid_req(instanceId, requestMsg);
397 if (rc)
398 {
399 instanceIdDb.free(eid, instanceId);
400 lg2::error(
401 "Failed to encode request GetTID for endpoint ID {EID}, error {RC} ",
402 "EID", eid, "RC", rc);
403 co_return rc;
404 }
405
406 const pldm_msg* responseMsg = nullptr;
407 size_t responseLen = 0;
408 rc = co_await sendRecvPldmMsgOverMctp(eid, request, &responseMsg,
409 &responseLen);
410 if (rc)
411 {
412 lg2::error("Failed to send GetTID for Endpoint {EID}, error {RC}",
413 "EID", eid, "RC", rc);
414 co_return rc;
415 }
416
417 uint8_t completionCode = 0;
418 rc = decode_get_tid_resp(responseMsg, responseLen, &completionCode, tid);
419 if (rc)
420 {
421 lg2::error(
422 "Failed to decode response GetTID for Endpoint ID {EID}, error {RC} ",
423 "EID", eid, "RC", rc);
424 co_return rc;
425 }
426
427 if (completionCode != PLDM_SUCCESS)
428 {
429 lg2::error("Error : GetTID for Endpoint ID {EID}, complete code {CC}.",
430 "EID", eid, "CC", completionCode);
431 co_return rc;
432 }
433
434 co_return completionCode;
435}
436
437exec::task<int> TerminusManager::setTidOverMctp(mctp_eid_t eid, pldm_tid_t tid)
438{
439 auto instanceId = instanceIdDb.next(eid);
440 Request request(sizeof(pldm_msg_hdr) + sizeof(pldm_set_tid_req));
441 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
442 auto rc = encode_set_tid_req(instanceId, tid, requestMsg);
443 if (rc)
444 {
445 instanceIdDb.free(eid, instanceId);
446 lg2::error(
447 "Failed to encode request SetTID for endpoint ID {EID}, error {RC} ",
448 "EID", eid, "RC", rc);
449 co_return rc;
450 }
451
452 const pldm_msg* responseMsg = nullptr;
453 size_t responseLen = 0;
454 rc = co_await sendRecvPldmMsgOverMctp(eid, request, &responseMsg,
455 &responseLen);
456 if (rc)
457 {
458 lg2::error("Failed to send SetTID for Endpoint {EID}, error {RC}",
459 "EID", eid, "RC", rc);
460 co_return rc;
461 }
462
463 if (responseMsg == NULL || responseLen != PLDM_SET_TID_RESP_BYTES)
464 {
465 lg2::error(
466 "Failed to decode response SetTID for Endpoint ID {EID}, error {RC} ",
467 "EID", eid, "RC", rc);
468 co_return PLDM_ERROR_INVALID_LENGTH;
469 }
470
471 co_return responseMsg->payload[0];
472}
473
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400474exec::task<int>
475 TerminusManager::getPLDMTypes(pldm_tid_t tid, uint64_t& supportedTypes)
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000476{
477 Request request(sizeof(pldm_msg_hdr));
478 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
479 auto rc = encode_get_types_req(0, requestMsg);
480 if (rc)
481 {
482 lg2::error(
483 "Failed to encode request getPLDMTypes for terminus ID {TID}, error {RC} ",
484 "TID", tid, "RC", rc);
485 co_return rc;
486 }
487
488 const pldm_msg* responseMsg = nullptr;
489 size_t responseLen = 0;
490
491 rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
492 if (rc)
493 {
494 lg2::error("Failed to send GetPLDMTypes for terminus {TID}, error {RC}",
495 "TID", tid, "RC", rc);
496 co_return rc;
497 }
498
499 uint8_t completionCode = 0;
500 bitfield8_t* types = reinterpret_cast<bitfield8_t*>(&supportedTypes);
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400501 rc =
502 decode_get_types_resp(responseMsg, responseLen, &completionCode, types);
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000503 if (rc)
504 {
505 lg2::error(
506 "Failed to decode response GetPLDMTypes for terminus ID {TID}, error {RC} ",
507 "TID", tid, "RC", rc);
508 co_return rc;
509 }
510
511 if (completionCode != PLDM_SUCCESS)
512 {
513 lg2::error(
514 "Error : GetPLDMTypes for terminus ID {TID}, complete code {CC}.",
515 "TID", tid, "CC", completionCode);
516 co_return rc;
517 }
518 co_return completionCode;
519}
520
521exec::task<int> TerminusManager::getPLDMCommands(pldm_tid_t tid, uint8_t type,
522 bitfield8_t* supportedCmds)
523{
524 Request request(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES);
525 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
526 ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
527
528 auto rc = encode_get_commands_req(0, type, version, requestMsg);
529 if (rc)
530 {
531 lg2::error(
532 "Failed to encode request GetPLDMCommands for terminus ID {TID}, error {RC} ",
533 "TID", tid, "RC", rc);
534 co_return rc;
535 }
536
537 const pldm_msg* responseMsg = nullptr;
538 size_t responseLen = 0;
539
540 rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
541 if (rc)
542 {
543 lg2::error(
544 "Failed to send GetPLDMCommands message for terminus {TID}, error {RC}",
545 "TID", tid, "RC", rc);
546 co_return rc;
547 }
548
549 /* Process response */
550 uint8_t completionCode = 0;
551 rc = decode_get_commands_resp(responseMsg, responseLen, &completionCode,
552 supportedCmds);
553 if (rc)
554 {
555 lg2::error(
556 "Failed to decode response GetPLDMCommands for terminus ID {TID}, error {RC} ",
557 "TID", tid, "RC", rc);
558 co_return rc;
559 }
560
561 if (completionCode != PLDM_SUCCESS)
562 {
563 lg2::error(
564 "Error : GetPLDMCommands for terminus ID {TID}, complete code {CC}.",
565 "TID", tid, "CC", completionCode);
566 co_return rc;
567 }
568
569 co_return completionCode;
570}
571
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400572exec::task<int> TerminusManager::sendRecvPldmMsg(
573 pldm_tid_t tid, Request& request, const pldm_msg** responseMsg,
574 size_t* responseLen)
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000575{
576 /**
577 * Size of tidPool is `std::numeric_limits<pldm_tid_t>::max() + 1`
578 * tidPool[i] always exist
579 */
580 if (!tidPool[tid])
581 {
582 co_return PLDM_ERROR_NOT_READY;
583 }
584
585 if (!transportLayerTable.contains(tid))
586 {
587 co_return PLDM_ERROR_NOT_READY;
588 }
589
590 if (transportLayerTable[tid] != SupportedTransportLayer::MCTP)
591 {
592 co_return PLDM_ERROR_NOT_READY;
593 }
594
595 auto mctpInfo = toMctpInfo(tid);
596 if (!mctpInfo.has_value())
597 {
598 co_return PLDM_ERROR_NOT_READY;
599 }
600
601 auto eid = std::get<0>(mctpInfo.value());
602 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
603 requestMsg->hdr.instance_id = instanceIdDb.next(eid);
604 auto rc = co_await sendRecvPldmMsgOverMctp(eid, request, responseMsg,
605 responseLen);
606
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000607 co_return rc;
608}
609
610} // namespace platform_mc
611} // namespace pldm