blob: 35526fb384f3df3a2f909e3c97a7cd19f70589c9 [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
40 auto rc = co_await configEventReceiver(tid);
41 if (rc)
42 {
43 lg2::error(
44 "Failed to config event receiver for terminus with TID: {TID}, error: {ERROR}",
45 "TID", tid, "ERROR", rc);
46 }
Gilbert Chen6c7fed42022-02-22 15:40:17 +000047 }
Thu Nguyen51d66b52024-08-06 09:15:55 +000048
49 co_return PLDM_SUCCESS;
50}
51
52exec::task<int> PlatformManager::configEventReceiver(pldm_tid_t tid)
53{
54 if (!termini.contains(tid))
55 {
56 co_return PLDM_ERROR;
57 }
58
59 auto& terminus = termini[tid];
60 if (!terminus->doesSupportCommand(PLDM_PLATFORM,
61 PLDM_EVENT_MESSAGE_SUPPORTED))
62 {
63 terminus->synchronyConfigurationSupported.byte = 0;
64 }
65 else
66 {
67 /**
68 * Get synchronyConfigurationSupported use PLDM command
69 * eventMessageBufferSize
70 */
71 uint8_t synchronyConfiguration = 0;
72 uint8_t numberEventClassReturned = 0;
73 std::vector<uint8_t> eventClass{};
74 auto rc = co_await eventMessageSupported(
75 tid, 1, synchronyConfiguration,
76 terminus->synchronyConfigurationSupported, numberEventClassReturned,
77 eventClass);
78 if (rc != PLDM_SUCCESS)
79 {
80 lg2::error(
81 "Failed to get event message supported for terminus with TID: {TID}, error: {ERROR}",
82 "TID", tid, "ERROR", rc);
83 terminus->synchronyConfigurationSupported.byte = 0;
84 }
85 }
86
87 if (!terminus->doesSupportCommand(PLDM_PLATFORM, PLDM_SET_EVENT_RECEIVER))
88 {
89 lg2::error("Terminus {TID} does not support Event", "TID", tid);
90 co_return PLDM_ERROR;
91 }
92
93 /**
94 * Set Event receiver base on synchronyConfigurationSupported data
95 * use PLDM command SetEventReceiver
96 */
97 pldm_event_message_global_enable eventMessageGlobalEnable =
98 PLDM_EVENT_MESSAGE_GLOBAL_DISABLE;
99 uint16_t heartbeatTimer = 0;
100
101 /* Use PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE when
102 * for eventMessageGlobalEnable when the terminus supports that type
103 */
104 if (terminus->synchronyConfigurationSupported.byte &
105 (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE))
106 {
107 heartbeatTimer = HEARTBEAT_TIMEOUT;
108 eventMessageGlobalEnable =
109 PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE;
110 }
111 /* Use PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC when
112 * for eventMessageGlobalEnable when the terminus does not support
113 * PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE
114 * and supports PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC type
115 */
116 else if (terminus->synchronyConfigurationSupported.byte &
117 (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC))
118 {
119 eventMessageGlobalEnable = PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC;
120 }
121 /* Only use PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING
122 * for eventMessageGlobalEnable when the terminus only supports
123 * this type
124 */
125 else if (terminus->synchronyConfigurationSupported.byte &
126 (1 << PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING))
127 {
128 eventMessageGlobalEnable = PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING;
129 }
130
131 if (eventMessageGlobalEnable != PLDM_EVENT_MESSAGE_GLOBAL_DISABLE)
132 {
133 auto rc = co_await setEventReceiver(tid, eventMessageGlobalEnable,
134 PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP,
135 heartbeatTimer);
136 if (rc != PLDM_SUCCESS)
137 {
138 lg2::error(
139 "Failed to set event receiver for terminus with TID: {TID}, error: {ERROR}",
140 "TID", tid, "ERROR", rc);
141 }
142 }
143
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000144 co_return PLDM_SUCCESS;
145}
146
Gilbert Chende2a1322022-05-24 15:35:21 +0100147exec::task<int> PlatformManager::getPDRs(std::shared_ptr<Terminus> terminus)
148{
149 pldm_tid_t tid = terminus->getTid();
150
151 /* Setting default values when getPDRRepositoryInfo fails or does not
152 * support */
153 uint8_t repositoryState = PLDM_AVAILABLE;
154 uint32_t recordCount = std::numeric_limits<uint32_t>::max();
155 uint32_t repositorySize = 0;
156 uint32_t largestRecordSize = std::numeric_limits<uint32_t>::max();
157 if (terminus->doesSupportCommand(PLDM_PLATFORM,
158 PLDM_GET_PDR_REPOSITORY_INFO))
159 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400160 auto rc =
161 co_await getPDRRepositoryInfo(tid, repositoryState, recordCount,
162 repositorySize, largestRecordSize);
Gilbert Chende2a1322022-05-24 15:35:21 +0100163 if (rc)
164 {
165 lg2::error(
166 "Failed to get PDR Repository Info for terminus with TID: {TID}, error: {ERROR}",
167 "TID", tid, "ERROR", rc);
168 }
169 else
170 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400171 recordCount =
172 std::min(recordCount + 1, std::numeric_limits<uint32_t>::max());
Gilbert Chende2a1322022-05-24 15:35:21 +0100173 largestRecordSize = std::min(largestRecordSize + 1,
174 std::numeric_limits<uint32_t>::max());
175 }
176 }
177
178 if (repositoryState != PLDM_AVAILABLE)
179 {
180 co_return PLDM_ERROR_NOT_READY;
181 }
182
183 uint32_t recordHndl = 0;
184 uint32_t nextRecordHndl = 0;
185 uint32_t nextDataTransferHndl = 0;
186 uint8_t transferFlag = 0;
187 uint16_t responseCnt = 0;
188 constexpr uint16_t recvBufSize = PLDM_PLATFORM_GETPDR_MAX_RECORD_BYTES;
189 std::vector<uint8_t> recvBuf(recvBufSize);
190 uint8_t transferCrc = 0;
191
192 terminus->pdrs.clear();
193 uint32_t receivedRecordCount = 0;
194
195 do
196 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400197 auto rc =
198 co_await getPDR(tid, recordHndl, 0, PLDM_GET_FIRSTPART, recvBufSize,
199 0, nextRecordHndl, nextDataTransferHndl,
200 transferFlag, responseCnt, recvBuf, transferCrc);
Gilbert Chende2a1322022-05-24 15:35:21 +0100201
202 if (rc)
203 {
204 lg2::error(
205 "Failed to get PDRs for terminus {TID}, error: {RC}, first part of record handle {RECORD}",
206 "TID", tid, "RC", rc, "RECORD", recordHndl);
207 terminus->pdrs.clear();
208 co_return rc;
209 }
210
211 if (transferFlag == PLDM_PLATFORM_TRANSFER_START_AND_END)
212 {
213 // single-part
214 terminus->pdrs.emplace_back(std::vector<uint8_t>(
215 recvBuf.begin(), recvBuf.begin() + responseCnt));
216 recordHndl = nextRecordHndl;
217 }
218 else
219 {
220 // multipart transfer
221 uint32_t receivedRecordSize = responseCnt;
222 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(recvBuf.data());
223 uint16_t recordChgNum = le16toh(pdrHdr->record_change_num);
224 std::vector<uint8_t> receivedPdr(recvBuf.begin(),
225 recvBuf.begin() + responseCnt);
226 do
227 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400228 rc = co_await getPDR(
229 tid, recordHndl, nextDataTransferHndl, PLDM_GET_NEXTPART,
230 recvBufSize, recordChgNum, nextRecordHndl,
231 nextDataTransferHndl, transferFlag, responseCnt, recvBuf,
232 transferCrc);
Gilbert Chende2a1322022-05-24 15:35:21 +0100233 if (rc)
234 {
235 lg2::error(
236 "Failed to get PDRs for terminus {TID}, error: {RC}, get middle part of record handle {RECORD}",
237 "TID", tid, "RC", rc, "RECORD", recordHndl);
238 terminus->pdrs.clear();
239 co_return rc;
240 }
241
242 receivedPdr.insert(receivedPdr.end(), recvBuf.begin(),
243 recvBuf.begin() + responseCnt);
244 receivedRecordSize += responseCnt;
245
246 if (transferFlag == PLDM_PLATFORM_TRANSFER_END)
247 {
248 terminus->pdrs.emplace_back(std::move(receivedPdr));
249 recordHndl = nextRecordHndl;
250 }
251 } while (nextDataTransferHndl != 0 &&
252 receivedRecordSize < largestRecordSize);
253 }
254 receivedRecordCount++;
255 } while (nextRecordHndl != 0 && receivedRecordCount < recordCount);
256
257 co_return PLDM_SUCCESS;
258}
259
260exec::task<int> PlatformManager::getPDR(
261 const pldm_tid_t tid, const uint32_t recordHndl,
262 const uint32_t dataTransferHndl, const uint8_t transferOpFlag,
263 const uint16_t requestCnt, const uint16_t recordChgNum,
264 uint32_t& nextRecordHndl, uint32_t& nextDataTransferHndl,
265 uint8_t& transferFlag, uint16_t& responseCnt,
266 std::vector<uint8_t>& recordData, uint8_t& transferCrc)
267{
268 Request request(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES);
269 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
270 auto rc = encode_get_pdr_req(0, recordHndl, dataTransferHndl,
271 transferOpFlag, requestCnt, recordChgNum,
272 requestMsg, PLDM_GET_PDR_REQ_BYTES);
273 if (rc)
274 {
275 lg2::error(
276 "Failed to encode request GetPDR for terminus ID {TID}, error {RC} ",
277 "TID", tid, "RC", rc);
278 co_return rc;
279 }
280
281 const pldm_msg* responseMsg = nullptr;
282 size_t responseLen = 0;
283 rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
284 &responseLen);
285 if (rc)
286 {
287 lg2::error(
288 "Failed to send GetPDR message for terminus {TID}, error {RC}",
289 "TID", tid, "RC", rc);
290 co_return rc;
291 }
292
293 uint8_t completionCode;
294 rc = decode_get_pdr_resp(responseMsg, responseLen, &completionCode,
295 &nextRecordHndl, &nextDataTransferHndl,
296 &transferFlag, &responseCnt, recordData.data(),
297 recordData.size(), &transferCrc);
298 if (rc)
299 {
300 lg2::error(
301 "Failed to decode response GetPDR for terminus ID {TID}, error {RC} ",
302 "TID", tid, "RC", rc);
303 co_return rc;
304 }
305
306 if (completionCode != PLDM_SUCCESS)
307 {
308 lg2::error("Error : GetPDR for terminus ID {TID}, complete code {CC}.",
309 "TID", tid, "CC", completionCode);
310 co_return rc;
311 }
312
313 co_return completionCode;
314}
315
316exec::task<int> PlatformManager::getPDRRepositoryInfo(
317 const pldm_tid_t tid, uint8_t& repositoryState, uint32_t& recordCount,
318 uint32_t& repositorySize, uint32_t& largestRecordSize)
319{
320 Request request(sizeof(pldm_msg_hdr) + sizeof(uint8_t));
321 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
322 auto rc = encode_pldm_header_only(PLDM_REQUEST, 0, PLDM_PLATFORM,
323 PLDM_GET_PDR_REPOSITORY_INFO, requestMsg);
324 if (rc)
325 {
326 lg2::error(
327 "Failed to encode request GetPDRRepositoryInfo for terminus ID {TID}, error {RC} ",
328 "TID", tid, "RC", rc);
329 co_return rc;
330 }
331
332 const pldm_msg* responseMsg = nullptr;
333 size_t responseLen = 0;
334 rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
335 &responseLen);
336 if (rc)
337 {
338 lg2::error(
339 "Failed to send GetPDRRepositoryInfo message for terminus {TID}, error {RC}",
340 "TID", tid, "RC", rc);
341 co_return rc;
342 }
343
344 uint8_t completionCode = 0;
345 std::array<uint8_t, PLDM_TIMESTAMP104_SIZE> updateTime = {};
346 std::array<uint8_t, PLDM_TIMESTAMP104_SIZE> oemUpdateTime = {};
347 uint8_t dataTransferHandleTimeout = 0;
348
349 rc = decode_get_pdr_repository_info_resp(
350 responseMsg, responseLen, &completionCode, &repositoryState,
351 updateTime.data(), oemUpdateTime.data(), &recordCount, &repositorySize,
352 &largestRecordSize, &dataTransferHandleTimeout);
353 if (rc)
354 {
355 lg2::error(
356 "Failed to decode response GetPDRRepositoryInfo for terminus ID {TID}, error {RC} ",
357 "TID", tid, "RC", rc);
358 co_return rc;
359 }
360
361 if (completionCode != PLDM_SUCCESS)
362 {
363 lg2::error(
364 "Error : GetPDRRepositoryInfo for terminus ID {TID}, complete code {CC}.",
365 "TID", tid, "CC", completionCode);
366 co_return rc;
367 }
368
369 co_return completionCode;
370}
371
Thu Nguyen51d66b52024-08-06 09:15:55 +0000372exec::task<int> PlatformManager::setEventReceiver(
373 pldm_tid_t tid, pldm_event_message_global_enable eventMessageGlobalEnable,
374 pldm_transport_protocol_type protocolType, uint16_t heartbeatTimer)
375{
376 size_t requestBytes = PLDM_SET_EVENT_RECEIVER_REQ_BYTES;
377 /**
378 * Ignore heartbeatTimer bytes when eventMessageGlobalEnable is not
379 * ENABLE_ASYNC_KEEP_ALIVE
380 */
381 if (eventMessageGlobalEnable !=
382 PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE)
383 {
384 requestBytes = requestBytes - sizeof(heartbeatTimer);
385 }
386 Request request(sizeof(pldm_msg_hdr) + requestBytes);
387 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
388 auto rc = encode_set_event_receiver_req(
389 0, eventMessageGlobalEnable, protocolType,
390 terminusManager.getLocalEid(), heartbeatTimer, requestMsg);
391 if (rc)
392 {
393 lg2::error(
394 "Failed to encode request SetEventReceiver for terminus ID {TID}, error {RC} ",
395 "TID", tid, "RC", rc);
396 co_return rc;
397 }
398
399 const pldm_msg* responseMsg = nullptr;
400 size_t responseLen = 0;
401 rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
402 &responseLen);
403 if (rc)
404 {
405 lg2::error(
406 "Failed to send SetEventReceiver message for terminus {TID}, error {RC}",
407 "TID", tid, "RC", rc);
408 co_return rc;
409 }
410
411 uint8_t completionCode;
412 rc = decode_set_event_receiver_resp(responseMsg, responseLen,
413 &completionCode);
414 if (rc)
415 {
416 lg2::error(
417 "Failed to decode response SetEventReceiver for terminus ID {TID}, error {RC} ",
418 "TID", tid, "RC", rc);
419 co_return rc;
420 }
421
422 if (completionCode != PLDM_SUCCESS)
423 {
424 lg2::error(
425 "Error : SetEventReceiver for terminus ID {TID}, complete code {CC}.",
426 "TID", tid, "CC", completionCode);
427 co_return completionCode;
428 }
429
430 co_return completionCode;
431}
432
433exec::task<int> PlatformManager::eventMessageSupported(
434 pldm_tid_t tid, uint8_t formatVersion, uint8_t& synchronyConfiguration,
435 bitfield8_t& synchronyConfigurationSupported,
436 uint8_t& numberEventClassReturned, std::vector<uint8_t>& eventClass)
437{
438 Request request(
439 sizeof(pldm_msg_hdr) + PLDM_EVENT_MESSAGE_SUPPORTED_REQ_BYTES);
440 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
441 auto rc = encode_event_message_supported_req(0, formatVersion, requestMsg);
442 if (rc)
443 {
444 lg2::error(
445 "Failed to encode request EventMessageSupported for terminus ID {TID}, error {RC} ",
446 "TID", tid, "RC", rc);
447 co_return rc;
448 }
449
450 const pldm_msg* responseMsg = nullptr;
451 size_t responseLen = 0;
452 rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
453 &responseLen);
454 if (rc)
455 {
456 lg2::error(
457 "Failed to send EventMessageSupported message for terminus {TID}, error {RC}",
458 "TID", tid, "RC", rc);
459 co_return rc;
460 }
461
462 uint8_t completionCode = 0;
463 uint8_t eventClassCount = static_cast<uint8_t>(responseLen) -
464 PLDM_EVENT_MESSAGE_SUPPORTED_MIN_RESP_BYTES;
465 eventClass.resize(eventClassCount);
466
467 rc = decode_event_message_supported_resp(
468 responseMsg, responseLen, &completionCode, &synchronyConfiguration,
469 &synchronyConfigurationSupported, &numberEventClassReturned,
470 eventClass.data(), eventClassCount);
471 if (rc)
472 {
473 lg2::error(
474 "Failed to decode response EventMessageSupported for terminus ID {TID}, error {RC} ",
475 "TID", tid, "RC", rc);
476 co_return rc;
477 }
478
479 if (completionCode != PLDM_SUCCESS)
480 {
481 lg2::error(
482 "Error : EventMessageSupported for terminus ID {TID}, complete code {CC}.",
483 "TID", tid, "CC", completionCode);
484 co_return completionCode;
485 }
486
487 co_return completionCode;
488}
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000489} // namespace platform_mc
490} // namespace pldm