blob: 31065a41b10aac6f98042e00f2ea708cd3ee2397 [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,
26 pldm_entity_association_tree* entityTree,
27 Requester& requester) :
28 mctp_fd(mctp_fd),
29 mctp_eid(mctp_eid), event(event), repo(repo), entityTree(entityTree),
30 requester(requester)
31{
32 fs::path hostFruJson(fs::path(HOST_JSONS_DIR) / fruJson);
33 if (fs::exists(hostFruJson))
34 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -050035 // Note parent entities for entities sent down by the host firmware.
36 // This will enable a merge of entity associations.
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050037 try
38 {
39 std::ifstream jsonFile(hostFruJson);
40 auto data = Json::parse(jsonFile, nullptr, false);
41 if (data.is_discarded())
42 {
43 std::cerr << "Parsing Host FRU json file failed" << std::endl;
44 }
45 else
46 {
47 auto entities = data.value("entities", emptyJsonList);
48 for (auto& entity : entities)
49 {
50 EntityType entityType = entity.value("entity_type", 0);
51 auto parent = entity.value("parent", emptyJson);
52 pldm_entity p{};
53 p.entity_type = parent.value("entity_type", 0);
54 p.entity_instance_num = parent.value("entity_instance", 0);
55 parents.emplace(entityType, std::move(p));
56 }
57 }
58 }
59 catch (const std::exception& e)
60 {
61 std::cerr << "Parsing Host FRU json file failed, exception = "
62 << e.what() << std::endl;
63 }
64 }
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050065
66 hostOffMatch = std::make_unique<sdbusplus::bus::match::match>(
67 pldm::utils::DBusHandler::getBus(),
68 propertiesChanged("/xyz/openbmc_project/state/host0",
69 "xyz.openbmc_project.State.Host"),
Tom Josephb4268602020-04-17 17:20:45 +053070 [this, repo](sdbusplus::message::message& msg) {
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050071 DbusChangedProps props{};
72 std::string intf;
73 msg.read(intf, props);
74 const auto itr = props.find("CurrentHostState");
75 if (itr != props.end())
76 {
77 PropertyValue value = itr->second;
78 auto propVal = std::get<std::string>(value);
79 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
80 {
81 pldm_pdr_remove_remote_pdrs(repo);
Tom Josephb4268602020-04-17 17:20:45 +053082 this->sensorMap.clear();
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050083 }
84 }
85 });
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050086}
87
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -050088void HostPDRHandler::fetchPDR(PDRRecordHandles&& recordHandles)
Pavithra Barithaya51efaf82020-04-02 02:42:27 -050089{
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -050090 pdrRecordHandles.clear();
91 pdrRecordHandles = std::move(recordHandles);
92
93 // Defer the actual fetch of PDRs from the host (by queuing the call on the
94 // main event loop). That way, we can respond to the platform event msg from
95 // the host firmware.
96 pdrFetchEvent = std::make_unique<sdeventplus::source::Defer>(
97 event, std::bind(std::mem_fn(&HostPDRHandler::_fetchPDR), this,
98 std::placeholders::_1));
99}
100
101void HostPDRHandler::_fetchPDR(sdeventplus::source::EventBase& /*source*/)
102{
103 pdrFetchEvent.reset();
104
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500105 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
106 PLDM_GET_PDR_REQ_BYTES);
107 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500108 bool merged = false;
Sampa Misra868c8792020-05-26 03:12:13 -0500109 PDRList stateSensorPDRs{};
110 TLPDRMap tlpdrInfo{};
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500111
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -0500112 uint32_t nextRecordHandle{};
113 uint32_t recordHandle{};
114 bool isFormatRecHandles = false;
115 if (!pdrRecordHandles.empty())
116 {
117 recordHandle = pdrRecordHandles.front();
118 pdrRecordHandles.pop_front();
119 isFormatRecHandles = true;
120 }
121
122 do
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500123 {
124 auto instanceId = requester.getInstanceId(mctp_eid);
125
126 auto rc =
127 encode_get_pdr_req(instanceId, recordHandle, 0, PLDM_GET_FIRSTPART,
128 UINT16_MAX, 0, request, PLDM_GET_PDR_REQ_BYTES);
129 if (rc != PLDM_SUCCESS)
130 {
131 requester.markFree(mctp_eid, instanceId);
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500132 std::cerr << "Failed to encode_get_pdr_req, rc = " << rc
133 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500134 return;
135 }
136
137 uint8_t* responseMsg = nullptr;
138 size_t responseMsgSize{};
139 auto requesterRc =
140 pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(),
141 requestMsg.size(), &responseMsg, &responseMsgSize);
142 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{
143 responseMsg, std::free};
144 requester.markFree(mctp_eid, instanceId);
145 if (requesterRc != PLDM_REQUESTER_SUCCESS)
146 {
147 std::cerr << "Failed to send msg to fetch pdrs, rc = "
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500148 << requesterRc << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500149 return;
150 }
151
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500152 uint8_t completionCode{};
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500153 uint32_t nextDataTransferHandle{};
154 uint8_t transferFlag{};
155 uint16_t respCount{};
156 uint8_t transferCRC{};
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500157 auto responsePtr =
158 reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500159 rc = decode_get_pdr_resp(
160 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr),
161 &completionCode, &nextRecordHandle, &nextDataTransferHandle,
162 &transferFlag, &respCount, nullptr, 0, &transferCRC);
163 if (rc != PLDM_SUCCESS)
164 {
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500165 std::cerr << "Failed to decode_get_pdr_resp, rc = " << rc
166 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500167 }
168 else
169 {
170 std::vector<uint8_t> pdr(respCount, 0);
171 rc = decode_get_pdr_resp(
172 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr),
173 &completionCode, &nextRecordHandle, &nextDataTransferHandle,
174 &transferFlag, &respCount, pdr.data(), respCount, &transferCRC);
175 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
176 {
177 std::cerr << "Failed to decode_get_pdr_resp: "
178 << "rc=" << rc
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500179 << ", cc=" << static_cast<unsigned>(completionCode)
180 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500181 }
182 else
183 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500184 // Process the PDR host firmware sent us. The most common action
185 // is to add the PDR to the the BMC's PDR repo.
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500186 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
187 if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
188 {
189 mergeEntityAssociations(pdr);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500190 merged = true;
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500191 }
192 else
193 {
Sampa Misra868c8792020-05-26 03:12:13 -0500194 if (pdrHdr->type == PLDM_TERMINUS_LOCATOR_PDR)
Tom Josephb4268602020-04-17 17:20:45 +0530195 {
Sampa Misra868c8792020-05-26 03:12:13 -0500196 auto tlpdr =
197 reinterpret_cast<const pldm_terminus_locator_pdr*>(
198 pdr.data());
199 tlpdrInfo.emplace(
200 static_cast<pdr::TerminusHandle>(
201 tlpdr->terminus_handle),
202 static_cast<pdr::TerminusID>(tlpdr->tid));
203 }
204 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR)
205 {
206 stateSensorPDRs.emplace_back(pdr);
Tom Josephb4268602020-04-17 17:20:45 +0530207 }
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500208 pldm_pdr_add(repo, pdr.data(), respCount, 0, true);
209 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500210 }
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -0500211
212 recordHandle = nextRecordHandle;
213 if (!pdrRecordHandles.empty())
214 {
215 recordHandle = pdrRecordHandles.front();
216 pdrRecordHandles.pop_front();
217 }
218 else if (isFormatRecHandles)
219 {
220 break;
221 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500222 }
Deepak Kodihalli7246e0c2020-07-08 06:40:18 -0500223 } while (recordHandle);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500224
Sampa Misra868c8792020-05-26 03:12:13 -0500225 parseStateSensorPDRs(stateSensorPDRs, tlpdrInfo);
226
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500227 if (merged)
228 {
229 // We have merged host's entity association PDRs with our own. Send an
230 // event to the host firmware to indicate the same.
231 sendPDRRepositoryChgEvent(
232 std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)),
233 FORMAT_IS_PDR_HANDLES);
234 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500235}
236
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500237bool HostPDRHandler::getParent(EntityType type, pldm_entity& parent)
238{
239 auto found = parents.find(type);
240 if (found != parents.end())
241 {
242 parent.entity_type = found->second.entity_type;
243 parent.entity_instance_num = found->second.entity_instance_num;
244 return true;
245 }
246
247 return false;
248}
249
250void HostPDRHandler::mergeEntityAssociations(const std::vector<uint8_t>& pdr)
251{
252 size_t numEntities{};
253 pldm_entity* entities = nullptr;
254 bool merged = false;
255 auto entityPdr = reinterpret_cast<pldm_pdr_entity_association*>(
256 const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr));
257
258 pldm_entity_association_pdr_extract(pdr.data(), pdr.size(), &numEntities,
259 &entities);
260 for (size_t i = 0; i < numEntities; ++i)
261 {
262 pldm_entity parent{};
263 if (getParent(entities[i].entity_type, parent))
264 {
265 auto node = pldm_entity_association_tree_find(entityTree, &parent);
266 if (node)
267 {
268 pldm_entity_association_tree_add(entityTree, &entities[i], node,
269 entityPdr->association_type);
270 merged = true;
271 }
272 }
273 }
274 free(entities);
275
276 if (merged)
277 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500278 // Update our PDR repo with the merged entity association PDRs
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500279 pldm_entity_association_pdr_add(entityTree, repo, true);
280 }
281}
282
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500283void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes,
284 uint8_t eventDataFormat)
285{
286 assert(eventDataFormat == FORMAT_IS_PDR_HANDLES);
287
288 // Extract from the PDR repo record handles of PDRs we want the host
289 // to pull up.
290 std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED};
291 std::vector<uint8_t> numsOfChangeEntries(1);
292 std::vector<std::vector<ChangeEntry>> changeEntries(
293 numsOfChangeEntries.size());
294 for (auto pdrType : pdrTypes)
295 {
296 const pldm_pdr_record* record{};
297 do
298 {
299 record = pldm_pdr_find_record_by_type(repo, pdrType, record,
300 nullptr, nullptr);
301 if (record && pldm_pdr_record_is_remote(record))
302 {
303 changeEntries[0].push_back(
304 pldm_pdr_get_record_handle(repo, record));
305 }
306 } while (record);
307 }
308 if (changeEntries.empty())
309 {
310 return;
311 }
312 numsOfChangeEntries[0] = changeEntries[0].size();
313
314 // Encode PLDM platform event msg to indicate a PDR repo change.
315 size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH +
316 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH +
317 changeEntries[0].size() * sizeof(uint32_t);
318 std::vector<uint8_t> eventDataVec{};
319 eventDataVec.resize(maxSize);
320 auto eventData =
321 reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>(
322 eventDataVec.data());
323 size_t actualSize{};
324 auto firstEntry = changeEntries[0].data();
325 auto rc = encode_pldm_pdr_repository_chg_event_data(
326 eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(),
327 &firstEntry, eventData, &actualSize, maxSize);
328 if (rc != PLDM_SUCCESS)
329 {
330 std::cerr
331 << "Failed to encode_pldm_pdr_repository_chg_event_data, rc = "
332 << rc << std::endl;
333 return;
334 }
335 auto instanceId = requester.getInstanceId(mctp_eid);
336 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
337 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
338 actualSize);
339 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
340 rc = encode_platform_event_message_req(
341 instanceId, 1, 0, PLDM_PDR_REPOSITORY_CHG_EVENT, eventDataVec.data(),
Christian Geddes3bdb3c22020-05-01 14:55:39 -0500342 actualSize, request,
343 actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500344 if (rc != PLDM_SUCCESS)
345 {
346 requester.markFree(mctp_eid, instanceId);
347 std::cerr << "Failed to encode_platform_event_message_req, rc = " << rc
348 << std::endl;
349 return;
350 }
351
352 // Send up the event to host.
353 uint8_t* responseMsg = nullptr;
354 size_t responseMsgSize{};
355 auto requesterRc =
356 pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(),
357 &responseMsg, &responseMsgSize);
358 requester.markFree(mctp_eid, instanceId);
359 if (requesterRc != PLDM_REQUESTER_SUCCESS)
360 {
361 std::cerr << "Failed to send msg to report pdrs, rc = " << requesterRc
362 << std::endl;
363 return;
364 }
365 uint8_t completionCode{};
366 uint8_t status{};
367 auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
368 rc = decode_platform_event_message_resp(
369 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr), &completionCode,
370 &status);
371 free(responseMsg);
372 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
373 {
374 std::cerr << "Failed to decode_platform_event_message_resp: "
375 << "rc=" << rc
376 << ", cc=" << static_cast<unsigned>(completionCode)
377 << std::endl;
378 }
379}
380
Sampa Misra868c8792020-05-26 03:12:13 -0500381void HostPDRHandler::parseStateSensorPDRs(const PDRList& stateSensorPDRs,
382 const TLPDRMap& tlpdrInfo)
383{
384 for (const auto& pdr : stateSensorPDRs)
385 {
386 SensorEntry sensorEntry{};
387 const auto& [terminusHandle, sensorID, sensorInfo] =
388 responder::pdr_utils::parseStateSensorPDR(pdr);
389 sensorEntry.sensorID = sensorID;
390 try
391 {
392 sensorEntry.terminusID = tlpdrInfo.at(terminusHandle);
393 }
394 // If there is no mapping for terminusHandle assign the reserved TID
395 // value of 0xFF to indicate that.
396 catch (const std::out_of_range& e)
397 {
398 sensorEntry.terminusID = PLDM_TID_RESERVED;
399 }
400 sensorMap.emplace(sensorEntry, std::move(sensorInfo));
401 }
402}
403
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500404} // namespace pldm