blob: f9d30b51bf8d9debd4a889f399db1c9aaff98d52 [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 }
210 free(entities);
211
212 if (merged)
213 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500214 // Update our PDR repo with the merged entity association PDRs
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500215 pldm_entity_association_pdr_add(entityTree, repo, true);
216 }
217}
218
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500219void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes,
220 uint8_t eventDataFormat)
221{
222 assert(eventDataFormat == FORMAT_IS_PDR_HANDLES);
223
224 // Extract from the PDR repo record handles of PDRs we want the host
225 // to pull up.
226 std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED};
227 std::vector<uint8_t> numsOfChangeEntries(1);
228 std::vector<std::vector<ChangeEntry>> changeEntries(
229 numsOfChangeEntries.size());
230 for (auto pdrType : pdrTypes)
231 {
232 const pldm_pdr_record* record{};
233 do
234 {
235 record = pldm_pdr_find_record_by_type(repo, pdrType, record,
236 nullptr, nullptr);
237 if (record && pldm_pdr_record_is_remote(record))
238 {
239 changeEntries[0].push_back(
240 pldm_pdr_get_record_handle(repo, record));
241 }
242 } while (record);
243 }
244 if (changeEntries.empty())
245 {
246 return;
247 }
248 numsOfChangeEntries[0] = changeEntries[0].size();
249
250 // Encode PLDM platform event msg to indicate a PDR repo change.
251 size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH +
252 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH +
253 changeEntries[0].size() * sizeof(uint32_t);
254 std::vector<uint8_t> eventDataVec{};
255 eventDataVec.resize(maxSize);
256 auto eventData =
257 reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>(
258 eventDataVec.data());
259 size_t actualSize{};
260 auto firstEntry = changeEntries[0].data();
261 auto rc = encode_pldm_pdr_repository_chg_event_data(
262 eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(),
263 &firstEntry, eventData, &actualSize, maxSize);
264 if (rc != PLDM_SUCCESS)
265 {
266 std::cerr
267 << "Failed to encode_pldm_pdr_repository_chg_event_data, rc = "
268 << rc << std::endl;
269 return;
270 }
271 auto instanceId = requester.getInstanceId(mctp_eid);
272 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
273 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
274 actualSize);
275 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
276 rc = encode_platform_event_message_req(
277 instanceId, 1, 0, PLDM_PDR_REPOSITORY_CHG_EVENT, eventDataVec.data(),
Christian Geddes3bdb3c22020-05-01 14:55:39 -0500278 actualSize, request,
279 actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500280 if (rc != PLDM_SUCCESS)
281 {
282 requester.markFree(mctp_eid, instanceId);
283 std::cerr << "Failed to encode_platform_event_message_req, rc = " << rc
284 << std::endl;
285 return;
286 }
287
Tom Joseph74f27c72021-05-16 07:58:53 -0700288 auto platformEventMessageResponseHandler = [](mctp_eid_t /*eid*/,
289 const pldm_msg* response,
290 size_t respMsgLen) {
291 if (response == nullptr || !respMsgLen)
292 {
293 std::cerr << "Failed to receive response for the PDR repository "
294 "changed event"
295 << "\n";
296 return;
297 }
298
299 uint8_t completionCode{};
300 uint8_t status{};
301 auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response);
302 auto rc = decode_platform_event_message_resp(
303 responsePtr, respMsgLen - sizeof(pldm_msg_hdr), &completionCode,
304 &status);
Sampa Misrac0c79482021-06-02 08:01:54 -0500305 if (rc || completionCode)
Tom Joseph74f27c72021-05-16 07:58:53 -0700306 {
307 std::cerr << "Failed to decode_platform_event_message_resp: "
308 << "rc=" << rc
309 << ", cc=" << static_cast<unsigned>(completionCode)
310 << std::endl;
311 }
312 };
313
Sampa Misrac0c79482021-06-02 08:01:54 -0500314 rc = handler->registerRequest(
Tom Joseph74f27c72021-05-16 07:58:53 -0700315 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PDR_REPOSITORY_CHG_EVENT,
316 std::move(requestMsg), std::move(platformEventMessageResponseHandler));
Sampa Misrac0c79482021-06-02 08:01:54 -0500317 if (rc)
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500318 {
Tom Joseph74f27c72021-05-16 07:58:53 -0700319 std::cerr << "Failed to send the PDR repository changed event request"
320 << "\n";
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500321 }
322}
323
Sampa Misra868c8792020-05-26 03:12:13 -0500324void HostPDRHandler::parseStateSensorPDRs(const PDRList& stateSensorPDRs,
325 const TLPDRMap& tlpdrInfo)
326{
327 for (const auto& pdr : stateSensorPDRs)
328 {
329 SensorEntry sensorEntry{};
330 const auto& [terminusHandle, sensorID, sensorInfo] =
331 responder::pdr_utils::parseStateSensorPDR(pdr);
332 sensorEntry.sensorID = sensorID;
333 try
334 {
335 sensorEntry.terminusID = tlpdrInfo.at(terminusHandle);
336 }
337 // If there is no mapping for terminusHandle assign the reserved TID
338 // value of 0xFF to indicate that.
339 catch (const std::out_of_range& e)
340 {
341 sensorEntry.terminusID = PLDM_TID_RESERVED;
342 }
343 sensorMap.emplace(sensorEntry, std::move(sensorInfo));
344 }
345}
346
Sampa Misrac0c79482021-06-02 08:01:54 -0500347void HostPDRHandler::processHostPDRs(mctp_eid_t /*eid*/,
348 const pldm_msg* response,
349 size_t respMsgLen)
350{
351 static bool merged = false;
352 static PDRList stateSensorPDRs{};
353 static TLPDRMap tlpdrInfo{};
354 uint32_t nextRecordHandle{};
355 uint8_t completionCode{};
356 uint32_t nextDataTransferHandle{};
357 uint8_t transferFlag{};
358 uint16_t respCount{};
359 uint8_t transferCRC{};
360 if (response == nullptr || !respMsgLen)
361 {
362 std::cerr << "Failed to receive response for the GetPDR"
363 " command \n";
364 return;
365 }
366
367 auto rc = decode_get_pdr_resp(
368 response, respMsgLen /*- sizeof(pldm_msg_hdr)*/, &completionCode,
369 &nextRecordHandle, &nextDataTransferHandle, &transferFlag, &respCount,
370 nullptr, 0, &transferCRC);
371 std::vector<uint8_t> responsePDRMsg;
372 responsePDRMsg.resize(respMsgLen + sizeof(pldm_msg_hdr));
373 memcpy(responsePDRMsg.data(), response, respMsgLen + sizeof(pldm_msg_hdr));
374 if (verbose)
375 {
376 std::cout << "Receiving Msg:" << std::endl;
377 printBuffer(responsePDRMsg, verbose);
378 }
379 if (rc != PLDM_SUCCESS)
380 {
381 std::cerr << "Failed to decode_get_pdr_resp, rc = " << rc << std::endl;
382 return;
383 }
384 else
385 {
386 std::vector<uint8_t> pdr(respCount, 0);
387 rc = decode_get_pdr_resp(response, respMsgLen, &completionCode,
388 &nextRecordHandle, &nextDataTransferHandle,
389 &transferFlag, &respCount, pdr.data(),
390 respCount, &transferCRC);
391 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
392 {
393 std::cerr << "Failed to decode_get_pdr_resp: "
394 << "rc=" << rc
395 << ", cc=" << static_cast<unsigned>(completionCode)
396 << std::endl;
397 return;
398 }
399 else
400 {
401 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
402 if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
403 {
404 this->mergeEntityAssociations(pdr);
405 merged = true;
406 }
407 else
408 {
409 if (pdrHdr->type == PLDM_TERMINUS_LOCATOR_PDR)
410 {
411 auto tlpdr =
412 reinterpret_cast<const pldm_terminus_locator_pdr*>(
413 pdr.data());
414 tlpdrInfo.emplace(
415 static_cast<pldm::pdr::TerminusHandle>(
416 tlpdr->terminus_handle),
417 static_cast<pldm::pdr::TerminusID>(tlpdr->tid));
418 }
419 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR)
420 {
421 stateSensorPDRs.emplace_back(pdr);
422 }
423 pldm_pdr_add(repo, pdr.data(), respCount, 0, true);
424 }
425 }
426 }
427 if (!nextRecordHandle)
428 {
429 /*received last record*/
430 this->parseStateSensorPDRs(stateSensorPDRs, tlpdrInfo);
431 stateSensorPDRs.clear();
432 tlpdrInfo.clear();
433 if (merged)
434 {
435 merged = false;
436 deferredPDRRepoChgEvent =
437 std::make_unique<sdeventplus::source::Defer>(
438 event,
439 std::bind(
440 std::mem_fn((&HostPDRHandler::_processPDRRepoChgEvent)),
441 this, std::placeholders::_1));
442 }
443 }
444 else
445 {
446 deferredFetchPDREvent = std::make_unique<sdeventplus::source::Defer>(
447 event,
448 std::bind(std::mem_fn((&HostPDRHandler::_processFetchPDREvent)),
449 this, nextRecordHandle, std::placeholders::_1));
450 }
451}
452
453void HostPDRHandler::_processPDRRepoChgEvent(
454 sdeventplus::source::EventBase& /*source */)
455{
456 deferredPDRRepoChgEvent.reset();
457 this->sendPDRRepositoryChgEvent(
458 std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)),
459 FORMAT_IS_PDR_HANDLES);
460}
461
462void HostPDRHandler::_processFetchPDREvent(
463 uint32_t nextRecordHandle, sdeventplus::source::EventBase& /*source */)
464{
465 deferredFetchPDREvent.reset();
466 if (!this->pdrRecordHandles.empty())
467 {
468 nextRecordHandle = this->pdrRecordHandles.front();
469 this->pdrRecordHandles.pop_front();
470 }
471 this->getHostPDR(nextRecordHandle);
472}
473
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500474} // namespace pldm