blob: 389a49202f34781dbfda9506c577f1086611569e [file] [log] [blame]
Deepak Kodihalli87514cc2020-04-16 09:08:38 -05001#include "config.h"
2
Pavithra Barithaya51efaf82020-04-02 02:42:27 -05003#include "host_pdr_handler.hpp"
4
Pavithra Barithayae8beb892020-04-14 23:24:25 -05005#include <assert.h>
6
Deepak Kodihalli87514cc2020-04-16 09:08:38 -05007#include <fstream>
8#include <nlohmann/json.hpp>
9
Pavithra Barithaya51efaf82020-04-02 02:42:27 -050010#include "libpldm/requester/pldm.h"
11
12namespace pldm
13{
14
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050015using Json = nlohmann::json;
16namespace fs = std::filesystem;
17constexpr auto fruJson = "host_frus.json";
18const Json emptyJson{};
19const std::vector<Json> emptyJsonList{};
20
21HostPDRHandler::HostPDRHandler(int mctp_fd, uint8_t mctp_eid,
22 sdeventplus::Event& event, pldm_pdr* repo,
23 pldm_entity_association_tree* entityTree,
24 Requester& requester) :
25 mctp_fd(mctp_fd),
26 mctp_eid(mctp_eid), event(event), repo(repo), entityTree(entityTree),
27 requester(requester)
28{
29 fs::path hostFruJson(fs::path(HOST_JSONS_DIR) / fruJson);
30 if (fs::exists(hostFruJson))
31 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -050032 // Note parent entities for entities sent down by the host firmware.
33 // This will enable a merge of entity associations.
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050034 try
35 {
36 std::ifstream jsonFile(hostFruJson);
37 auto data = Json::parse(jsonFile, nullptr, false);
38 if (data.is_discarded())
39 {
40 std::cerr << "Parsing Host FRU json file failed" << std::endl;
41 }
42 else
43 {
44 auto entities = data.value("entities", emptyJsonList);
45 for (auto& entity : entities)
46 {
47 EntityType entityType = entity.value("entity_type", 0);
48 auto parent = entity.value("parent", emptyJson);
49 pldm_entity p{};
50 p.entity_type = parent.value("entity_type", 0);
51 p.entity_instance_num = parent.value("entity_instance", 0);
52 parents.emplace(entityType, std::move(p));
53 }
54 }
55 }
56 catch (const std::exception& e)
57 {
58 std::cerr << "Parsing Host FRU json file failed, exception = "
59 << e.what() << std::endl;
60 }
61 }
62}
63
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -050064void HostPDRHandler::fetchPDR(std::vector<uint32_t>&& recordHandles)
Pavithra Barithaya51efaf82020-04-02 02:42:27 -050065{
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -050066 pdrRecordHandles.clear();
67 pdrRecordHandles = std::move(recordHandles);
68
69 // Defer the actual fetch of PDRs from the host (by queuing the call on the
70 // main event loop). That way, we can respond to the platform event msg from
71 // the host firmware.
72 pdrFetchEvent = std::make_unique<sdeventplus::source::Defer>(
73 event, std::bind(std::mem_fn(&HostPDRHandler::_fetchPDR), this,
74 std::placeholders::_1));
75}
76
77void HostPDRHandler::_fetchPDR(sdeventplus::source::EventBase& /*source*/)
78{
79 pdrFetchEvent.reset();
80
Pavithra Barithaya51efaf82020-04-02 02:42:27 -050081 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
82 PLDM_GET_PDR_REQ_BYTES);
83 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
Pavithra Barithayae8beb892020-04-14 23:24:25 -050084 bool merged = false;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -050085
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -050086 for (auto recordHandle : pdrRecordHandles)
Pavithra Barithaya51efaf82020-04-02 02:42:27 -050087 {
88 auto instanceId = requester.getInstanceId(mctp_eid);
89
90 auto rc =
91 encode_get_pdr_req(instanceId, recordHandle, 0, PLDM_GET_FIRSTPART,
92 UINT16_MAX, 0, request, PLDM_GET_PDR_REQ_BYTES);
93 if (rc != PLDM_SUCCESS)
94 {
95 requester.markFree(mctp_eid, instanceId);
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -050096 std::cerr << "Failed to encode_get_pdr_req, rc = " << rc
97 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -050098 return;
99 }
100
101 uint8_t* responseMsg = nullptr;
102 size_t responseMsgSize{};
103 auto requesterRc =
104 pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(),
105 requestMsg.size(), &responseMsg, &responseMsgSize);
106 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{
107 responseMsg, std::free};
108 requester.markFree(mctp_eid, instanceId);
109 if (requesterRc != PLDM_REQUESTER_SUCCESS)
110 {
111 std::cerr << "Failed to send msg to fetch pdrs, rc = "
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500112 << requesterRc << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500113 return;
114 }
115
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500116 uint8_t completionCode{};
117 uint32_t nextRecordHandle{};
118 uint32_t nextDataTransferHandle{};
119 uint8_t transferFlag{};
120 uint16_t respCount{};
121 uint8_t transferCRC{};
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500122 auto responsePtr =
123 reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500124 rc = decode_get_pdr_resp(
125 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr),
126 &completionCode, &nextRecordHandle, &nextDataTransferHandle,
127 &transferFlag, &respCount, nullptr, 0, &transferCRC);
128 if (rc != PLDM_SUCCESS)
129 {
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500130 std::cerr << "Failed to decode_get_pdr_resp, rc = " << rc
131 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500132 }
133 else
134 {
135 std::vector<uint8_t> pdr(respCount, 0);
136 rc = decode_get_pdr_resp(
137 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr),
138 &completionCode, &nextRecordHandle, &nextDataTransferHandle,
139 &transferFlag, &respCount, pdr.data(), respCount, &transferCRC);
140 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
141 {
142 std::cerr << "Failed to decode_get_pdr_resp: "
143 << "rc=" << rc
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500144 << ", cc=" << static_cast<unsigned>(completionCode)
145 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500146 }
147 else
148 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500149 // Process the PDR host firmware sent us. The most common action
150 // is to add the PDR to the the BMC's PDR repo.
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500151 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
152 if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
153 {
154 mergeEntityAssociations(pdr);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500155 merged = true;
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500156 }
157 else
158 {
159 pldm_pdr_add(repo, pdr.data(), respCount, 0, true);
160 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500161 }
162 }
163 }
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500164
165 if (merged)
166 {
167 // We have merged host's entity association PDRs with our own. Send an
168 // event to the host firmware to indicate the same.
169 sendPDRRepositoryChgEvent(
170 std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)),
171 FORMAT_IS_PDR_HANDLES);
172 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500173}
174
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500175bool HostPDRHandler::getParent(EntityType type, pldm_entity& parent)
176{
177 auto found = parents.find(type);
178 if (found != parents.end())
179 {
180 parent.entity_type = found->second.entity_type;
181 parent.entity_instance_num = found->second.entity_instance_num;
182 return true;
183 }
184
185 return false;
186}
187
188void HostPDRHandler::mergeEntityAssociations(const std::vector<uint8_t>& pdr)
189{
190 size_t numEntities{};
191 pldm_entity* entities = nullptr;
192 bool merged = false;
193 auto entityPdr = reinterpret_cast<pldm_pdr_entity_association*>(
194 const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr));
195
196 pldm_entity_association_pdr_extract(pdr.data(), pdr.size(), &numEntities,
197 &entities);
198 for (size_t i = 0; i < numEntities; ++i)
199 {
200 pldm_entity parent{};
201 if (getParent(entities[i].entity_type, parent))
202 {
203 auto node = pldm_entity_association_tree_find(entityTree, &parent);
204 if (node)
205 {
206 pldm_entity_association_tree_add(entityTree, &entities[i], node,
207 entityPdr->association_type);
208 merged = true;
209 }
210 }
211 }
212 free(entities);
213
214 if (merged)
215 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500216 // Update our PDR repo with the merged entity association PDRs
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500217 pldm_entity_association_pdr_add(entityTree, repo, true);
218 }
219}
220
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500221void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes,
222 uint8_t eventDataFormat)
223{
224 assert(eventDataFormat == FORMAT_IS_PDR_HANDLES);
225
226 // Extract from the PDR repo record handles of PDRs we want the host
227 // to pull up.
228 std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED};
229 std::vector<uint8_t> numsOfChangeEntries(1);
230 std::vector<std::vector<ChangeEntry>> changeEntries(
231 numsOfChangeEntries.size());
232 for (auto pdrType : pdrTypes)
233 {
234 const pldm_pdr_record* record{};
235 do
236 {
237 record = pldm_pdr_find_record_by_type(repo, pdrType, record,
238 nullptr, nullptr);
239 if (record && pldm_pdr_record_is_remote(record))
240 {
241 changeEntries[0].push_back(
242 pldm_pdr_get_record_handle(repo, record));
243 }
244 } while (record);
245 }
246 if (changeEntries.empty())
247 {
248 return;
249 }
250 numsOfChangeEntries[0] = changeEntries[0].size();
251
252 // Encode PLDM platform event msg to indicate a PDR repo change.
253 size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH +
254 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH +
255 changeEntries[0].size() * sizeof(uint32_t);
256 std::vector<uint8_t> eventDataVec{};
257 eventDataVec.resize(maxSize);
258 auto eventData =
259 reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>(
260 eventDataVec.data());
261 size_t actualSize{};
262 auto firstEntry = changeEntries[0].data();
263 auto rc = encode_pldm_pdr_repository_chg_event_data(
264 eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(),
265 &firstEntry, eventData, &actualSize, maxSize);
266 if (rc != PLDM_SUCCESS)
267 {
268 std::cerr
269 << "Failed to encode_pldm_pdr_repository_chg_event_data, rc = "
270 << rc << std::endl;
271 return;
272 }
273 auto instanceId = requester.getInstanceId(mctp_eid);
274 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
275 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
276 actualSize);
277 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
278 rc = encode_platform_event_message_req(
279 instanceId, 1, 0, PLDM_PDR_REPOSITORY_CHG_EVENT, eventDataVec.data(),
280 actualSize, request);
281 if (rc != PLDM_SUCCESS)
282 {
283 requester.markFree(mctp_eid, instanceId);
284 std::cerr << "Failed to encode_platform_event_message_req, rc = " << rc
285 << std::endl;
286 return;
287 }
288
289 // Send up the event to host.
290 uint8_t* responseMsg = nullptr;
291 size_t responseMsgSize{};
292 auto requesterRc =
293 pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(),
294 &responseMsg, &responseMsgSize);
295 requester.markFree(mctp_eid, instanceId);
296 if (requesterRc != PLDM_REQUESTER_SUCCESS)
297 {
298 std::cerr << "Failed to send msg to report pdrs, rc = " << requesterRc
299 << std::endl;
300 return;
301 }
302 uint8_t completionCode{};
303 uint8_t status{};
304 auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
305 rc = decode_platform_event_message_resp(
306 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr), &completionCode,
307 &status);
308 free(responseMsg);
309 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
310 {
311 std::cerr << "Failed to decode_platform_event_message_resp: "
312 << "rc=" << rc
313 << ", cc=" << static_cast<unsigned>(completionCode)
314 << std::endl;
315 }
316}
317
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500318} // namespace pldm