blob: db845fc270e94f465a3812ff7915237f5883dfdc [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
Pavithra Barithayae8beb892020-04-14 23:24:25 -05005#include <assert.h>
6
Deepak Kodihalli87514cc2020-04-16 09:08:38 -05007#include <fstream>
8#include <nlohmann/json.hpp>
9
Pavithra Barithaya51efaf82020-04-02 02:42:27 -050010#include "libpldm/requester/pldm.h"
11
12namespace pldm
13{
14
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050015using namespace pldm::utils;
16using namespace sdbusplus::bus::match::rules;
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050017using Json = nlohmann::json;
18namespace fs = std::filesystem;
19constexpr auto fruJson = "host_frus.json";
20const Json emptyJson{};
21const std::vector<Json> emptyJsonList{};
22
23HostPDRHandler::HostPDRHandler(int mctp_fd, uint8_t mctp_eid,
24 sdeventplus::Event& event, pldm_pdr* repo,
25 pldm_entity_association_tree* entityTree,
26 Requester& requester) :
27 mctp_fd(mctp_fd),
28 mctp_eid(mctp_eid), event(event), repo(repo), entityTree(entityTree),
29 requester(requester)
30{
31 fs::path hostFruJson(fs::path(HOST_JSONS_DIR) / fruJson);
32 if (fs::exists(hostFruJson))
33 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -050034 // Note parent entities for entities sent down by the host firmware.
35 // This will enable a merge of entity associations.
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050036 try
37 {
38 std::ifstream jsonFile(hostFruJson);
39 auto data = Json::parse(jsonFile, nullptr, false);
40 if (data.is_discarded())
41 {
42 std::cerr << "Parsing Host FRU json file failed" << std::endl;
43 }
44 else
45 {
46 auto entities = data.value("entities", emptyJsonList);
47 for (auto& entity : entities)
48 {
49 EntityType entityType = entity.value("entity_type", 0);
50 auto parent = entity.value("parent", emptyJson);
51 pldm_entity p{};
52 p.entity_type = parent.value("entity_type", 0);
53 p.entity_instance_num = parent.value("entity_instance", 0);
54 parents.emplace(entityType, std::move(p));
55 }
56 }
57 }
58 catch (const std::exception& e)
59 {
60 std::cerr << "Parsing Host FRU json file failed, exception = "
61 << e.what() << std::endl;
62 }
63 }
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050064
65 hostOffMatch = std::make_unique<sdbusplus::bus::match::match>(
66 pldm::utils::DBusHandler::getBus(),
67 propertiesChanged("/xyz/openbmc_project/state/host0",
68 "xyz.openbmc_project.State.Host"),
Tom Josephb4268602020-04-17 17:20:45 +053069 [this, repo](sdbusplus::message::message& msg) {
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050070 DbusChangedProps props{};
71 std::string intf;
72 msg.read(intf, props);
73 const auto itr = props.find("CurrentHostState");
74 if (itr != props.end())
75 {
76 PropertyValue value = itr->second;
77 auto propVal = std::get<std::string>(value);
78 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
79 {
80 pldm_pdr_remove_remote_pdrs(repo);
Tom Josephb4268602020-04-17 17:20:45 +053081 this->sensorMap.clear();
Deepak Kodihalli6b1d1ca2020-04-27 07:24:51 -050082 }
83 }
84 });
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050085}
86
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -050087void HostPDRHandler::fetchPDR(std::vector<uint32_t>&& recordHandles)
Pavithra Barithaya51efaf82020-04-02 02:42:27 -050088{
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -050089 pdrRecordHandles.clear();
90 pdrRecordHandles = std::move(recordHandles);
91
92 // Defer the actual fetch of PDRs from the host (by queuing the call on the
93 // main event loop). That way, we can respond to the platform event msg from
94 // the host firmware.
95 pdrFetchEvent = std::make_unique<sdeventplus::source::Defer>(
96 event, std::bind(std::mem_fn(&HostPDRHandler::_fetchPDR), this,
97 std::placeholders::_1));
98}
99
100void HostPDRHandler::_fetchPDR(sdeventplus::source::EventBase& /*source*/)
101{
102 pdrFetchEvent.reset();
103
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500104 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
105 PLDM_GET_PDR_REQ_BYTES);
106 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500107 bool merged = false;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500108
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500109 for (auto recordHandle : pdrRecordHandles)
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500110 {
111 auto instanceId = requester.getInstanceId(mctp_eid);
112
113 auto rc =
114 encode_get_pdr_req(instanceId, recordHandle, 0, PLDM_GET_FIRSTPART,
115 UINT16_MAX, 0, request, PLDM_GET_PDR_REQ_BYTES);
116 if (rc != PLDM_SUCCESS)
117 {
118 requester.markFree(mctp_eid, instanceId);
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500119 std::cerr << "Failed to encode_get_pdr_req, rc = " << rc
120 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500121 return;
122 }
123
124 uint8_t* responseMsg = nullptr;
125 size_t responseMsgSize{};
126 auto requesterRc =
127 pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(),
128 requestMsg.size(), &responseMsg, &responseMsgSize);
129 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{
130 responseMsg, std::free};
131 requester.markFree(mctp_eid, instanceId);
132 if (requesterRc != PLDM_REQUESTER_SUCCESS)
133 {
134 std::cerr << "Failed to send msg to fetch pdrs, rc = "
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500135 << requesterRc << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500136 return;
137 }
138
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500139 uint8_t completionCode{};
140 uint32_t nextRecordHandle{};
141 uint32_t nextDataTransferHandle{};
142 uint8_t transferFlag{};
143 uint16_t respCount{};
144 uint8_t transferCRC{};
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500145 auto responsePtr =
146 reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500147 rc = decode_get_pdr_resp(
148 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr),
149 &completionCode, &nextRecordHandle, &nextDataTransferHandle,
150 &transferFlag, &respCount, nullptr, 0, &transferCRC);
151 if (rc != PLDM_SUCCESS)
152 {
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500153 std::cerr << "Failed to decode_get_pdr_resp, rc = " << rc
154 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500155 }
156 else
157 {
158 std::vector<uint8_t> pdr(respCount, 0);
159 rc = decode_get_pdr_resp(
160 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr),
161 &completionCode, &nextRecordHandle, &nextDataTransferHandle,
162 &transferFlag, &respCount, pdr.data(), respCount, &transferCRC);
163 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
164 {
165 std::cerr << "Failed to decode_get_pdr_resp: "
166 << "rc=" << rc
Deepak Kodihalli8cb6f662020-04-10 02:55:43 -0500167 << ", cc=" << static_cast<unsigned>(completionCode)
168 << std::endl;
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500169 }
170 else
171 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500172 // Process the PDR host firmware sent us. The most common action
173 // is to add the PDR to the the BMC's PDR repo.
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500174 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
175 if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
176 {
177 mergeEntityAssociations(pdr);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500178 merged = true;
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500179 }
180 else
181 {
Tom Josephb4268602020-04-17 17:20:45 +0530182 if (pdrHdr->type == PLDM_STATE_SENSOR_PDR)
183 {
184 const auto& [terminusHandle, sensorID, sensorInfo] =
185 responder::pdr_utils::parseStateSensorPDR(pdr);
186 SensorEntry sensorEntry{};
187 // TODO: Lookup Terminus ID from the Terminus Locator
188 // PDR with terminusHandle
189 sensorEntry.terminusID = 0;
190 sensorEntry.sensorID = sensorID;
191 sensorMap.emplace(sensorEntry, std::move(sensorInfo));
192 }
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500193 pldm_pdr_add(repo, pdr.data(), respCount, 0, true);
194 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500195 }
196 }
197 }
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500198
199 if (merged)
200 {
201 // We have merged host's entity association PDRs with our own. Send an
202 // event to the host firmware to indicate the same.
203 sendPDRRepositoryChgEvent(
204 std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)),
205 FORMAT_IS_PDR_HANDLES);
206 }
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500207}
208
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500209bool HostPDRHandler::getParent(EntityType type, pldm_entity& parent)
210{
211 auto found = parents.find(type);
212 if (found != parents.end())
213 {
214 parent.entity_type = found->second.entity_type;
215 parent.entity_instance_num = found->second.entity_instance_num;
216 return true;
217 }
218
219 return false;
220}
221
222void HostPDRHandler::mergeEntityAssociations(const std::vector<uint8_t>& pdr)
223{
224 size_t numEntities{};
225 pldm_entity* entities = nullptr;
226 bool merged = false;
227 auto entityPdr = reinterpret_cast<pldm_pdr_entity_association*>(
228 const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr));
229
230 pldm_entity_association_pdr_extract(pdr.data(), pdr.size(), &numEntities,
231 &entities);
232 for (size_t i = 0; i < numEntities; ++i)
233 {
234 pldm_entity parent{};
235 if (getParent(entities[i].entity_type, parent))
236 {
237 auto node = pldm_entity_association_tree_find(entityTree, &parent);
238 if (node)
239 {
240 pldm_entity_association_tree_add(entityTree, &entities[i], node,
241 entityPdr->association_type);
242 merged = true;
243 }
244 }
245 }
246 free(entities);
247
248 if (merged)
249 {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500250 // Update our PDR repo with the merged entity association PDRs
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500251 pldm_entity_association_pdr_add(entityTree, repo, true);
252 }
253}
254
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500255void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes,
256 uint8_t eventDataFormat)
257{
258 assert(eventDataFormat == FORMAT_IS_PDR_HANDLES);
259
260 // Extract from the PDR repo record handles of PDRs we want the host
261 // to pull up.
262 std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED};
263 std::vector<uint8_t> numsOfChangeEntries(1);
264 std::vector<std::vector<ChangeEntry>> changeEntries(
265 numsOfChangeEntries.size());
266 for (auto pdrType : pdrTypes)
267 {
268 const pldm_pdr_record* record{};
269 do
270 {
271 record = pldm_pdr_find_record_by_type(repo, pdrType, record,
272 nullptr, nullptr);
273 if (record && pldm_pdr_record_is_remote(record))
274 {
275 changeEntries[0].push_back(
276 pldm_pdr_get_record_handle(repo, record));
277 }
278 } while (record);
279 }
280 if (changeEntries.empty())
281 {
282 return;
283 }
284 numsOfChangeEntries[0] = changeEntries[0].size();
285
286 // Encode PLDM platform event msg to indicate a PDR repo change.
287 size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH +
288 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH +
289 changeEntries[0].size() * sizeof(uint32_t);
290 std::vector<uint8_t> eventDataVec{};
291 eventDataVec.resize(maxSize);
292 auto eventData =
293 reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>(
294 eventDataVec.data());
295 size_t actualSize{};
296 auto firstEntry = changeEntries[0].data();
297 auto rc = encode_pldm_pdr_repository_chg_event_data(
298 eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(),
299 &firstEntry, eventData, &actualSize, maxSize);
300 if (rc != PLDM_SUCCESS)
301 {
302 std::cerr
303 << "Failed to encode_pldm_pdr_repository_chg_event_data, rc = "
304 << rc << std::endl;
305 return;
306 }
307 auto instanceId = requester.getInstanceId(mctp_eid);
308 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
309 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
310 actualSize);
311 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
312 rc = encode_platform_event_message_req(
313 instanceId, 1, 0, PLDM_PDR_REPOSITORY_CHG_EVENT, eventDataVec.data(),
Christian Geddes3bdb3c22020-05-01 14:55:39 -0500314 actualSize, request,
315 actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500316 if (rc != PLDM_SUCCESS)
317 {
318 requester.markFree(mctp_eid, instanceId);
319 std::cerr << "Failed to encode_platform_event_message_req, rc = " << rc
320 << std::endl;
321 return;
322 }
323
324 // Send up the event to host.
325 uint8_t* responseMsg = nullptr;
326 size_t responseMsgSize{};
327 auto requesterRc =
328 pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(),
329 &responseMsg, &responseMsgSize);
330 requester.markFree(mctp_eid, instanceId);
331 if (requesterRc != PLDM_REQUESTER_SUCCESS)
332 {
333 std::cerr << "Failed to send msg to report pdrs, rc = " << requesterRc
334 << std::endl;
335 return;
336 }
337 uint8_t completionCode{};
338 uint8_t status{};
339 auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
340 rc = decode_platform_event_message_resp(
341 responsePtr, responseMsgSize - sizeof(pldm_msg_hdr), &completionCode,
342 &status);
343 free(responseMsg);
344 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
345 {
346 std::cerr << "Failed to decode_platform_event_message_resp: "
347 << "rc=" << rc
348 << ", cc=" << static_cast<unsigned>(completionCode)
349 << std::endl;
350 }
351}
352
Pavithra Barithaya51efaf82020-04-02 02:42:27 -0500353} // namespace pldm