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 co_return PLDM_SUCCESS; 41 } 42 43 exec::task<int> PlatformManager::getPDRs(std::shared_ptr<Terminus> terminus) 44 { 45 pldm_tid_t tid = terminus->getTid(); 46 47 /* Setting default values when getPDRRepositoryInfo fails or does not 48 * support */ 49 uint8_t repositoryState = PLDM_AVAILABLE; 50 uint32_t recordCount = std::numeric_limits<uint32_t>::max(); 51 uint32_t repositorySize = 0; 52 uint32_t largestRecordSize = std::numeric_limits<uint32_t>::max(); 53 if (terminus->doesSupportCommand(PLDM_PLATFORM, 54 PLDM_GET_PDR_REPOSITORY_INFO)) 55 { 56 auto rc = co_await getPDRRepositoryInfo(tid, repositoryState, 57 recordCount, repositorySize, 58 largestRecordSize); 59 if (rc) 60 { 61 lg2::error( 62 "Failed to get PDR Repository Info for terminus with TID: {TID}, error: {ERROR}", 63 "TID", tid, "ERROR", rc); 64 } 65 else 66 { 67 recordCount = std::min(recordCount + 1, 68 std::numeric_limits<uint32_t>::max()); 69 largestRecordSize = std::min(largestRecordSize + 1, 70 std::numeric_limits<uint32_t>::max()); 71 } 72 } 73 74 if (repositoryState != PLDM_AVAILABLE) 75 { 76 co_return PLDM_ERROR_NOT_READY; 77 } 78 79 uint32_t recordHndl = 0; 80 uint32_t nextRecordHndl = 0; 81 uint32_t nextDataTransferHndl = 0; 82 uint8_t transferFlag = 0; 83 uint16_t responseCnt = 0; 84 constexpr uint16_t recvBufSize = PLDM_PLATFORM_GETPDR_MAX_RECORD_BYTES; 85 std::vector<uint8_t> recvBuf(recvBufSize); 86 uint8_t transferCrc = 0; 87 88 terminus->pdrs.clear(); 89 uint32_t receivedRecordCount = 0; 90 91 do 92 { 93 auto rc = co_await getPDR(tid, recordHndl, 0, PLDM_GET_FIRSTPART, 94 recvBufSize, 0, nextRecordHndl, 95 nextDataTransferHndl, transferFlag, 96 responseCnt, recvBuf, transferCrc); 97 98 if (rc) 99 { 100 lg2::error( 101 "Failed to get PDRs for terminus {TID}, error: {RC}, first part of record handle {RECORD}", 102 "TID", tid, "RC", rc, "RECORD", recordHndl); 103 terminus->pdrs.clear(); 104 co_return rc; 105 } 106 107 if (transferFlag == PLDM_PLATFORM_TRANSFER_START_AND_END) 108 { 109 // single-part 110 terminus->pdrs.emplace_back(std::vector<uint8_t>( 111 recvBuf.begin(), recvBuf.begin() + responseCnt)); 112 recordHndl = nextRecordHndl; 113 } 114 else 115 { 116 // multipart transfer 117 uint32_t receivedRecordSize = responseCnt; 118 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(recvBuf.data()); 119 uint16_t recordChgNum = le16toh(pdrHdr->record_change_num); 120 std::vector<uint8_t> receivedPdr(recvBuf.begin(), 121 recvBuf.begin() + responseCnt); 122 do 123 { 124 rc = co_await getPDR(tid, recordHndl, nextDataTransferHndl, 125 PLDM_GET_NEXTPART, recvBufSize, 126 recordChgNum, nextRecordHndl, 127 nextDataTransferHndl, transferFlag, 128 responseCnt, recvBuf, transferCrc); 129 if (rc) 130 { 131 lg2::error( 132 "Failed to get PDRs for terminus {TID}, error: {RC}, get middle part of record handle {RECORD}", 133 "TID", tid, "RC", rc, "RECORD", recordHndl); 134 terminus->pdrs.clear(); 135 co_return rc; 136 } 137 138 receivedPdr.insert(receivedPdr.end(), recvBuf.begin(), 139 recvBuf.begin() + responseCnt); 140 receivedRecordSize += responseCnt; 141 142 if (transferFlag == PLDM_PLATFORM_TRANSFER_END) 143 { 144 terminus->pdrs.emplace_back(std::move(receivedPdr)); 145 recordHndl = nextRecordHndl; 146 } 147 } while (nextDataTransferHndl != 0 && 148 receivedRecordSize < largestRecordSize); 149 } 150 receivedRecordCount++; 151 } while (nextRecordHndl != 0 && receivedRecordCount < recordCount); 152 153 co_return PLDM_SUCCESS; 154 } 155 156 exec::task<int> PlatformManager::getPDR( 157 const pldm_tid_t tid, const uint32_t recordHndl, 158 const uint32_t dataTransferHndl, const uint8_t transferOpFlag, 159 const uint16_t requestCnt, const uint16_t recordChgNum, 160 uint32_t& nextRecordHndl, uint32_t& nextDataTransferHndl, 161 uint8_t& transferFlag, uint16_t& responseCnt, 162 std::vector<uint8_t>& recordData, uint8_t& transferCrc) 163 { 164 Request request(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES); 165 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data()); 166 auto rc = encode_get_pdr_req(0, recordHndl, dataTransferHndl, 167 transferOpFlag, requestCnt, recordChgNum, 168 requestMsg, PLDM_GET_PDR_REQ_BYTES); 169 if (rc) 170 { 171 lg2::error( 172 "Failed to encode request GetPDR for terminus ID {TID}, error {RC} ", 173 "TID", tid, "RC", rc); 174 co_return rc; 175 } 176 177 const pldm_msg* responseMsg = nullptr; 178 size_t responseLen = 0; 179 rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg, 180 &responseLen); 181 if (rc) 182 { 183 lg2::error( 184 "Failed to send GetPDR message for terminus {TID}, error {RC}", 185 "TID", tid, "RC", rc); 186 co_return rc; 187 } 188 189 uint8_t completionCode; 190 rc = decode_get_pdr_resp(responseMsg, responseLen, &completionCode, 191 &nextRecordHndl, &nextDataTransferHndl, 192 &transferFlag, &responseCnt, recordData.data(), 193 recordData.size(), &transferCrc); 194 if (rc) 195 { 196 lg2::error( 197 "Failed to decode response GetPDR for terminus ID {TID}, error {RC} ", 198 "TID", tid, "RC", rc); 199 co_return rc; 200 } 201 202 if (completionCode != PLDM_SUCCESS) 203 { 204 lg2::error("Error : GetPDR for terminus ID {TID}, complete code {CC}.", 205 "TID", tid, "CC", completionCode); 206 co_return rc; 207 } 208 209 co_return completionCode; 210 } 211 212 exec::task<int> PlatformManager::getPDRRepositoryInfo( 213 const pldm_tid_t tid, uint8_t& repositoryState, uint32_t& recordCount, 214 uint32_t& repositorySize, uint32_t& largestRecordSize) 215 { 216 Request request(sizeof(pldm_msg_hdr) + sizeof(uint8_t)); 217 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data()); 218 auto rc = encode_pldm_header_only(PLDM_REQUEST, 0, PLDM_PLATFORM, 219 PLDM_GET_PDR_REPOSITORY_INFO, requestMsg); 220 if (rc) 221 { 222 lg2::error( 223 "Failed to encode request GetPDRRepositoryInfo for terminus ID {TID}, error {RC} ", 224 "TID", tid, "RC", rc); 225 co_return rc; 226 } 227 228 const pldm_msg* responseMsg = nullptr; 229 size_t responseLen = 0; 230 rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg, 231 &responseLen); 232 if (rc) 233 { 234 lg2::error( 235 "Failed to send GetPDRRepositoryInfo message for terminus {TID}, error {RC}", 236 "TID", tid, "RC", rc); 237 co_return rc; 238 } 239 240 uint8_t completionCode = 0; 241 std::array<uint8_t, PLDM_TIMESTAMP104_SIZE> updateTime = {}; 242 std::array<uint8_t, PLDM_TIMESTAMP104_SIZE> oemUpdateTime = {}; 243 uint8_t dataTransferHandleTimeout = 0; 244 245 rc = decode_get_pdr_repository_info_resp( 246 responseMsg, responseLen, &completionCode, &repositoryState, 247 updateTime.data(), oemUpdateTime.data(), &recordCount, &repositorySize, 248 &largestRecordSize, &dataTransferHandleTimeout); 249 if (rc) 250 { 251 lg2::error( 252 "Failed to decode response GetPDRRepositoryInfo for terminus ID {TID}, error {RC} ", 253 "TID", tid, "RC", rc); 254 co_return rc; 255 } 256 257 if (completionCode != PLDM_SUCCESS) 258 { 259 lg2::error( 260 "Error : GetPDRRepositoryInfo for terminus ID {TID}, complete code {CC}.", 261 "TID", tid, "CC", completionCode); 262 co_return rc; 263 } 264 265 co_return completionCode; 266 } 267 268 } // namespace platform_mc 269 } // namespace pldm 270