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 =
57             co_await getPDRRepositoryInfo(tid, repositoryState, recordCount,
58                                           repositorySize, 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 =
68                 std::min(recordCount + 1, 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 =
94             co_await getPDR(tid, recordHndl, 0, PLDM_GET_FIRSTPART, recvBufSize,
95                             0, nextRecordHndl, nextDataTransferHndl,
96                             transferFlag, 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(
125                     tid, recordHndl, nextDataTransferHndl, PLDM_GET_NEXTPART,
126                     recvBufSize, recordChgNum, nextRecordHndl,
127                     nextDataTransferHndl, transferFlag, responseCnt, recvBuf,
128                     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