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 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 } 47 } 48 49 co_return PLDM_SUCCESS; 50 } 51 52 exec::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 144 co_return PLDM_SUCCESS; 145 } 146 147 exec::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 { 160 auto rc = 161 co_await getPDRRepositoryInfo(tid, repositoryState, recordCount, 162 repositorySize, largestRecordSize); 163 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 { 171 recordCount = 172 std::min(recordCount + 1, std::numeric_limits<uint32_t>::max()); 173 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 { 197 auto rc = 198 co_await getPDR(tid, recordHndl, 0, PLDM_GET_FIRSTPART, recvBufSize, 199 0, nextRecordHndl, nextDataTransferHndl, 200 transferFlag, responseCnt, recvBuf, transferCrc); 201 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 { 228 rc = co_await getPDR( 229 tid, recordHndl, nextDataTransferHndl, PLDM_GET_NEXTPART, 230 recvBufSize, recordChgNum, nextRecordHndl, 231 nextDataTransferHndl, transferFlag, responseCnt, recvBuf, 232 transferCrc); 233 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 260 exec::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 316 exec::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 372 exec::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 433 exec::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 } 489 } // namespace platform_mc 490 } // namespace pldm 491