blob: 10adefd3203e3ff41cb691c874f5f39d00bd528d [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{
Gilbert Cheneac61a42022-02-23 20:56:19 +0000165 std::vector<pldm_tid_t> addedTids;
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000166 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 {
Patrick Williams29d2f4a2024-07-13 16:44:15 -0500176 auto it = findTerminusPtr(mctpInfo);
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000177 if (it == termini.end())
178 {
179 co_await initMctpTerminus(mctpInfo);
180 }
Gilbert Cheneac61a42022-02-23 20:56:19 +0000181
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());
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000189 }
190
191 if (manager)
192 {
193 co_await manager->afterDiscoverTerminus();
Gilbert Cheneac61a42022-02-23 20:56:19 +0000194 for (const auto& tid : addedTids)
195 {
196 manager->startSensorPolling(tid);
197 }
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000198 }
199
200 queuedMctpInfos.pop();
201 }
202
203 co_return PLDM_SUCCESS;
204}
205
206void TerminusManager::removeMctpTerminus(const MctpInfos& mctpInfos)
207{
208 // remove terminus
209 for (const auto& mctpInfo : mctpInfos)
210 {
Patrick Williams29d2f4a2024-07-13 16:44:15 -0500211 auto it = findTerminusPtr(mctpInfo);
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000212 if (it == termini.end())
213 {
214 continue;
215 }
216
Gilbert Cheneac61a42022-02-23 20:56:19 +0000217 if (manager)
218 {
219 manager->stopSensorPolling(it->second->getTid());
220 }
221
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000222 unmapTid(it->first);
223 termini.erase(it);
224 }
225}
226
227exec::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);
Eric Yang1be20722024-10-28 21:34:39 +0800329 unmapTid(tid);
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000330 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);
Eric Yang1be20722024-10-28 21:34:39 +0800341 unmapTid(tid);
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000342 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 std::vector<bitfield8_t> cmds(PLDM_MAX_CMDS_PER_TYPE / 8);
356 auto rc = co_await getPLDMCommands(tid, type, cmds.data());
357 if (rc)
358 {
359 lg2::error(
360 "Failed to Get PLDM Commands for terminus {TID}, error {ERROR}",
361 "TID", tid, "ERROR", rc);
362 }
363
364 for (size_t i = 0; i < cmds.size(); i++)
365 {
366 auto idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + i;
367 if (idx >= pldmCmds.size())
368 {
369 lg2::error(
370 "Calculated index {IDX} out of bounds for pldmCmds, type {TYPE}, command index {CMD_IDX}",
371 "IDX", idx, "TYPE", type, "CMD_IDX", i);
372 continue;
373 }
374 pldmCmds[idx] = cmds[i].byte;
375 }
376 type++;
377 }
378 termini[tid]->setSupportedCommands(pldmCmds);
379
380 co_return PLDM_SUCCESS;
381}
382
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400383exec::task<int> TerminusManager::sendRecvPldmMsgOverMctp(
384 mctp_eid_t eid, Request& request, const pldm_msg** responseMsg,
385 size_t* responseLen)
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000386{
Thu Nguyen6b901e42024-07-10 15:21:10 +0700387 int rc = 0;
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000388 try
389 {
Thu Nguyen6b901e42024-07-10 15:21:10 +0700390 std::tie(rc, *responseMsg, *responseLen) =
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000391 co_await handler.sendRecvMsg(eid, std::move(request));
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000392 }
393 catch (const sdbusplus::exception_t& e)
394 {
395 lg2::error(
Thu Nguyen6b901e42024-07-10 15:21:10 +0700396 "Send and Receive PLDM message over MCTP throw error - {ERROR}.",
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000397 "ERROR", e);
398 co_return PLDM_ERROR;
399 }
Thu Nguyen6b901e42024-07-10 15:21:10 +0700400 catch (const int& e)
Jerry C Chen2da113f2024-07-09 16:02:23 +0800401 {
Thu Nguyen6b901e42024-07-10 15:21:10 +0700402 lg2::error(
403 "Send and Receive PLDM message over MCTP throw int error - {ERROR}.",
404 "ERROR", e);
Jerry C Chen2da113f2024-07-09 16:02:23 +0800405 co_return PLDM_ERROR;
406 }
Thu Nguyen6b901e42024-07-10 15:21:10 +0700407
408 co_return rc;
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000409}
410
411exec::task<int> TerminusManager::getTidOverMctp(mctp_eid_t eid, pldm_tid_t* tid)
412{
413 auto instanceId = instanceIdDb.next(eid);
414 Request request(sizeof(pldm_msg_hdr));
415 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
416 auto rc = encode_get_tid_req(instanceId, requestMsg);
417 if (rc)
418 {
419 instanceIdDb.free(eid, instanceId);
420 lg2::error(
421 "Failed to encode request GetTID for endpoint ID {EID}, error {RC} ",
422 "EID", eid, "RC", rc);
423 co_return rc;
424 }
425
426 const pldm_msg* responseMsg = nullptr;
427 size_t responseLen = 0;
428 rc = co_await sendRecvPldmMsgOverMctp(eid, request, &responseMsg,
429 &responseLen);
430 if (rc)
431 {
432 lg2::error("Failed to send GetTID for Endpoint {EID}, error {RC}",
433 "EID", eid, "RC", rc);
434 co_return rc;
435 }
436
437 uint8_t completionCode = 0;
438 rc = decode_get_tid_resp(responseMsg, responseLen, &completionCode, tid);
439 if (rc)
440 {
441 lg2::error(
442 "Failed to decode response GetTID for Endpoint ID {EID}, error {RC} ",
443 "EID", eid, "RC", rc);
444 co_return rc;
445 }
446
447 if (completionCode != PLDM_SUCCESS)
448 {
449 lg2::error("Error : GetTID for Endpoint ID {EID}, complete code {CC}.",
450 "EID", eid, "CC", completionCode);
451 co_return rc;
452 }
453
454 co_return completionCode;
455}
456
457exec::task<int> TerminusManager::setTidOverMctp(mctp_eid_t eid, pldm_tid_t tid)
458{
459 auto instanceId = instanceIdDb.next(eid);
460 Request request(sizeof(pldm_msg_hdr) + sizeof(pldm_set_tid_req));
461 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
462 auto rc = encode_set_tid_req(instanceId, tid, requestMsg);
463 if (rc)
464 {
465 instanceIdDb.free(eid, instanceId);
466 lg2::error(
467 "Failed to encode request SetTID for endpoint ID {EID}, error {RC} ",
468 "EID", eid, "RC", rc);
469 co_return rc;
470 }
471
472 const pldm_msg* responseMsg = nullptr;
473 size_t responseLen = 0;
474 rc = co_await sendRecvPldmMsgOverMctp(eid, request, &responseMsg,
475 &responseLen);
476 if (rc)
477 {
478 lg2::error("Failed to send SetTID for Endpoint {EID}, error {RC}",
479 "EID", eid, "RC", rc);
480 co_return rc;
481 }
482
483 if (responseMsg == NULL || responseLen != PLDM_SET_TID_RESP_BYTES)
484 {
485 lg2::error(
486 "Failed to decode response SetTID for Endpoint ID {EID}, error {RC} ",
487 "EID", eid, "RC", rc);
488 co_return PLDM_ERROR_INVALID_LENGTH;
489 }
490
491 co_return responseMsg->payload[0];
492}
493
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400494exec::task<int>
495 TerminusManager::getPLDMTypes(pldm_tid_t tid, uint64_t& supportedTypes)
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000496{
497 Request request(sizeof(pldm_msg_hdr));
498 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
499 auto rc = encode_get_types_req(0, requestMsg);
500 if (rc)
501 {
502 lg2::error(
503 "Failed to encode request getPLDMTypes for terminus ID {TID}, error {RC} ",
504 "TID", tid, "RC", rc);
505 co_return rc;
506 }
507
508 const pldm_msg* responseMsg = nullptr;
509 size_t responseLen = 0;
510
511 rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
512 if (rc)
513 {
514 lg2::error("Failed to send GetPLDMTypes for terminus {TID}, error {RC}",
515 "TID", tid, "RC", rc);
516 co_return rc;
517 }
518
519 uint8_t completionCode = 0;
520 bitfield8_t* types = reinterpret_cast<bitfield8_t*>(&supportedTypes);
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400521 rc =
522 decode_get_types_resp(responseMsg, responseLen, &completionCode, types);
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000523 if (rc)
524 {
525 lg2::error(
526 "Failed to decode response GetPLDMTypes for terminus ID {TID}, error {RC} ",
527 "TID", tid, "RC", rc);
528 co_return rc;
529 }
530
531 if (completionCode != PLDM_SUCCESS)
532 {
533 lg2::error(
534 "Error : GetPLDMTypes for terminus ID {TID}, complete code {CC}.",
535 "TID", tid, "CC", completionCode);
536 co_return rc;
537 }
538 co_return completionCode;
539}
540
541exec::task<int> TerminusManager::getPLDMCommands(pldm_tid_t tid, uint8_t type,
542 bitfield8_t* supportedCmds)
543{
544 Request request(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES);
545 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
546 ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
547
548 auto rc = encode_get_commands_req(0, type, version, requestMsg);
549 if (rc)
550 {
551 lg2::error(
552 "Failed to encode request GetPLDMCommands for terminus ID {TID}, error {RC} ",
553 "TID", tid, "RC", rc);
554 co_return rc;
555 }
556
557 const pldm_msg* responseMsg = nullptr;
558 size_t responseLen = 0;
559
560 rc = co_await sendRecvPldmMsg(tid, request, &responseMsg, &responseLen);
561 if (rc)
562 {
563 lg2::error(
564 "Failed to send GetPLDMCommands message for terminus {TID}, error {RC}",
565 "TID", tid, "RC", rc);
566 co_return rc;
567 }
568
569 /* Process response */
570 uint8_t completionCode = 0;
571 rc = decode_get_commands_resp(responseMsg, responseLen, &completionCode,
572 supportedCmds);
573 if (rc)
574 {
575 lg2::error(
576 "Failed to decode response GetPLDMCommands for terminus ID {TID}, error {RC} ",
577 "TID", tid, "RC", rc);
578 co_return rc;
579 }
580
581 if (completionCode != PLDM_SUCCESS)
582 {
583 lg2::error(
584 "Error : GetPLDMCommands for terminus ID {TID}, complete code {CC}.",
585 "TID", tid, "CC", completionCode);
586 co_return rc;
587 }
588
589 co_return completionCode;
590}
591
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400592exec::task<int> TerminusManager::sendRecvPldmMsg(
593 pldm_tid_t tid, Request& request, const pldm_msg** responseMsg,
594 size_t* responseLen)
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000595{
596 /**
597 * Size of tidPool is `std::numeric_limits<pldm_tid_t>::max() + 1`
598 * tidPool[i] always exist
599 */
600 if (!tidPool[tid])
601 {
602 co_return PLDM_ERROR_NOT_READY;
603 }
604
605 if (!transportLayerTable.contains(tid))
606 {
607 co_return PLDM_ERROR_NOT_READY;
608 }
609
610 if (transportLayerTable[tid] != SupportedTransportLayer::MCTP)
611 {
612 co_return PLDM_ERROR_NOT_READY;
613 }
614
615 auto mctpInfo = toMctpInfo(tid);
616 if (!mctpInfo.has_value())
617 {
618 co_return PLDM_ERROR_NOT_READY;
619 }
620
621 auto eid = std::get<0>(mctpInfo.value());
622 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
623 requestMsg->hdr.instance_id = instanceIdDb.next(eid);
624 auto rc = co_await sendRecvPldmMsgOverMctp(eid, request, responseMsg,
625 responseLen);
626
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000627 co_return rc;
628}
629
630} // namespace platform_mc
631} // namespace pldm