blob: 93fdb091b8f386dbc3078a783f6d2cc001f879c8 [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) {
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
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) {
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
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{
150 auto foundIter = std::find_if(termini.begin(), termini.end(),
151 [&](const auto& terminusPair) {
152 auto terminusMctpInfo = toMctpInfo(terminusPair.first);
153 return (
154 terminusMctpInfo &&
155 (std::get<0>(terminusMctpInfo.value()) == std::get<0>(mctpInfo)) &&
156 (std::get<3>(terminusMctpInfo.value()) == std::get<3>(mctpInfo)));
157 });
158
159 return foundIter;
160}
161
162exec::task<int> TerminusManager::discoverMctpTerminusTask()
163{
164 while (!queuedMctpInfos.empty())
165 {
166 if (manager)
167 {
168 co_await manager->beforeDiscoverTerminus();
169 }
170
171 const MctpInfos& mctpInfos = queuedMctpInfos.front();
172 for (const auto& mctpInfo : mctpInfos)
173 {
Patrick Williams29d2f4a2024-07-13 16:44:15 -0500174 auto it = findTerminusPtr(mctpInfo);
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000175 if (it == termini.end())
176 {
177 co_await initMctpTerminus(mctpInfo);
178 }
179 }
180
181 if (manager)
182 {
183 co_await manager->afterDiscoverTerminus();
184 }
185
186 queuedMctpInfos.pop();
187 }
188
189 co_return PLDM_SUCCESS;
190}
191
192void TerminusManager::removeMctpTerminus(const MctpInfos& mctpInfos)
193{
194 // remove terminus
195 for (const auto& mctpInfo : mctpInfos)
196 {
Patrick Williams29d2f4a2024-07-13 16:44:15 -0500197 auto it = findTerminusPtr(mctpInfo);
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000198 if (it == termini.end())
199 {
200 continue;
201 }
202
203 unmapTid(it->first);
204 termini.erase(it);
205 }
206}
207
208exec::task<int> TerminusManager::initMctpTerminus(const MctpInfo& mctpInfo)
209{
210 mctp_eid_t eid = std::get<0>(mctpInfo);
211 pldm_tid_t tid = 0;
212 bool isMapped = false;
213 auto rc = co_await getTidOverMctp(eid, &tid);
214 if (rc != PLDM_SUCCESS)
215 {
216 lg2::error("Failed to Get Terminus ID, error {ERROR}.", "ERROR", rc);
217 co_return PLDM_ERROR;
218 }
219
220 if (tid == PLDM_TID_RESERVED)
221 {
222 lg2::error("Terminus responses the reserved {TID}.", "TID", tid);
223 co_return PLDM_ERROR;
224 }
225
226 /* Terminus already has TID */
227 if (tid != PLDM_TID_UNASSIGNED)
228 {
229 /* TID is used by one discovered terminus */
230 auto it = termini.find(tid);
231 if (it != termini.end())
232 {
233 auto terminusMctpInfo = toMctpInfo(it->first);
234 /* The discovered terminus has the same MCTP Info */
235 if (terminusMctpInfo &&
236 (std::get<0>(terminusMctpInfo.value()) ==
237 std::get<0>(mctpInfo)) &&
238 (std::get<3>(terminusMctpInfo.value()) ==
239 std::get<3>(mctpInfo)))
240 {
241 co_return PLDM_SUCCESS;
242 }
243 else
244 {
245 /* ToDo:
246 * Maybe the terminus supports multiple medium interfaces
247 * Or the TID is used by other terminus.
248 * Check the UUID to confirm.
249 */
250 isMapped = false;
251 }
252 }
253 /* Use the terminus TID for mapping */
254 else
255 {
256 auto mappedTid = storeTerminusInfo(mctpInfo, tid);
257 if (!mappedTid)
258 {
259 lg2::error("Failed to store Terminus Info for terminus {TID}.",
260 "TID", tid);
261 co_return PLDM_ERROR;
262 }
263 isMapped = true;
264 }
265 }
266
267 if (!isMapped)
268 {
269 // Assigning a tid. If it has been mapped, mapTid()
270 // returns the tid assigned before.
271 auto mappedTid = mapTid(mctpInfo);
272 if (!mappedTid)
273 {
274 lg2::error("Failed to store Terminus Info for terminus {TID}.",
275 "TID", tid);
276 co_return PLDM_ERROR;
277 }
278
279 tid = mappedTid.value();
280 rc = co_await setTidOverMctp(eid, tid);
281 if (rc != PLDM_SUCCESS)
282 {
283 lg2::error("Failed to Set terminus TID, error{ERROR}.", "ERROR",
284 rc);
285 unmapTid(tid);
286 co_return rc;
287 }
288
289 if (rc != PLDM_SUCCESS && rc != PLDM_ERROR_UNSUPPORTED_PLDM_CMD)
290 {
291 lg2::error("Terminus {TID} does not support SetTID command.", "TID",
292 tid);
293 unmapTid(tid);
294 co_return rc;
295 }
296
297 if (termini.contains(tid))
298 {
299 // the terminus has been discovered before
300 co_return PLDM_SUCCESS;
301 }
302 }
303 /* Discovery the mapped terminus */
304 uint64_t supportedTypes = 0;
305 rc = co_await getPLDMTypes(tid, supportedTypes);
306 if (rc)
307 {
308 lg2::error("Failed to Get PLDM Types for terminus {TID}, error {ERROR}",
309 "TID", tid, "ERROR", rc);
310 co_return PLDM_ERROR;
311 }
312
313 try
314 {
315 termini[tid] = std::make_shared<Terminus>(tid, supportedTypes);
316 }
317 catch (const sdbusplus::exception_t& e)
318 {
319 lg2::error("Failed to create terminus manager for terminus {TID}",
320 "TID", tid);
321 co_return PLDM_ERROR;
322 }
323
324 uint8_t type = PLDM_BASE;
325 auto size = PLDM_MAX_TYPES * (PLDM_MAX_CMDS_PER_TYPE / 8);
326 std::vector<uint8_t> pldmCmds(size);
327 while ((type < PLDM_MAX_TYPES))
328 {
329 if (!termini[tid]->doesSupportType(type))
330 {
331 type++;
332 continue;
333 }
334 std::vector<bitfield8_t> cmds(PLDM_MAX_CMDS_PER_TYPE / 8);
335 auto rc = co_await getPLDMCommands(tid, type, cmds.data());
336 if (rc)
337 {
338 lg2::error(
339 "Failed to Get PLDM Commands for terminus {TID}, error {ERROR}",
340 "TID", tid, "ERROR", rc);
341 }
342
343 for (size_t i = 0; i < cmds.size(); i++)
344 {
345 auto idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + i;
346 if (idx >= pldmCmds.size())
347 {
348 lg2::error(
349 "Calculated index {IDX} out of bounds for pldmCmds, type {TYPE}, command index {CMD_IDX}",
350 "IDX", idx, "TYPE", type, "CMD_IDX", i);
351 continue;
352 }
353 pldmCmds[idx] = cmds[i].byte;
354 }
355 type++;
356 }
357 termini[tid]->setSupportedCommands(pldmCmds);
358
359 co_return PLDM_SUCCESS;
360}
361
362exec::task<int>
363 TerminusManager::sendRecvPldmMsgOverMctp(mctp_eid_t eid, Request& request,
364 const pldm_msg** responseMsg,
365 size_t* responseLen)
366{
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
474exec::task<int> TerminusManager::getPLDMTypes(pldm_tid_t tid,
475 uint64_t& supportedTypes)
476{
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);
501 rc = decode_get_types_resp(responseMsg, responseLen, &completionCode,
502 types);
503 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
572exec::task<int> TerminusManager::sendRecvPldmMsg(pldm_tid_t tid,
573 Request& request,
574 const pldm_msg** responseMsg,
575 size_t* responseLen)
576{
577 /**
578 * Size of tidPool is `std::numeric_limits<pldm_tid_t>::max() + 1`
579 * tidPool[i] always exist
580 */
581 if (!tidPool[tid])
582 {
583 co_return PLDM_ERROR_NOT_READY;
584 }
585
586 if (!transportLayerTable.contains(tid))
587 {
588 co_return PLDM_ERROR_NOT_READY;
589 }
590
591 if (transportLayerTable[tid] != SupportedTransportLayer::MCTP)
592 {
593 co_return PLDM_ERROR_NOT_READY;
594 }
595
596 auto mctpInfo = toMctpInfo(tid);
597 if (!mctpInfo.has_value())
598 {
599 co_return PLDM_ERROR_NOT_READY;
600 }
601
602 auto eid = std::get<0>(mctpInfo.value());
603 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
604 requestMsg->hdr.instance_id = instanceIdDb.next(eid);
605 auto rc = co_await sendRecvPldmMsgOverMctp(eid, request, responseMsg,
606 responseLen);
607
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000608 co_return rc;
609}
610
611} // namespace platform_mc
612} // namespace pldm