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 16 exec::task<int> PlatformManager::initTerminus() 17 { 18 for (auto& [tid, terminus] : termini) 19 { 20 if (terminus->initialized) 21 { 22 continue; 23 } 24 terminus->initialized = true; 25 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 } 39 40 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 63 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 } 70 } 71 72 co_return PLDM_SUCCESS; 73 } 74 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 = 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 167 co_return PLDM_SUCCESS; 168 } 169 170 exec::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 { 183 auto rc = 184 co_await getPDRRepositoryInfo(tid, repositoryState, recordCount, 185 repositorySize, largestRecordSize); 186 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 { 194 recordCount = 195 std::min(recordCount + 1, std::numeric_limits<uint32_t>::max()); 196 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 { 220 auto rc = 221 co_await getPDR(tid, recordHndl, 0, PLDM_GET_FIRSTPART, recvBufSize, 222 0, nextRecordHndl, nextDataTransferHndl, 223 transferFlag, responseCnt, recvBuf, transferCrc); 224 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 { 251 rc = co_await getPDR( 252 tid, recordHndl, nextDataTransferHndl, PLDM_GET_NEXTPART, 253 recvBufSize, recordChgNum, nextRecordHndl, 254 nextDataTransferHndl, transferFlag, responseCnt, recvBuf, 255 transferCrc); 256 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 283 exec::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 339 exec::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 395 exec::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 446 exec::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 507 exec::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 } 563 } // namespace platform_mc 564 } // namespace pldm 565