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 = 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 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 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 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 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 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 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