blob: a2d4d1781c261e71f6d91668499b527747ed6459 [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
George Liu6492f522020-06-16 10:34:05 +08005#include "libpldm/requester/pldm.h"
6
Pavithra Barithayae8beb892020-04-14 23:24:25 -05007#include <assert.h>
8
Deepak Kodihalli87514cc2020-04-16 09:08:38 -05009#include <nlohmann/json.hpp>
10
George Liu6492f522020-06-16 10:34:05 +080011#include <fstream>
Pavithra Barithaya51efaf82020-04-02 02:42:27 -050012
13namespace pldm
14{
15
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050016using namespace pldm::utils;
17using namespace sdbusplus::bus::match::rules;
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050018using Json = nlohmann::json;
19namespace fs = std::filesystem;
20constexpr auto fruJson = "host_frus.json";
21const Json emptyJson{};
22const std::vector<Json> emptyJsonList{};
23
Tom Joseph74f27c72021-05-16 07:58:53 -070024HostPDRHandler::HostPDRHandler(
25 int mctp_fd, uint8_t mctp_eid, sdeventplus::Event& event, pldm_pdr* repo,
26 const std::string& eventsJsonsDir, pldm_entity_association_tree* entityTree,
27 pldm_entity_association_tree* bmcEntityTree, Requester& requester,
Sampa Misrac0c79482021-06-02 08:01:54 -050028 pldm::requester::Handler<pldm::requester::Request>* handler, bool verbose) :
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050029 mctp_fd(mctp_fd),
Pavithra Barithaya3aec9972020-12-14 01:55:44 -060030 mctp_eid(mctp_eid), event(event), repo(repo),
31 stateSensorHandler(eventsJsonsDir), entityTree(entityTree),
Tom Joseph74f27c72021-05-16 07:58:53 -070032 bmcEntityTree(bmcEntityTree), requester(requester), handler(handler),
33 verbose(verbose)
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050034{
35 fs::path hostFruJson(fs::path(HOST_JSONS_DIR) / fruJson);
36 if (fs::exists(hostFruJson))
37 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -050038 // Note parent entities for entities sent down by the host firmware.
39 // This will enable a merge of entity associations.
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050040 try
41 {
42 std::ifstream jsonFile(hostFruJson);
43 auto data = Json::parse(jsonFile, nullptr, false);
44 if (data.is_discarded())
45 {
46 std::cerr << "Parsing Host FRU json file failed" << std::endl;
47 }
48 else
49 {
50 auto entities = data.value("entities", emptyJsonList);
51 for (auto& entity : entities)
52 {
53 EntityType entityType = entity.value("entity_type", 0);
54 auto parent = entity.value("parent", emptyJson);
55 pldm_entity p{};
56 p.entity_type = parent.value("entity_type", 0);
57 p.entity_instance_num = parent.value("entity_instance", 0);
58 parents.emplace(entityType, std::move(p));
59 }
60 }
61 }
62 catch (const std::exception& e)
63 {
64 std::cerr << "Parsing Host FRU json file failed, exception = "
65 << e.what() << std::endl;
66 }
67 }
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050068
69 hostOffMatch = std::make_unique<sdbusplus::bus::match::match>(
70 pldm::utils::DBusHandler::getBus(),
71 propertiesChanged("/xyz/openbmc_project/state/host0",
72 "xyz.openbmc_project.State.Host"),
Sampa Misrac073a202021-05-08 10:56:05 -050073 [this, repo, entityTree,
74 bmcEntityTree](sdbusplus::message::message& msg) {
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050075 DbusChangedProps props{};
76 std::string intf;
77 msg.read(intf, props);
78 const auto itr = props.find("CurrentHostState");
79 if (itr != props.end())
80 {
81 PropertyValue value = itr->second;
82 auto propVal = std::get<std::string>(value);
83 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
84 {
85 pldm_pdr_remove_remote_pdrs(repo);
Sampa Misrac073a202021-05-08 10:56:05 -050086 pldm_entity_association_tree_destroy_root(entityTree);
87 pldm_entity_association_tree_copy_root(bmcEntityTree,
88 entityTree);
Tom Josephb4268602020-04-17 17:20:45 +053089 this->sensorMap.clear();
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050090 }
91 }
92 });
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050093}
94
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -050095void HostPDRHandler::fetchPDR(PDRRecordHandles&& recordHandles)
Pavithra Barithaya51efaf82020-04-02 02:42:27 -050096{
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -050097 pdrRecordHandles.clear();
98 pdrRecordHandles = std::move(recordHandles);
99
100 // Defer the actual fetch of PDRs from the host (by queuing the call on the
101 // main event loop). That way, we can respond to the platform event msg from
102 // the host firmware.
103 pdrFetchEvent = std::make_unique<sdeventplus::source::Defer>(
104 event, std::bind(std::mem_fn(&HostPDRHandler::_fetchPDR), this,
105 std::placeholders::_1));
106}
107
108void HostPDRHandler::_fetchPDR(sdeventplus::source::EventBase& /*source*/)
109{
Sampa Misrac0c79482021-06-02 08:01:54 -0500110 getHostPDR();
111}
112
113void HostPDRHandler::getHostPDR(uint32_t nextRecordHandle)
114{
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500115 pdrFetchEvent.reset();
116
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500117 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
118 PLDM_GET_PDR_REQ_BYTES);
119 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -0500120 uint32_t recordHandle{};
Sampa Misrac0c79482021-06-02 08:01:54 -0500121 if (!nextRecordHandle)
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -0500122 {
Sampa Misrac0c79482021-06-02 08:01:54 -0500123 if (!pdrRecordHandles.empty())
124 {
125 recordHandle = pdrRecordHandles.front();
126 pdrRecordHandles.pop_front();
127 }
128 }
129 else
130 {
131 recordHandle = nextRecordHandle;
132 }
133 auto instanceId = requester.getInstanceId(mctp_eid);
134
135 auto rc =
136 encode_get_pdr_req(instanceId, recordHandle, 0, PLDM_GET_FIRSTPART,
137 UINT16_MAX, 0, request, PLDM_GET_PDR_REQ_BYTES);
138 if (rc != PLDM_SUCCESS)
139 {
140 requester.markFree(mctp_eid, instanceId);
141 std::cerr << "Failed to encode_get_pdr_req, rc = " << rc << std::endl;
142 return;
143 }
144 if (verbose)
145 {
146 std::cout << "Sending Msg:" << std::endl;
147 printBuffer(requestMsg, verbose);
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -0500148 }
149
Sampa Misrac0c79482021-06-02 08:01:54 -0500150 rc = handler->registerRequest(
151 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_GET_PDR,
152 std::move(requestMsg),
153 std::move(std::bind_front(&HostPDRHandler::processHostPDRs, this)));
154 if (rc)
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500155 {
Sampa Misrac0c79482021-06-02 08:01:54 -0500156 std::cerr << "Failed to send the GetPDR request to Host \n";
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500157 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500158}
159
Pavithra Barithaya3aec9972020-12-14 01:55:44 -0600160int HostPDRHandler::handleStateSensorEvent(const StateSensorEntry& entry,
161 pdr::EventState state)
162{
163 auto rc = stateSensorHandler.eventAction(entry, state);
164 if (rc != PLDM_SUCCESS)
165 {
166 std::cerr << "Failed to fetch and update D-bus property, rc = " << rc
167 << std::endl;
168 return rc;
169 }
170 return PLDM_SUCCESS;
171}
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500172bool HostPDRHandler::getParent(EntityType type, pldm_entity& parent)
173{
174 auto found = parents.find(type);
175 if (found != parents.end())
176 {
177 parent.entity_type = found->second.entity_type;
178 parent.entity_instance_num = found->second.entity_instance_num;
179 return true;
180 }
181
182 return false;
183}
184
185void HostPDRHandler::mergeEntityAssociations(const std::vector<uint8_t>& pdr)
186{
187 size_t numEntities{};
188 pldm_entity* entities = nullptr;
189 bool merged = false;
190 auto entityPdr = reinterpret_cast<pldm_pdr_entity_association*>(
191 const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr));
192
193 pldm_entity_association_pdr_extract(pdr.data(), pdr.size(), &numEntities,
194 &entities);
195 for (size_t i = 0; i < numEntities; ++i)
196 {
197 pldm_entity parent{};
198 if (getParent(entities[i].entity_type, parent))
199 {
200 auto node = pldm_entity_association_tree_find(entityTree, &parent);
201 if (node)
202 {
George Liu64a8f0f2021-06-12 10:56:11 +0800203 pldm_entity_association_tree_add(entityTree, &entities[i],
204 0xFFFF, node,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500205 entityPdr->association_type);
206 merged = true;
207 }
208 }
209 }
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500210
211 if (merged)
212 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500213 // Update our PDR repo with the merged entity association PDRs
Sampa Misra719ed392021-06-04 05:15:13 -0500214 pldm_entity_node* node = nullptr;
215 pldm_find_entity_ref_in_tree(entityTree, entities[0], &node);
216 if (node == nullptr)
217 {
218 std::cerr
219 << "\ncould not find referrence of the entity in the tree \n";
220 }
221 else
222 {
223 pldm_entity_association_pdr_add_from_node(node, repo, &entities,
224 numEntities, true);
225 }
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500226 }
Sampa Misra719ed392021-06-04 05:15:13 -0500227 free(entities);
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500228}
229
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500230void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes,
231 uint8_t eventDataFormat)
232{
233 assert(eventDataFormat == FORMAT_IS_PDR_HANDLES);
234
235 // Extract from the PDR repo record handles of PDRs we want the host
236 // to pull up.
237 std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED};
238 std::vector<uint8_t> numsOfChangeEntries(1);
239 std::vector<std::vector<ChangeEntry>> changeEntries(
240 numsOfChangeEntries.size());
241 for (auto pdrType : pdrTypes)
242 {
243 const pldm_pdr_record* record{};
244 do
245 {
246 record = pldm_pdr_find_record_by_type(repo, pdrType, record,
247 nullptr, nullptr);
248 if (record && pldm_pdr_record_is_remote(record))
249 {
250 changeEntries[0].push_back(
251 pldm_pdr_get_record_handle(repo, record));
252 }
253 } while (record);
254 }
255 if (changeEntries.empty())
256 {
257 return;
258 }
259 numsOfChangeEntries[0] = changeEntries[0].size();
260
261 // Encode PLDM platform event msg to indicate a PDR repo change.
262 size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH +
263 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH +
264 changeEntries[0].size() * sizeof(uint32_t);
265 std::vector<uint8_t> eventDataVec{};
266 eventDataVec.resize(maxSize);
267 auto eventData =
268 reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>(
269 eventDataVec.data());
270 size_t actualSize{};
271 auto firstEntry = changeEntries[0].data();
272 auto rc = encode_pldm_pdr_repository_chg_event_data(
273 eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(),
274 &firstEntry, eventData, &actualSize, maxSize);
275 if (rc != PLDM_SUCCESS)
276 {
277 std::cerr
278 << "Failed to encode_pldm_pdr_repository_chg_event_data, rc = "
279 << rc << std::endl;
280 return;
281 }
282 auto instanceId = requester.getInstanceId(mctp_eid);
283 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
284 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
285 actualSize);
286 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
287 rc = encode_platform_event_message_req(
288 instanceId, 1, 0, PLDM_PDR_REPOSITORY_CHG_EVENT, eventDataVec.data(),
Christian Geddes3bdb3c22020-05-01 14:55:39 -0500289 actualSize, request,
290 actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500291 if (rc != PLDM_SUCCESS)
292 {
293 requester.markFree(mctp_eid, instanceId);
294 std::cerr << "Failed to encode_platform_event_message_req, rc = " << rc
295 << std::endl;
296 return;
297 }
298
Tom Joseph74f27c72021-05-16 07:58:53 -0700299 auto platformEventMessageResponseHandler = [](mctp_eid_t /*eid*/,
300 const pldm_msg* response,
301 size_t respMsgLen) {
302 if (response == nullptr || !respMsgLen)
303 {
304 std::cerr << "Failed to receive response for the PDR repository "
305 "changed event"
306 << "\n";
307 return;
308 }
309
310 uint8_t completionCode{};
311 uint8_t status{};
312 auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response);
313 auto rc = decode_platform_event_message_resp(
314 responsePtr, respMsgLen - sizeof(pldm_msg_hdr), &completionCode,
315 &status);
Sampa Misrac0c79482021-06-02 08:01:54 -0500316 if (rc || completionCode)
Tom Joseph74f27c72021-05-16 07:58:53 -0700317 {
318 std::cerr << "Failed to decode_platform_event_message_resp: "
319 << "rc=" << rc
320 << ", cc=" << static_cast<unsigned>(completionCode)
321 << std::endl;
322 }
323 };
324
Sampa Misrac0c79482021-06-02 08:01:54 -0500325 rc = handler->registerRequest(
Tom Joseph74f27c72021-05-16 07:58:53 -0700326 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PDR_REPOSITORY_CHG_EVENT,
327 std::move(requestMsg), std::move(platformEventMessageResponseHandler));
Sampa Misrac0c79482021-06-02 08:01:54 -0500328 if (rc)
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500329 {
Tom Joseph74f27c72021-05-16 07:58:53 -0700330 std::cerr << "Failed to send the PDR repository changed event request"
331 << "\n";
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500332 }
333}
334
Sampa Misra868c8792020-05-26 03:12:13 -0500335void HostPDRHandler::parseStateSensorPDRs(const PDRList& stateSensorPDRs,
336 const TLPDRMap& tlpdrInfo)
337{
338 for (const auto& pdr : stateSensorPDRs)
339 {
340 SensorEntry sensorEntry{};
341 const auto& [terminusHandle, sensorID, sensorInfo] =
342 responder::pdr_utils::parseStateSensorPDR(pdr);
343 sensorEntry.sensorID = sensorID;
344 try
345 {
346 sensorEntry.terminusID = tlpdrInfo.at(terminusHandle);
347 }
348 // If there is no mapping for terminusHandle assign the reserved TID
349 // value of 0xFF to indicate that.
350 catch (const std::out_of_range& e)
351 {
352 sensorEntry.terminusID = PLDM_TID_RESERVED;
353 }
354 sensorMap.emplace(sensorEntry, std::move(sensorInfo));
355 }
356}
357
Sampa Misrac0c79482021-06-02 08:01:54 -0500358void HostPDRHandler::processHostPDRs(mctp_eid_t /*eid*/,
359 const pldm_msg* response,
360 size_t respMsgLen)
361{
362 static bool merged = false;
363 static PDRList stateSensorPDRs{};
364 static TLPDRMap tlpdrInfo{};
365 uint32_t nextRecordHandle{};
366 uint8_t completionCode{};
367 uint32_t nextDataTransferHandle{};
368 uint8_t transferFlag{};
369 uint16_t respCount{};
370 uint8_t transferCRC{};
371 if (response == nullptr || !respMsgLen)
372 {
373 std::cerr << "Failed to receive response for the GetPDR"
374 " command \n";
375 return;
376 }
377
378 auto rc = decode_get_pdr_resp(
379 response, respMsgLen /*- sizeof(pldm_msg_hdr)*/, &completionCode,
380 &nextRecordHandle, &nextDataTransferHandle, &transferFlag, &respCount,
381 nullptr, 0, &transferCRC);
382 std::vector<uint8_t> responsePDRMsg;
383 responsePDRMsg.resize(respMsgLen + sizeof(pldm_msg_hdr));
384 memcpy(responsePDRMsg.data(), response, respMsgLen + sizeof(pldm_msg_hdr));
385 if (verbose)
386 {
387 std::cout << "Receiving Msg:" << std::endl;
388 printBuffer(responsePDRMsg, verbose);
389 }
390 if (rc != PLDM_SUCCESS)
391 {
392 std::cerr << "Failed to decode_get_pdr_resp, rc = " << rc << std::endl;
393 return;
394 }
395 else
396 {
397 std::vector<uint8_t> pdr(respCount, 0);
398 rc = decode_get_pdr_resp(response, respMsgLen, &completionCode,
399 &nextRecordHandle, &nextDataTransferHandle,
400 &transferFlag, &respCount, pdr.data(),
401 respCount, &transferCRC);
402 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
403 {
404 std::cerr << "Failed to decode_get_pdr_resp: "
405 << "rc=" << rc
406 << ", cc=" << static_cast<unsigned>(completionCode)
407 << std::endl;
408 return;
409 }
410 else
411 {
412 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
413 if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
414 {
415 this->mergeEntityAssociations(pdr);
416 merged = true;
417 }
418 else
419 {
420 if (pdrHdr->type == PLDM_TERMINUS_LOCATOR_PDR)
421 {
422 auto tlpdr =
423 reinterpret_cast<const pldm_terminus_locator_pdr*>(
424 pdr.data());
425 tlpdrInfo.emplace(
426 static_cast<pldm::pdr::TerminusHandle>(
427 tlpdr->terminus_handle),
428 static_cast<pldm::pdr::TerminusID>(tlpdr->tid));
429 }
430 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR)
431 {
432 stateSensorPDRs.emplace_back(pdr);
433 }
434 pldm_pdr_add(repo, pdr.data(), respCount, 0, true);
435 }
436 }
437 }
438 if (!nextRecordHandle)
439 {
440 /*received last record*/
441 this->parseStateSensorPDRs(stateSensorPDRs, tlpdrInfo);
442 stateSensorPDRs.clear();
443 tlpdrInfo.clear();
444 if (merged)
445 {
446 merged = false;
447 deferredPDRRepoChgEvent =
448 std::make_unique<sdeventplus::source::Defer>(
449 event,
450 std::bind(
451 std::mem_fn((&HostPDRHandler::_processPDRRepoChgEvent)),
452 this, std::placeholders::_1));
453 }
454 }
455 else
456 {
457 deferredFetchPDREvent = std::make_unique<sdeventplus::source::Defer>(
458 event,
459 std::bind(std::mem_fn((&HostPDRHandler::_processFetchPDREvent)),
460 this, nextRecordHandle, std::placeholders::_1));
461 }
462}
463
464void HostPDRHandler::_processPDRRepoChgEvent(
465 sdeventplus::source::EventBase& /*source */)
466{
467 deferredPDRRepoChgEvent.reset();
468 this->sendPDRRepositoryChgEvent(
469 std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)),
470 FORMAT_IS_PDR_HANDLES);
471}
472
473void HostPDRHandler::_processFetchPDREvent(
474 uint32_t nextRecordHandle, sdeventplus::source::EventBase& /*source */)
475{
476 deferredFetchPDREvent.reset();
477 if (!this->pdrRecordHandles.empty())
478 {
479 nextRecordHandle = this->pdrRecordHandles.front();
480 this->pdrRecordHandles.pop_front();
481 }
482 this->getHostPDR(nextRecordHandle);
483}
484
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500485} // namespace pldm