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