1 #include "platform_manager.hpp"
2
3 #include "terminus_manager.hpp"
4
5 #include <phosphor-logging/lg2.hpp>
6
7 #include <ranges>
8
9 PHOSPHOR_LOG2_USING;
10
11 namespace pldm
12 {
13 namespace platform_mc
14 {
15
initTerminus()16 exec::task<int> PlatformManager::initTerminus()
17 {
18 for (auto& [tid, terminus] : termini)
19 {
20 if (terminus->initialized)
21 {
22 continue;
23 }
24
25 if (terminus->doesSupportCommand(PLDM_PLATFORM, PLDM_GET_PDR))
26 {
27 auto rc = co_await getPDRs(terminus);
28 if (rc)
29 {
30 lg2::error(
31 "Failed to fetch PDRs for terminus with TID: {TID}, error: {ERROR}",
32 "TID", tid, "ERROR", rc);
33 continue; // Continue to next terminus
34 }
35
36 terminus->parseTerminusPDRs();
37 }
38
39 uint16_t terminusMaxBufferSize = terminus->maxBufferSize;
40 if (!terminus->doesSupportCommand(PLDM_PLATFORM,
41 PLDM_EVENT_MESSAGE_BUFFER_SIZE))
42 {
43 terminusMaxBufferSize = PLDM_PLATFORM_DEFAULT_MESSAGE_BUFFER_SIZE;
44 }
45 else
46 {
47 /* Get maxBufferSize use PLDM command eventMessageBufferSize */
48 auto rc = co_await eventMessageBufferSize(
49 tid, terminus->maxBufferSize, terminusMaxBufferSize);
50 if (rc != PLDM_SUCCESS)
51 {
52 lg2::error(
53 "Failed to get message buffer size for terminus with TID: {TID}, error: {ERROR}",
54 "TID", tid, "ERROR", rc);
55 terminusMaxBufferSize =
56 PLDM_PLATFORM_DEFAULT_MESSAGE_BUFFER_SIZE;
57 }
58 }
59 terminus->maxBufferSize =
60 std::min(terminus->maxBufferSize, terminusMaxBufferSize);
61
62 auto rc = co_await configEventReceiver(tid);
63 if (rc)
64 {
65 lg2::error(
66 "Failed to config event receiver for terminus with TID: {TID}, error: {ERROR}",
67 "TID", tid, "ERROR", rc);
68 }
69 terminus->initialized = true;
70 }
71
72 co_return PLDM_SUCCESS;
73 }
74
configEventReceiver(pldm_tid_t tid)75 exec::task<int> PlatformManager::configEventReceiver(pldm_tid_t tid)
76 {
77 if (!termini.contains(tid))
78 {
79 co_return PLDM_ERROR;
80 }
81
82 auto& terminus = termini[tid];
83 if (!terminus->doesSupportCommand(PLDM_PLATFORM,
84 PLDM_EVENT_MESSAGE_SUPPORTED))
85 {
86 terminus->synchronyConfigurationSupported.byte =
87 1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE;
88 }
89 else
90 {
91 /**
92 * Get synchronyConfigurationSupported use PLDM command
93 * eventMessageBufferSize
94 */
95 uint8_t synchronyConfiguration = 0;
96 uint8_t numberEventClassReturned = 0;
97 std::vector<uint8_t> eventClass{};
98 auto rc = co_await eventMessageSupported(
99 tid, 1, synchronyConfiguration,
100 terminus->synchronyConfigurationSupported, numberEventClassReturned,
101 eventClass);
102 if (rc != PLDM_SUCCESS)
103 {
104 lg2::error(
105 "Failed to get event message supported for terminus with TID: {TID}, error: {ERROR}",
106 "TID", tid, "ERROR", rc);
107 terminus->synchronyConfigurationSupported.byte = 0;
108 }
109 }
110
111 if (!terminus->doesSupportCommand(PLDM_PLATFORM, PLDM_SET_EVENT_RECEIVER))
112 {
113 lg2::error("Terminus {TID} does not support Event", "TID", tid);
114 co_return PLDM_ERROR;
115 }
116
117 /**
118 * Set Event receiver base on synchronyConfigurationSupported data
119 * use PLDM command SetEventReceiver
120 */
121 pldm_event_message_global_enable eventMessageGlobalEnable =
122 PLDM_EVENT_MESSAGE_GLOBAL_DISABLE;
123 uint16_t heartbeatTimer = 0;
124
125 /* Use PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE when
126 * for eventMessageGlobalEnable when the terminus supports that type
127 */
128 if (terminus->synchronyConfigurationSupported.byte &
129 (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE))
130 {
131 heartbeatTimer = HEARTBEAT_TIMEOUT;
132 eventMessageGlobalEnable =
133 PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE;
134 }
135 /* Use PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC when
136 * for eventMessageGlobalEnable when the terminus does not support
137 * PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE
138 * and supports PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC type
139 */
140 else if (terminus->synchronyConfigurationSupported.byte &
141 (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC))
142 {
143 eventMessageGlobalEnable = PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC;
144 }
145 /* Only use PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING
146 * for eventMessageGlobalEnable when the terminus only supports
147 * this type
148 */
149 else if (terminus->synchronyConfigurationSupported.byte &
150 (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING))
151 {
152 eventMessageGlobalEnable = PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING;
153 }
154
155 if (eventMessageGlobalEnable != PLDM_EVENT_MESSAGE_GLOBAL_DISABLE)
156 {
157 auto rc = co_await setEventReceiver(tid, eventMessageGlobalEnable,
158 PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP,
159 heartbeatTimer);
160 if (rc != PLDM_SUCCESS)
161 {
162 lg2::error(
163 "Failed to set event receiver for terminus with TID: {TID}, error: {ERROR}",
164 "TID", tid, "ERROR", rc);
165 }
166 }
167
168 co_return PLDM_SUCCESS;
169 }
170
getPDRs(std::shared_ptr<Terminus> terminus)171 exec::task<int> PlatformManager::getPDRs(std::shared_ptr<Terminus> terminus)
172 {
173 pldm_tid_t tid = terminus->getTid();
174
175 /* Setting default values when getPDRRepositoryInfo fails or does not
176 * support */
177 uint8_t repositoryState = PLDM_AVAILABLE;
178 uint32_t recordCount = std::numeric_limits<uint32_t>::max();
179 uint32_t repositorySize = 0;
180 uint32_t largestRecordSize = std::numeric_limits<uint32_t>::max();
181 if (terminus->doesSupportCommand(PLDM_PLATFORM,
182 PLDM_GET_PDR_REPOSITORY_INFO))
183 {
184 auto rc =
185 co_await getPDRRepositoryInfo(tid, repositoryState, recordCount,
186 repositorySize, largestRecordSize);
187 if (rc)
188 {
189 lg2::error(
190 "Failed to get PDR Repository Info for terminus with TID: {TID}, error: {ERROR}",
191 "TID", tid, "ERROR", rc);
192 }
193 else
194 {
195 recordCount =
196 std::min(recordCount + 1, std::numeric_limits<uint32_t>::max());
197 largestRecordSize = std::min(largestRecordSize + 1,
198 std::numeric_limits<uint32_t>::max());
199 }
200 }
201
202 if (repositoryState != PLDM_AVAILABLE)
203 {
204 co_return PLDM_ERROR_NOT_READY;
205 }
206
207 uint32_t recordHndl = 0;
208 uint32_t nextRecordHndl = 0;
209 uint32_t nextDataTransferHndl = 0;
210 uint8_t transferFlag = 0;
211 uint16_t responseCnt = 0;
212 constexpr uint16_t recvBufSize = PLDM_PLATFORM_GETPDR_MAX_RECORD_BYTES;
213 std::vector<uint8_t> recvBuf(recvBufSize);
214 uint8_t transferCrc = 0;
215
216 terminus->pdrs.clear();
217 uint32_t receivedRecordCount = 0;
218
219 do
220 {
221 auto rc =
222 co_await getPDR(tid, recordHndl, 0, PLDM_GET_FIRSTPART, recvBufSize,
223 0, nextRecordHndl, nextDataTransferHndl,
224 transferFlag, responseCnt, recvBuf, transferCrc);
225
226 if (rc)
227 {
228 lg2::error(
229 "Failed to get PDRs for terminus {TID}, error: {RC}, first part of record handle {RECORD}",
230 "TID", tid, "RC", rc, "RECORD", recordHndl);
231 terminus->pdrs.clear();
232 co_return rc;
233 }
234
235 if (transferFlag == PLDM_PLATFORM_TRANSFER_START_AND_END)
236 {
237 // single-part
238 terminus->pdrs.emplace_back(std::vector<uint8_t>(
239 recvBuf.begin(), recvBuf.begin() + responseCnt));
240 recordHndl = nextRecordHndl;
241 }
242 else
243 {
244 // multipart transfer
245 uint32_t receivedRecordSize = responseCnt;
246 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(recvBuf.data());
247 uint16_t recordChgNum = le16toh(pdrHdr->record_change_num);
248 std::vector<uint8_t> receivedPdr(recvBuf.begin(),
249 recvBuf.begin() + responseCnt);
250 do
251 {
252 rc = co_await getPDR(
253 tid, recordHndl, nextDataTransferHndl, PLDM_GET_NEXTPART,
254 recvBufSize, recordChgNum, nextRecordHndl,
255 nextDataTransferHndl, transferFlag, responseCnt, recvBuf,
256 transferCrc);
257 if (rc)
258 {
259 lg2::error(
260 "Failed to get PDRs for terminus {TID}, error: {RC}, get middle part of record handle {RECORD}",
261 "TID", tid, "RC", rc, "RECORD", recordHndl);
262 terminus->pdrs.clear();
263 co_return rc;
264 }
265
266 receivedPdr.insert(receivedPdr.end(), recvBuf.begin(),
267 recvBuf.begin() + responseCnt);
268 receivedRecordSize += responseCnt;
269
270 if (transferFlag == PLDM_PLATFORM_TRANSFER_END)
271 {
272 terminus->pdrs.emplace_back(std::move(receivedPdr));
273 recordHndl = nextRecordHndl;
274 }
275 } while (nextDataTransferHndl != 0 &&
276 receivedRecordSize < largestRecordSize);
277 }
278 receivedRecordCount++;
279 } while (nextRecordHndl != 0 && receivedRecordCount < recordCount);
280
281 co_return PLDM_SUCCESS;
282 }
283
getPDR(const pldm_tid_t tid,const uint32_t recordHndl,const uint32_t dataTransferHndl,const uint8_t transferOpFlag,const uint16_t requestCnt,const uint16_t recordChgNum,uint32_t & nextRecordHndl,uint32_t & nextDataTransferHndl,uint8_t & transferFlag,uint16_t & responseCnt,std::vector<uint8_t> & recordData,uint8_t & transferCrc)284 exec::task<int> PlatformManager::getPDR(
285 const pldm_tid_t tid, const uint32_t recordHndl,
286 const uint32_t dataTransferHndl, const uint8_t transferOpFlag,
287 const uint16_t requestCnt, const uint16_t recordChgNum,
288 uint32_t& nextRecordHndl, uint32_t& nextDataTransferHndl,
289 uint8_t& transferFlag, uint16_t& responseCnt,
290 std::vector<uint8_t>& recordData, uint8_t& transferCrc)
291 {
292 Request request(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES);
293 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
294 auto rc = encode_get_pdr_req(0, recordHndl, dataTransferHndl,
295 transferOpFlag, requestCnt, recordChgNum,
296 requestMsg, PLDM_GET_PDR_REQ_BYTES);
297 if (rc)
298 {
299 lg2::error(
300 "Failed to encode request GetPDR for terminus ID {TID}, error {RC} ",
301 "TID", tid, "RC", rc);
302 co_return rc;
303 }
304
305 const pldm_msg* responseMsg = nullptr;
306 size_t responseLen = 0;
307 rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
308 &responseLen);
309 if (rc)
310 {
311 lg2::error(
312 "Failed to send GetPDR message for terminus {TID}, error {RC}",
313 "TID", tid, "RC", rc);
314 co_return rc;
315 }
316
317 uint8_t completionCode;
318 rc = decode_get_pdr_resp(responseMsg, responseLen, &completionCode,
319 &nextRecordHndl, &nextDataTransferHndl,
320 &transferFlag, &responseCnt, recordData.data(),
321 recordData.size(), &transferCrc);
322 if (rc)
323 {
324 lg2::error(
325 "Failed to decode response GetPDR for terminus ID {TID}, error {RC} ",
326 "TID", tid, "RC", rc);
327 co_return rc;
328 }
329
330 if (completionCode != PLDM_SUCCESS)
331 {
332 lg2::error("Error : GetPDR for terminus ID {TID}, complete code {CC}.",
333 "TID", tid, "CC", completionCode);
334 co_return rc;
335 }
336
337 co_return completionCode;
338 }
339
getPDRRepositoryInfo(const pldm_tid_t tid,uint8_t & repositoryState,uint32_t & recordCount,uint32_t & repositorySize,uint32_t & largestRecordSize)340 exec::task<int> PlatformManager::getPDRRepositoryInfo(
341 const pldm_tid_t tid, uint8_t& repositoryState, uint32_t& recordCount,
342 uint32_t& repositorySize, uint32_t& largestRecordSize)
343 {
344 Request request(sizeof(pldm_msg_hdr) + sizeof(uint8_t));
345 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
346 auto rc = encode_pldm_header_only(PLDM_REQUEST, 0, PLDM_PLATFORM,
347 PLDM_GET_PDR_REPOSITORY_INFO, requestMsg);
348 if (rc)
349 {
350 lg2::error(
351 "Failed to encode request GetPDRRepositoryInfo for terminus ID {TID}, error {RC} ",
352 "TID", tid, "RC", rc);
353 co_return rc;
354 }
355
356 const pldm_msg* responseMsg = nullptr;
357 size_t responseLen = 0;
358 rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
359 &responseLen);
360 if (rc)
361 {
362 lg2::error(
363 "Failed to send GetPDRRepositoryInfo message for terminus {TID}, error {RC}",
364 "TID", tid, "RC", rc);
365 co_return rc;
366 }
367
368 uint8_t completionCode = 0;
369 std::array<uint8_t, PLDM_TIMESTAMP104_SIZE> updateTime = {};
370 std::array<uint8_t, PLDM_TIMESTAMP104_SIZE> oemUpdateTime = {};
371 uint8_t dataTransferHandleTimeout = 0;
372
373 rc = decode_get_pdr_repository_info_resp(
374 responseMsg, responseLen, &completionCode, &repositoryState,
375 updateTime.data(), oemUpdateTime.data(), &recordCount, &repositorySize,
376 &largestRecordSize, &dataTransferHandleTimeout);
377 if (rc)
378 {
379 lg2::error(
380 "Failed to decode response GetPDRRepositoryInfo for terminus ID {TID}, error {RC} ",
381 "TID", tid, "RC", rc);
382 co_return rc;
383 }
384
385 if (completionCode != PLDM_SUCCESS)
386 {
387 lg2::error(
388 "Error : GetPDRRepositoryInfo for terminus ID {TID}, complete code {CC}.",
389 "TID", tid, "CC", completionCode);
390 co_return rc;
391 }
392
393 co_return completionCode;
394 }
395
eventMessageBufferSize(pldm_tid_t tid,uint16_t receiverMaxBufferSize,uint16_t & terminusBufferSize)396 exec::task<int> PlatformManager::eventMessageBufferSize(
397 pldm_tid_t tid, uint16_t receiverMaxBufferSize,
398 uint16_t& terminusBufferSize)
399 {
400 Request request(
401 sizeof(pldm_msg_hdr) + PLDM_EVENT_MESSAGE_BUFFER_SIZE_REQ_BYTES);
402 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
403 auto rc = encode_event_message_buffer_size_req(0, receiverMaxBufferSize,
404 requestMsg);
405 if (rc)
406 {
407 lg2::error(
408 "Failed to encode request GetPDRRepositoryInfo for terminus ID {TID}, error {RC} ",
409 "TID", tid, "RC", rc);
410 co_return rc;
411 }
412
413 const pldm_msg* responseMsg = nullptr;
414 size_t responseLen = 0;
415 rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
416 &responseLen);
417 if (rc)
418 {
419 lg2::error(
420 "Failed to send EventMessageBufferSize message for terminus {TID}, error {RC}",
421 "TID", tid, "RC", rc);
422 co_return rc;
423 }
424
425 uint8_t completionCode;
426 rc = decode_event_message_buffer_size_resp(
427 responseMsg, responseLen, &completionCode, &terminusBufferSize);
428 if (rc)
429 {
430 lg2::error(
431 "Failed to decode response EventMessageBufferSize for terminus ID {TID}, error {RC} ",
432 "TID", tid, "RC", rc);
433 co_return rc;
434 }
435
436 if (completionCode != PLDM_SUCCESS)
437 {
438 lg2::error(
439 "Error : EventMessageBufferSize for terminus ID {TID}, complete code {CC}.",
440 "TID", tid, "CC", completionCode);
441 co_return completionCode;
442 }
443
444 co_return completionCode;
445 }
446
setEventReceiver(pldm_tid_t tid,pldm_event_message_global_enable eventMessageGlobalEnable,pldm_transport_protocol_type protocolType,uint16_t heartbeatTimer)447 exec::task<int> PlatformManager::setEventReceiver(
448 pldm_tid_t tid, pldm_event_message_global_enable eventMessageGlobalEnable,
449 pldm_transport_protocol_type protocolType, uint16_t heartbeatTimer)
450 {
451 size_t requestBytes = PLDM_SET_EVENT_RECEIVER_REQ_BYTES;
452 /**
453 * Ignore heartbeatTimer bytes when eventMessageGlobalEnable is not
454 * ENABLE_ASYNC_KEEP_ALIVE
455 */
456 if (eventMessageGlobalEnable !=
457 PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE)
458 {
459 requestBytes = requestBytes - sizeof(heartbeatTimer);
460 }
461 Request request(sizeof(pldm_msg_hdr) + requestBytes);
462 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
463 auto rc = encode_set_event_receiver_req(
464 0, eventMessageGlobalEnable, protocolType,
465 terminusManager.getLocalEid(), heartbeatTimer, requestMsg);
466 if (rc)
467 {
468 lg2::error(
469 "Failed to encode request SetEventReceiver for terminus ID {TID}, error {RC} ",
470 "TID", tid, "RC", rc);
471 co_return rc;
472 }
473
474 const pldm_msg* responseMsg = nullptr;
475 size_t responseLen = 0;
476 rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
477 &responseLen);
478 if (rc)
479 {
480 lg2::error(
481 "Failed to send SetEventReceiver message for terminus {TID}, error {RC}",
482 "TID", tid, "RC", rc);
483 co_return rc;
484 }
485
486 uint8_t completionCode;
487 rc = decode_set_event_receiver_resp(responseMsg, responseLen,
488 &completionCode);
489 if (rc)
490 {
491 lg2::error(
492 "Failed to decode response SetEventReceiver for terminus ID {TID}, error {RC} ",
493 "TID", tid, "RC", rc);
494 co_return rc;
495 }
496
497 if (completionCode != PLDM_SUCCESS)
498 {
499 lg2::error(
500 "Error : SetEventReceiver for terminus ID {TID}, complete code {CC}.",
501 "TID", tid, "CC", completionCode);
502 co_return completionCode;
503 }
504
505 co_return completionCode;
506 }
507
eventMessageSupported(pldm_tid_t tid,uint8_t formatVersion,uint8_t & synchronyConfiguration,bitfield8_t & synchronyConfigurationSupported,uint8_t & numberEventClassReturned,std::vector<uint8_t> & eventClass)508 exec::task<int> PlatformManager::eventMessageSupported(
509 pldm_tid_t tid, uint8_t formatVersion, uint8_t& synchronyConfiguration,
510 bitfield8_t& synchronyConfigurationSupported,
511 uint8_t& numberEventClassReturned, std::vector<uint8_t>& eventClass)
512 {
513 Request request(
514 sizeof(pldm_msg_hdr) + PLDM_EVENT_MESSAGE_SUPPORTED_REQ_BYTES);
515 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
516 auto rc = encode_event_message_supported_req(0, formatVersion, requestMsg);
517 if (rc)
518 {
519 lg2::error(
520 "Failed to encode request EventMessageSupported for terminus ID {TID}, error {RC} ",
521 "TID", tid, "RC", rc);
522 co_return rc;
523 }
524
525 const pldm_msg* responseMsg = nullptr;
526 size_t responseLen = 0;
527 rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
528 &responseLen);
529 if (rc)
530 {
531 lg2::error(
532 "Failed to send EventMessageSupported message for terminus {TID}, error {RC}",
533 "TID", tid, "RC", rc);
534 co_return rc;
535 }
536
537 uint8_t completionCode = 0;
538 uint8_t eventClassCount = static_cast<uint8_t>(responseLen) -
539 PLDM_EVENT_MESSAGE_SUPPORTED_MIN_RESP_BYTES;
540 eventClass.resize(eventClassCount);
541
542 rc = decode_event_message_supported_resp(
543 responseMsg, responseLen, &completionCode, &synchronyConfiguration,
544 &synchronyConfigurationSupported, &numberEventClassReturned,
545 eventClass.data(), eventClassCount);
546 if (rc)
547 {
548 lg2::error(
549 "Failed to decode response EventMessageSupported for terminus ID {TID}, error {RC} ",
550 "TID", tid, "RC", rc);
551 co_return rc;
552 }
553
554 if (completionCode != PLDM_SUCCESS)
555 {
556 lg2::error(
557 "Error : EventMessageSupported for terminus ID {TID}, complete code {CC}.",
558 "TID", tid, "CC", completionCode);
559 co_return completionCode;
560 }
561
562 co_return completionCode;
563 }
564 } // namespace platform_mc
565 } // namespace pldm
566