blob: e6bf7d75b58e386ad91986e207764a0dbeb11861 [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
24HostPDRHandler::HostPDRHandler(int mctp_fd, uint8_t mctp_eid,
25 sdeventplus::Event& event, pldm_pdr* repo,
Pavithra Barithaya3aec9972020-12-14 01:55:44 -060026 const std::string& eventsJsonsDir,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050027 pldm_entity_association_tree* entityTree,
Sridevi Rameshae28bc72020-12-10 07:21:16 -060028 Requester& requester, 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),
Sridevi Rameshae28bc72020-12-10 07:21:16 -060032 requester(requester), verbose(verbose)
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050033{
34 fs::path hostFruJson(fs::path(HOST_JSONS_DIR) / fruJson);
35 if (fs::exists(hostFruJson))
36 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -050037 // Note parent entities for entities sent down by the host firmware.
38 // This will enable a merge of entity associations.
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050039 try
40 {
41 std::ifstream jsonFile(hostFruJson);
42 auto data = Json::parse(jsonFile, nullptr, false);
43 if (data.is_discarded())
44 {
45 std::cerr << "Parsing Host FRU json file failed" << std::endl;
46 }
47 else
48 {
49 auto entities = data.value("entities", emptyJsonList);
50 for (auto& entity : entities)
51 {
52 EntityType entityType = entity.value("entity_type", 0);
53 auto parent = entity.value("parent", emptyJson);
54 pldm_entity p{};
55 p.entity_type = parent.value("entity_type", 0);
56 p.entity_instance_num = parent.value("entity_instance", 0);
57 parents.emplace(entityType, std::move(p));
58 }
59 }
60 }
61 catch (const std::exception& e)
62 {
63 std::cerr << "Parsing Host FRU json file failed, exception = "
64 << e.what() << std::endl;
65 }
66 }
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050067
68 hostOffMatch = std::make_unique<sdbusplus::bus::match::match>(
69 pldm::utils::DBusHandler::getBus(),
70 propertiesChanged("/xyz/openbmc_project/state/host0",
71 "xyz.openbmc_project.State.Host"),
Tom Josephb4268602020-04-17 17:20:45 +053072 [this, repo](sdbusplus::message::message& msg) {
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050073 DbusChangedProps props{};
74 std::string intf;
75 msg.read(intf, props);
76 const auto itr = props.find("CurrentHostState");
77 if (itr != props.end())
78 {
79 PropertyValue value = itr->second;
80 auto propVal = std::get<std::string>(value);
81 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
82 {
83 pldm_pdr_remove_remote_pdrs(repo);
Tom Josephb4268602020-04-17 17:20:45 +053084 this->sensorMap.clear();
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050085 }
86 }
87 });
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050088}
89
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -050090void HostPDRHandler::fetchPDR(PDRRecordHandles&& recordHandles)
Pavithra Barithaya51efaf82020-04-02 02:42:27 -050091{
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -050092 pdrRecordHandles.clear();
93 pdrRecordHandles = std::move(recordHandles);
94
95 // Defer the actual fetch of PDRs from the host (by queuing the call on the
96 // main event loop). That way, we can respond to the platform event msg from
97 // the host firmware.
98 pdrFetchEvent = std::make_unique<sdeventplus::source::Defer>(
99 event, std::bind(std::mem_fn(&HostPDRHandler::_fetchPDR), this,
100 std::placeholders::_1));
101}
102
103void HostPDRHandler::_fetchPDR(sdeventplus::source::EventBase& /*source*/)
104{
105 pdrFetchEvent.reset();
106
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500107 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
108 PLDM_GET_PDR_REQ_BYTES);
109 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500110 bool merged = false;
Sampa Misra868c8792020-05-26 03:12:13 -0500111 PDRList stateSensorPDRs{};
112 TLPDRMap tlpdrInfo{};
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500113
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -0500114 uint32_t nextRecordHandle{};
115 uint32_t recordHandle{};
116 bool isFormatRecHandles = false;
117 if (!pdrRecordHandles.empty())
118 {
119 recordHandle = pdrRecordHandles.front();
120 pdrRecordHandles.pop_front();
121 isFormatRecHandles = true;
122 }
123
124 do
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500125 {
126 auto instanceId = requester.getInstanceId(mctp_eid);
127
128 auto rc =
129 encode_get_pdr_req(instanceId, recordHandle, 0, PLDM_GET_FIRSTPART,
130 UINT16_MAX, 0, request, PLDM_GET_PDR_REQ_BYTES);
131 if (rc != PLDM_SUCCESS)
132 {
133 requester.markFree(mctp_eid, instanceId);
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500134 std::cerr << "Failed to encode_get_pdr_req, rc = " << rc
135 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500136 return;
137 }
Sridevi Rameshae28bc72020-12-10 07:21:16 -0600138 if (verbose)
139 {
140 std::cout << "Sending Msg:" << std::endl;
141 printBuffer(requestMsg, verbose);
142 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500143
144 uint8_t* responseMsg = nullptr;
145 size_t responseMsgSize{};
146 auto requesterRc =
147 pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(),
148 requestMsg.size(), &responseMsg, &responseMsgSize);
149 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{
150 responseMsg, std::free};
151 requester.markFree(mctp_eid, instanceId);
152 if (requesterRc != PLDM_REQUESTER_SUCCESS)
153 {
154 std::cerr << "Failed to send msg to fetch pdrs, rc = "
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500155 << requesterRc << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500156 return;
157 }
158
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500159 uint8_t completionCode{};
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500160 uint32_t nextDataTransferHandle{};
161 uint8_t transferFlag{};
162 uint16_t respCount{};
163 uint8_t transferCRC{};
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500164 auto responsePtr =
165 reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500166 rc = decode_get_pdr_resp(
167 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr),
168 &completionCode, &nextRecordHandle, &nextDataTransferHandle,
169 &transferFlag, &respCount, nullptr, 0, &transferCRC);
Sridevi Rameshae28bc72020-12-10 07:21:16 -0600170
171 std::vector<uint8_t> responsePDRMsg;
172 responsePDRMsg.resize(responseMsgSize);
173 memcpy(responsePDRMsg.data(), responsePtr, responsePDRMsg.size());
174 if (verbose)
175 {
176 std::cout << "Receiving Msg:" << std::endl;
177 printBuffer(responsePDRMsg, verbose);
178 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500179 if (rc != PLDM_SUCCESS)
180 {
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500181 std::cerr << "Failed to decode_get_pdr_resp, rc = " << rc
182 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500183 }
184 else
185 {
186 std::vector<uint8_t> pdr(respCount, 0);
187 rc = decode_get_pdr_resp(
188 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr),
189 &completionCode, &nextRecordHandle, &nextDataTransferHandle,
190 &transferFlag, &respCount, pdr.data(), respCount, &transferCRC);
191 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
192 {
193 std::cerr << "Failed to decode_get_pdr_resp: "
194 << "rc=" << rc
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500195 << ", cc=" << static_cast<unsigned>(completionCode)
196 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500197 }
198 else
199 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500200 // Process the PDR host firmware sent us. The most common action
201 // is to add the PDR to the the BMC's PDR repo.
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500202 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
203 if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
204 {
205 mergeEntityAssociations(pdr);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500206 merged = true;
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500207 }
208 else
209 {
Sampa Misra868c8792020-05-26 03:12:13 -0500210 if (pdrHdr->type == PLDM_TERMINUS_LOCATOR_PDR)
Tom Josephb4268602020-04-17 17:20:45 +0530211 {
Sampa Misra868c8792020-05-26 03:12:13 -0500212 auto tlpdr =
213 reinterpret_cast<const pldm_terminus_locator_pdr*>(
214 pdr.data());
215 tlpdrInfo.emplace(
216 static_cast<pdr::TerminusHandle>(
217 tlpdr->terminus_handle),
218 static_cast<pdr::TerminusID>(tlpdr->tid));
219 }
220 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR)
221 {
222 stateSensorPDRs.emplace_back(pdr);
Tom Josephb4268602020-04-17 17:20:45 +0530223 }
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500224 pldm_pdr_add(repo, pdr.data(), respCount, 0, true);
225 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500226 }
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -0500227
228 recordHandle = nextRecordHandle;
229 if (!pdrRecordHandles.empty())
230 {
231 recordHandle = pdrRecordHandles.front();
232 pdrRecordHandles.pop_front();
233 }
234 else if (isFormatRecHandles)
235 {
236 break;
237 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500238 }
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -0500239 } while (recordHandle);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500240
Sampa Misra868c8792020-05-26 03:12:13 -0500241 parseStateSensorPDRs(stateSensorPDRs, tlpdrInfo);
242
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500243 if (merged)
244 {
245 // We have merged host's entity association PDRs with our own. Send an
246 // event to the host firmware to indicate the same.
247 sendPDRRepositoryChgEvent(
248 std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)),
249 FORMAT_IS_PDR_HANDLES);
250 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500251}
252
Pavithra Barithaya3aec9972020-12-14 01:55:44 -0600253int HostPDRHandler::handleStateSensorEvent(const StateSensorEntry& entry,
254 pdr::EventState state)
255{
256 auto rc = stateSensorHandler.eventAction(entry, state);
257 if (rc != PLDM_SUCCESS)
258 {
259 std::cerr << "Failed to fetch and update D-bus property, rc = " << rc
260 << std::endl;
261 return rc;
262 }
263 return PLDM_SUCCESS;
264}
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500265bool HostPDRHandler::getParent(EntityType type, pldm_entity& parent)
266{
267 auto found = parents.find(type);
268 if (found != parents.end())
269 {
270 parent.entity_type = found->second.entity_type;
271 parent.entity_instance_num = found->second.entity_instance_num;
272 return true;
273 }
274
275 return false;
276}
277
278void HostPDRHandler::mergeEntityAssociations(const std::vector<uint8_t>& pdr)
279{
280 size_t numEntities{};
281 pldm_entity* entities = nullptr;
282 bool merged = false;
283 auto entityPdr = reinterpret_cast<pldm_pdr_entity_association*>(
284 const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr));
285
286 pldm_entity_association_pdr_extract(pdr.data(), pdr.size(), &numEntities,
287 &entities);
288 for (size_t i = 0; i < numEntities; ++i)
289 {
290 pldm_entity parent{};
291 if (getParent(entities[i].entity_type, parent))
292 {
293 auto node = pldm_entity_association_tree_find(entityTree, &parent);
294 if (node)
295 {
296 pldm_entity_association_tree_add(entityTree, &entities[i], node,
297 entityPdr->association_type);
298 merged = true;
299 }
300 }
301 }
302 free(entities);
303
304 if (merged)
305 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500306 // Update our PDR repo with the merged entity association PDRs
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500307 pldm_entity_association_pdr_add(entityTree, repo, true);
308 }
309}
310
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500311void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes,
312 uint8_t eventDataFormat)
313{
314 assert(eventDataFormat == FORMAT_IS_PDR_HANDLES);
315
316 // Extract from the PDR repo record handles of PDRs we want the host
317 // to pull up.
318 std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED};
319 std::vector<uint8_t> numsOfChangeEntries(1);
320 std::vector<std::vector<ChangeEntry>> changeEntries(
321 numsOfChangeEntries.size());
322 for (auto pdrType : pdrTypes)
323 {
324 const pldm_pdr_record* record{};
325 do
326 {
327 record = pldm_pdr_find_record_by_type(repo, pdrType, record,
328 nullptr, nullptr);
329 if (record && pldm_pdr_record_is_remote(record))
330 {
331 changeEntries[0].push_back(
332 pldm_pdr_get_record_handle(repo, record));
333 }
334 } while (record);
335 }
336 if (changeEntries.empty())
337 {
338 return;
339 }
340 numsOfChangeEntries[0] = changeEntries[0].size();
341
342 // Encode PLDM platform event msg to indicate a PDR repo change.
343 size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH +
344 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH +
345 changeEntries[0].size() * sizeof(uint32_t);
346 std::vector<uint8_t> eventDataVec{};
347 eventDataVec.resize(maxSize);
348 auto eventData =
349 reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>(
350 eventDataVec.data());
351 size_t actualSize{};
352 auto firstEntry = changeEntries[0].data();
353 auto rc = encode_pldm_pdr_repository_chg_event_data(
354 eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(),
355 &firstEntry, eventData, &actualSize, maxSize);
356 if (rc != PLDM_SUCCESS)
357 {
358 std::cerr
359 << "Failed to encode_pldm_pdr_repository_chg_event_data, rc = "
360 << rc << std::endl;
361 return;
362 }
363 auto instanceId = requester.getInstanceId(mctp_eid);
364 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
365 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
366 actualSize);
367 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
368 rc = encode_platform_event_message_req(
369 instanceId, 1, 0, PLDM_PDR_REPOSITORY_CHG_EVENT, eventDataVec.data(),
Christian Geddes3bdb3c22020-05-01 14:55:39 -0500370 actualSize, request,
371 actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500372 if (rc != PLDM_SUCCESS)
373 {
374 requester.markFree(mctp_eid, instanceId);
375 std::cerr << "Failed to encode_platform_event_message_req, rc = " << rc
376 << std::endl;
377 return;
378 }
379
380 // Send up the event to host.
381 uint8_t* responseMsg = nullptr;
382 size_t responseMsgSize{};
383 auto requesterRc =
384 pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(),
385 &responseMsg, &responseMsgSize);
386 requester.markFree(mctp_eid, instanceId);
387 if (requesterRc != PLDM_REQUESTER_SUCCESS)
388 {
389 std::cerr << "Failed to send msg to report pdrs, rc = " << requesterRc
390 << std::endl;
391 return;
392 }
393 uint8_t completionCode{};
394 uint8_t status{};
395 auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
396 rc = decode_platform_event_message_resp(
397 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr), &completionCode,
398 &status);
399 free(responseMsg);
400 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
401 {
402 std::cerr << "Failed to decode_platform_event_message_resp: "
403 << "rc=" << rc
404 << ", cc=" << static_cast<unsigned>(completionCode)
405 << std::endl;
406 }
407}
408
Sampa Misra868c8792020-05-26 03:12:13 -0500409void HostPDRHandler::parseStateSensorPDRs(const PDRList& stateSensorPDRs,
410 const TLPDRMap& tlpdrInfo)
411{
412 for (const auto& pdr : stateSensorPDRs)
413 {
414 SensorEntry sensorEntry{};
415 const auto& [terminusHandle, sensorID, sensorInfo] =
416 responder::pdr_utils::parseStateSensorPDR(pdr);
417 sensorEntry.sensorID = sensorID;
418 try
419 {
420 sensorEntry.terminusID = tlpdrInfo.at(terminusHandle);
421 }
422 // If there is no mapping for terminusHandle assign the reserved TID
423 // value of 0xFF to indicate that.
424 catch (const std::out_of_range& e)
425 {
426 sensorEntry.terminusID = PLDM_TID_RESERVED;
427 }
428 sensorMap.emplace(sensorEntry, std::move(sensorInfo));
429 }
430}
431
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500432} // namespace pldm