blob: 226fc23cd18ff1f1167c1cf6f63461cad73d676f [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,
28 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{
110 pdrFetchEvent.reset();
111
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500112 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
113 PLDM_GET_PDR_REQ_BYTES);
114 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500115 bool merged = false;
Sampa Misra868c8792020-05-26 03:12:13 -0500116 PDRList stateSensorPDRs{};
117 TLPDRMap tlpdrInfo{};
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500118
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -0500119 uint32_t nextRecordHandle{};
120 uint32_t recordHandle{};
121 bool isFormatRecHandles = false;
122 if (!pdrRecordHandles.empty())
123 {
124 recordHandle = pdrRecordHandles.front();
125 pdrRecordHandles.pop_front();
126 isFormatRecHandles = true;
127 }
128
129 do
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500130 {
131 auto instanceId = requester.getInstanceId(mctp_eid);
132
133 auto rc =
134 encode_get_pdr_req(instanceId, recordHandle, 0, PLDM_GET_FIRSTPART,
135 UINT16_MAX, 0, request, PLDM_GET_PDR_REQ_BYTES);
136 if (rc != PLDM_SUCCESS)
137 {
138 requester.markFree(mctp_eid, instanceId);
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500139 std::cerr << "Failed to encode_get_pdr_req, rc = " << rc
140 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500141 return;
142 }
Sridevi Rameshae28bc72020-12-10 07:21:16 -0600143 if (verbose)
144 {
145 std::cout << "Sending Msg:" << std::endl;
146 printBuffer(requestMsg, verbose);
147 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500148
149 uint8_t* responseMsg = nullptr;
150 size_t responseMsgSize{};
151 auto requesterRc =
152 pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(),
153 requestMsg.size(), &responseMsg, &responseMsgSize);
154 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{
155 responseMsg, std::free};
156 requester.markFree(mctp_eid, instanceId);
157 if (requesterRc != PLDM_REQUESTER_SUCCESS)
158 {
159 std::cerr << "Failed to send msg to fetch pdrs, rc = "
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500160 << requesterRc << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500161 return;
162 }
163
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500164 uint8_t completionCode{};
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500165 uint32_t nextDataTransferHandle{};
166 uint8_t transferFlag{};
167 uint16_t respCount{};
168 uint8_t transferCRC{};
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500169 auto responsePtr =
170 reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500171 rc = decode_get_pdr_resp(
172 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr),
173 &completionCode, &nextRecordHandle, &nextDataTransferHandle,
174 &transferFlag, &respCount, nullptr, 0, &transferCRC);
Sridevi Rameshae28bc72020-12-10 07:21:16 -0600175
176 std::vector<uint8_t> responsePDRMsg;
177 responsePDRMsg.resize(responseMsgSize);
178 memcpy(responsePDRMsg.data(), responsePtr, responsePDRMsg.size());
179 if (verbose)
180 {
181 std::cout << "Receiving Msg:" << std::endl;
182 printBuffer(responsePDRMsg, verbose);
183 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500184 if (rc != PLDM_SUCCESS)
185 {
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500186 std::cerr << "Failed to decode_get_pdr_resp, rc = " << rc
187 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500188 }
189 else
190 {
191 std::vector<uint8_t> pdr(respCount, 0);
192 rc = decode_get_pdr_resp(
193 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr),
194 &completionCode, &nextRecordHandle, &nextDataTransferHandle,
195 &transferFlag, &respCount, pdr.data(), respCount, &transferCRC);
196 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
197 {
198 std::cerr << "Failed to decode_get_pdr_resp: "
199 << "rc=" << rc
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500200 << ", cc=" << static_cast<unsigned>(completionCode)
201 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500202 }
203 else
204 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500205 // Process the PDR host firmware sent us. The most common action
206 // is to add the PDR to the the BMC's PDR repo.
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500207 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
208 if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
209 {
210 mergeEntityAssociations(pdr);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500211 merged = true;
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500212 }
213 else
214 {
Sampa Misra868c8792020-05-26 03:12:13 -0500215 if (pdrHdr->type == PLDM_TERMINUS_LOCATOR_PDR)
Tom Josephb4268602020-04-17 17:20:45 +0530216 {
Sampa Misra868c8792020-05-26 03:12:13 -0500217 auto tlpdr =
218 reinterpret_cast<const pldm_terminus_locator_pdr*>(
219 pdr.data());
220 tlpdrInfo.emplace(
221 static_cast<pdr::TerminusHandle>(
222 tlpdr->terminus_handle),
223 static_cast<pdr::TerminusID>(tlpdr->tid));
224 }
225 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR)
226 {
227 stateSensorPDRs.emplace_back(pdr);
Tom Josephb4268602020-04-17 17:20:45 +0530228 }
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500229 pldm_pdr_add(repo, pdr.data(), respCount, 0, true);
230 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500231 }
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -0500232
233 recordHandle = nextRecordHandle;
234 if (!pdrRecordHandles.empty())
235 {
236 recordHandle = pdrRecordHandles.front();
237 pdrRecordHandles.pop_front();
238 }
239 else if (isFormatRecHandles)
240 {
241 break;
242 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500243 }
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -0500244 } while (recordHandle);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500245
Sampa Misra868c8792020-05-26 03:12:13 -0500246 parseStateSensorPDRs(stateSensorPDRs, tlpdrInfo);
247
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500248 if (merged)
249 {
250 // We have merged host's entity association PDRs with our own. Send an
251 // event to the host firmware to indicate the same.
252 sendPDRRepositoryChgEvent(
253 std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)),
254 FORMAT_IS_PDR_HANDLES);
255 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500256}
257
Pavithra Barithaya3aec9972020-12-14 01:55:44 -0600258int HostPDRHandler::handleStateSensorEvent(const StateSensorEntry& entry,
259 pdr::EventState state)
260{
261 auto rc = stateSensorHandler.eventAction(entry, state);
262 if (rc != PLDM_SUCCESS)
263 {
264 std::cerr << "Failed to fetch and update D-bus property, rc = " << rc
265 << std::endl;
266 return rc;
267 }
268 return PLDM_SUCCESS;
269}
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500270bool HostPDRHandler::getParent(EntityType type, pldm_entity& parent)
271{
272 auto found = parents.find(type);
273 if (found != parents.end())
274 {
275 parent.entity_type = found->second.entity_type;
276 parent.entity_instance_num = found->second.entity_instance_num;
277 return true;
278 }
279
280 return false;
281}
282
283void HostPDRHandler::mergeEntityAssociations(const std::vector<uint8_t>& pdr)
284{
285 size_t numEntities{};
286 pldm_entity* entities = nullptr;
287 bool merged = false;
288 auto entityPdr = reinterpret_cast<pldm_pdr_entity_association*>(
289 const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr));
290
291 pldm_entity_association_pdr_extract(pdr.data(), pdr.size(), &numEntities,
292 &entities);
293 for (size_t i = 0; i < numEntities; ++i)
294 {
295 pldm_entity parent{};
296 if (getParent(entities[i].entity_type, parent))
297 {
298 auto node = pldm_entity_association_tree_find(entityTree, &parent);
299 if (node)
300 {
301 pldm_entity_association_tree_add(entityTree, &entities[i], node,
302 entityPdr->association_type);
303 merged = true;
304 }
305 }
306 }
307 free(entities);
308
309 if (merged)
310 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500311 // Update our PDR repo with the merged entity association PDRs
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500312 pldm_entity_association_pdr_add(entityTree, repo, true);
313 }
314}
315
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500316void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes,
317 uint8_t eventDataFormat)
318{
319 assert(eventDataFormat == FORMAT_IS_PDR_HANDLES);
320
321 // Extract from the PDR repo record handles of PDRs we want the host
322 // to pull up.
323 std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED};
324 std::vector<uint8_t> numsOfChangeEntries(1);
325 std::vector<std::vector<ChangeEntry>> changeEntries(
326 numsOfChangeEntries.size());
327 for (auto pdrType : pdrTypes)
328 {
329 const pldm_pdr_record* record{};
330 do
331 {
332 record = pldm_pdr_find_record_by_type(repo, pdrType, record,
333 nullptr, nullptr);
334 if (record && pldm_pdr_record_is_remote(record))
335 {
336 changeEntries[0].push_back(
337 pldm_pdr_get_record_handle(repo, record));
338 }
339 } while (record);
340 }
341 if (changeEntries.empty())
342 {
343 return;
344 }
345 numsOfChangeEntries[0] = changeEntries[0].size();
346
347 // Encode PLDM platform event msg to indicate a PDR repo change.
348 size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH +
349 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH +
350 changeEntries[0].size() * sizeof(uint32_t);
351 std::vector<uint8_t> eventDataVec{};
352 eventDataVec.resize(maxSize);
353 auto eventData =
354 reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>(
355 eventDataVec.data());
356 size_t actualSize{};
357 auto firstEntry = changeEntries[0].data();
358 auto rc = encode_pldm_pdr_repository_chg_event_data(
359 eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(),
360 &firstEntry, eventData, &actualSize, maxSize);
361 if (rc != PLDM_SUCCESS)
362 {
363 std::cerr
364 << "Failed to encode_pldm_pdr_repository_chg_event_data, rc = "
365 << rc << std::endl;
366 return;
367 }
368 auto instanceId = requester.getInstanceId(mctp_eid);
369 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
370 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
371 actualSize);
372 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
373 rc = encode_platform_event_message_req(
374 instanceId, 1, 0, PLDM_PDR_REPOSITORY_CHG_EVENT, eventDataVec.data(),
Christian Geddes3bdb3c22020-05-01 14:55:39 -0500375 actualSize, request,
376 actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500377 if (rc != PLDM_SUCCESS)
378 {
379 requester.markFree(mctp_eid, instanceId);
380 std::cerr << "Failed to encode_platform_event_message_req, rc = " << rc
381 << std::endl;
382 return;
383 }
384
Tom Joseph74f27c72021-05-16 07:58:53 -0700385 auto platformEventMessageResponseHandler = [](mctp_eid_t /*eid*/,
386 const pldm_msg* response,
387 size_t respMsgLen) {
388 if (response == nullptr || !respMsgLen)
389 {
390 std::cerr << "Failed to receive response for the PDR repository "
391 "changed event"
392 << "\n";
393 return;
394 }
395
396 uint8_t completionCode{};
397 uint8_t status{};
398 auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response);
399 auto rc = decode_platform_event_message_resp(
400 responsePtr, respMsgLen - sizeof(pldm_msg_hdr), &completionCode,
401 &status);
402 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
403 {
404 std::cerr << "Failed to decode_platform_event_message_resp: "
405 << "rc=" << rc
406 << ", cc=" << static_cast<unsigned>(completionCode)
407 << std::endl;
408 }
409 };
410
411 rc = handler.registerRequest(
412 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PDR_REPOSITORY_CHG_EVENT,
413 std::move(requestMsg), std::move(platformEventMessageResponseHandler));
414 if (rc != PLDM_SUCCESS)
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500415 {
Tom Joseph74f27c72021-05-16 07:58:53 -0700416 std::cerr << "Failed to send the PDR repository changed event request"
417 << "\n";
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500418 }
419}
420
Sampa Misra868c8792020-05-26 03:12:13 -0500421void HostPDRHandler::parseStateSensorPDRs(const PDRList& stateSensorPDRs,
422 const TLPDRMap& tlpdrInfo)
423{
424 for (const auto& pdr : stateSensorPDRs)
425 {
426 SensorEntry sensorEntry{};
427 const auto& [terminusHandle, sensorID, sensorInfo] =
428 responder::pdr_utils::parseStateSensorPDR(pdr);
429 sensorEntry.sensorID = sensorID;
430 try
431 {
432 sensorEntry.terminusID = tlpdrInfo.at(terminusHandle);
433 }
434 // If there is no mapping for terminusHandle assign the reserved TID
435 // value of 0xFF to indicate that.
436 catch (const std::out_of_range& e)
437 {
438 sensorEntry.terminusID = PLDM_TID_RESERVED;
439 }
440 sensorMap.emplace(sensorEntry, std::move(sensorInfo));
441 }
442}
443
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500444} // namespace pldm