blob: 6c177fc7c9a65e131e37af05af935d741accaf1e [file] [log] [blame]
Patrick Williams05e95592021-09-02 09:28:14 -05001#include "pldm.hpp"
2
3#include "file.hpp"
4
5#include <fmt/core.h>
6#include <libpldm/entity.h>
7#include <libpldm/platform.h>
8#include <libpldm/state_set.h>
Eddie James36313c72021-11-18 08:27:03 -06009#include <libpldm/state_set_oem_ibm.h>
Patrick Williams05e95592021-09-02 09:28:14 -050010
11#include <phosphor-logging/log.hpp>
12
13namespace pldm
14{
15
Patrick Williams05e95592021-09-02 09:28:14 -050016using namespace phosphor::logging;
17
Eddie Jamescbad2192021-10-07 09:39:39 -050018void Interface::fetchSensorInfo(uint16_t stateSetId,
19 SensorToInstance& sensorInstanceMap,
20 SensorOffset& sensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -050021{
Eddie Jamescbad2192021-10-07 09:39:39 -050022 PdrList pdrs{};
23
24 auto& bus = open_power::occ::utils::getBus();
25 try
26 {
27 auto method = bus.new_method_call(
28 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
29 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
30 method.append(tid, (uint16_t)PLDM_ENTITY_PROC, stateSetId);
31
32 auto responseMsg = bus.call(method);
33 responseMsg.read(pdrs);
34 }
35 catch (const sdbusplus::exception::exception& e)
36 {
37 log<level::ERR>("pldm: Failed to fetch the state sensor PDRs",
38 entry("ERROR=%s", e.what()));
39 }
40
41 if (pdrs.empty())
42 {
43 log<level::ERR>("pldm: state sensor PDRs not present");
44 return;
45 }
46
Patrick Williams05e95592021-09-02 09:28:14 -050047 bool offsetFound = false;
48 auto pdr =
49 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
50 auto possibleStatesPtr = pdr->possible_states;
51 for (auto offset = 0; offset < pdr->composite_sensor_count; offset++)
52 {
53 auto possibleStates =
54 reinterpret_cast<const state_sensor_possible_states*>(
55 possibleStatesPtr);
56
Eddie Jamescbad2192021-10-07 09:39:39 -050057 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -050058 {
59 sensorOffset = offset;
60 offsetFound = true;
61 break;
62 }
63 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
64 sizeof(possibleStates->possible_states_size) +
65 possibleStates->possible_states_size;
66 }
67
68 if (!offsetFound)
69 {
Eddie Jamescbad2192021-10-07 09:39:39 -050070 log<level::ERR>("pldm: state sensor PDR not found");
Patrick Williams05e95592021-09-02 09:28:14 -050071 return;
72 }
73
74 // To order SensorID based on the EntityInstance.
75 // Note that when a proc is on a DCM, the PDRs for these sensors
76 // could have the same instance IDs but different container IDs.
77 std::map<uint32_t, SensorID> entityInstMap{};
78 for (auto& pdr : pdrs)
79 {
80 auto pdrPtr =
81 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
82 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
83 static_cast<uint32_t>(pdrPtr->entity_instance);
84 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->sensor_id));
85 }
86
87 open_power::occ::instanceID count = start;
88 for (auto const& pair : entityInstMap)
89 {
90 sensorInstanceMap.emplace(pair.second, count);
91 count++;
92 }
93}
94
95void Interface::sensorEvent(sdbusplus::message::message& msg)
96{
97 if (!isOCCSensorCacheValid())
98 {
Eddie Jamescbad2192021-10-07 09:39:39 -050099 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
100 sensorToOCCInstance, OCCSensorOffset);
101 }
Patrick Williams05e95592021-09-02 09:28:14 -0500102
Eddie Jamescbad2192021-10-07 09:39:39 -0500103 if (sensorToSBEInstance.empty())
104 {
105 fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSBEInstance,
106 SBESensorOffset);
Patrick Williams05e95592021-09-02 09:28:14 -0500107 }
108
109 TerminusID tid{};
110 SensorID sensorId{};
111 SensorOffset msgSensorOffset{};
112 EventState eventState{};
113 EventState previousEventState{};
114
115 msg.read(tid, sensorId, msgSensorOffset, eventState, previousEventState);
116
Eddie Jamescbad2192021-10-07 09:39:39 -0500117 if (msgSensorOffset == OCCSensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -0500118 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500119 auto sensorEntry = sensorToOCCInstance.find(sensorId);
Patrick Williams05e95592021-09-02 09:28:14 -0500120
Eddie James432dc482021-11-19 15:29:31 -0600121 if (sensorEntry != sensorToOCCInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500122 {
Eddie James432dc482021-11-19 15:29:31 -0600123 if (eventState ==
124 static_cast<EventState>(
125 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
126 {
127 log<level::INFO>(
128 fmt::format("PLDM: OCC{} is RUNNING", sensorEntry->second)
129 .c_str());
130 callBack(sensorEntry->second, true);
131 }
132 else if (eventState ==
133 static_cast<EventState>(
134 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
135 {
136 log<level::INFO>(fmt::format("PLDM: OCC{} has now STOPPED",
137 sensorEntry->second)
138 .c_str());
139 callBack(sensorEntry->second, false);
140 }
141
Eddie Jamescbad2192021-10-07 09:39:39 -0500142 return;
143 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500144 }
Eddie James432dc482021-11-19 15:29:31 -0600145
146 if (msgSensorOffset == SBESensorOffset)
Eddie Jamescbad2192021-10-07 09:39:39 -0500147 {
148 auto sensorEntry = sensorToSBEInstance.find(sensorId);
149
Eddie James432dc482021-11-19 15:29:31 -0600150 if (sensorEntry != sensorToSBEInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500151 {
Eddie James432dc482021-11-19 15:29:31 -0600152 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
153 {
154 log<level::INFO>("pldm: HRESET is NOT READY",
155 entry("SBE=%d", sensorEntry->second));
156 }
157 else if (eventState == static_cast<EventState>(SBE_HRESET_READY))
158 {
159 sbeCallBack(sensorEntry->second, true);
160 }
161 else if (eventState == static_cast<EventState>(SBE_HRESET_FAILED))
162 {
163 sbeCallBack(sensorEntry->second, false);
164 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500165 }
166 }
Patrick Williams05e95592021-09-02 09:28:14 -0500167}
168
169void Interface::hostStateEvent(sdbusplus::message::message& msg)
170{
171 std::map<std::string, std::variant<std::string>> properties{};
172 std::string interface;
173 msg.read(interface, properties);
174 const auto stateEntry = properties.find("CurrentHostState");
175 if (stateEntry != properties.end())
176 {
177 auto stateEntryValue = stateEntry->second;
178 auto propVal = std::get<std::string>(stateEntryValue);
179 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
180 {
181 sensorToOCCInstance.clear();
182 occInstanceToEffecter.clear();
Eddie Jamescbad2192021-10-07 09:39:39 -0500183
184 sensorToSBEInstance.clear();
185 sbeInstanceToEffecter.clear();
Patrick Williams05e95592021-09-02 09:28:14 -0500186 }
187 }
188}
189
Eddie James432dc482021-11-19 15:29:31 -0600190void Interface::fetchEffecterInfo(uint16_t stateSetId,
Eddie Jamescbad2192021-10-07 09:39:39 -0500191 InstanceToEffecter& instanceToEffecterMap,
192 CompositeEffecterCount& effecterCount,
193 uint8_t& stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500194{
Eddie Jamescbad2192021-10-07 09:39:39 -0500195 PdrList pdrs{};
196
197 auto& bus = open_power::occ::utils::getBus();
198 try
199 {
200 auto method = bus.new_method_call(
201 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
202 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Eddie James432dc482021-11-19 15:29:31 -0600203 method.append(tid, (uint16_t)PLDM_ENTITY_PROC, stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -0500204
205 auto responseMsg = bus.call(method);
206 responseMsg.read(pdrs);
207 }
208 catch (const sdbusplus::exception::exception& e)
209 {
210 log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
211 entry("ERROR=%s", e.what()));
212 }
213
214 if (!pdrs.size())
215 {
216 log<level::ERR>("pldm: state effecter PDRs not present");
217 return;
218 }
219
Patrick Williams05e95592021-09-02 09:28:14 -0500220 bool offsetFound = false;
221 auto pdr =
222 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
223 auto possibleStatesPtr = pdr->possible_states;
224 for (auto offset = 0; offset < pdr->composite_effecter_count; offset++)
225 {
226 auto possibleStates =
227 reinterpret_cast<const state_effecter_possible_states*>(
228 possibleStatesPtr);
229
Eddie Jamescbad2192021-10-07 09:39:39 -0500230 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500231 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500232 stateIdPos = offset;
Patrick Williams05e95592021-09-02 09:28:14 -0500233 effecterCount = pdr->composite_effecter_count;
234 offsetFound = true;
235 break;
236 }
237 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
238 sizeof(possibleStates->possible_states_size) +
239 possibleStates->possible_states_size;
240 }
241
242 if (!offsetFound)
243 {
244 return;
245 }
246
247 std::map<EntityInstance, EffecterID> entityInstMap{};
248 for (auto& pdr : pdrs)
249 {
250 auto pdrPtr =
251 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
252 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
253 static_cast<uint32_t>(pdrPtr->entity_instance);
254 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
255 }
256
257 open_power::occ::instanceID position = start;
258 for (auto const& pair : entityInstMap)
259 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500260 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500261 position++;
262 }
263}
264
265std::vector<uint8_t>
266 Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId,
267 CompositeEffecterCount effecterCount,
Eddie Jamescbad2192021-10-07 09:39:39 -0500268 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500269{
270 std::vector<uint8_t> request(
271 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
272 (effecterCount * sizeof(set_effecter_state_field)));
273 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
274 std::vector<set_effecter_state_field> stateField;
275
276 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
277 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500278 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500279 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500280 stateField.emplace_back(
281 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500282 }
283 else
284 {
285 stateField.emplace_back(
286 set_effecter_state_field{PLDM_NO_CHANGE, 0});
287 }
288 }
289 auto rc = encode_set_state_effecter_states_req(
290 instanceId, effecterId, effecterCount, stateField.data(), requestMsg);
291 if (rc != PLDM_SUCCESS)
292 {
293 log<level::ERR>("encode set effecter states request returned error ",
294 entry("RC=%d", rc));
295 request.clear();
296 }
297 return request;
298}
299
300void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
301{
302 if (!isPDREffecterCacheValid())
303 {
Eddie James432dc482021-11-19 15:29:31 -0600304 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
305 occInstanceToEffecter, OCCEffecterCount,
306 bootRestartPosition);
Patrick Williams05e95592021-09-02 09:28:14 -0500307 }
308
309 // Find the matching effecter for the OCC instance
310 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
311 if (effecterEntry == occInstanceToEffecter.end())
312 {
313 log<level::ERR>(
314 "pldm: Failed to find a matching effecter for OCC instance",
315 entry("OCC_INSTANCE_ID=%d", occInstanceId));
316
317 return;
318 }
319
320 uint8_t instanceId{};
Eddie Jamescbad2192021-10-07 09:39:39 -0500321 if (!getMctpInstanceId(instanceId))
322 {
323 return;
324 }
Patrick Williams05e95592021-09-02 09:28:14 -0500325
Eddie Jamescbad2192021-10-07 09:39:39 -0500326 // Prepare the SetStateEffecterStates request to reset the OCC
327 auto request = prepareSetEffecterReq(
328 instanceId, effecterEntry->second, OCCEffecterCount,
329 bootRestartPosition, PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
330
331 if (request.empty())
332 {
333 log<level::ERR>("pldm: SetStateEffecterStates OCC reset request empty");
334 return;
335 }
336
337 sendPldm(request);
338}
339
340void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
341{
342 if (sbeInstanceToEffecter.empty())
343 {
Eddie James432dc482021-11-19 15:29:31 -0600344 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
Eddie Jamescbad2192021-10-07 09:39:39 -0500345 sbeInstanceToEffecter, SBEEffecterCount,
346 sbeMaintenanceStatePosition);
347 }
348
349 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
350 if (effecterEntry == sbeInstanceToEffecter.end())
351 {
352 log<level::ERR>(
353 "pldm: Failed to find a matching effecter for SBE instance",
354 entry("SBE=%d", sbeInstanceId));
355 return;
356 }
357
358 uint8_t instanceId{};
359 if (!getMctpInstanceId(instanceId))
360 {
361 return;
362 }
363
364 // Prepare the SetStateEffecterStates request to HRESET the SBE
365 auto request = prepareSetEffecterReq(
366 instanceId, effecterEntry->second, SBEEffecterCount,
367 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
368
369 if (request.empty())
370 {
371 log<level::ERR>("pldm: SetStateEffecterStates HRESET request empty");
372 return;
373 }
374
375 sendPldm(request);
376}
377
378bool Interface::getMctpInstanceId(uint8_t& instanceId)
379{
Patrick Williams05e95592021-09-02 09:28:14 -0500380 auto& bus = open_power::occ::utils::getBus();
381 try
382 {
383 auto method = bus.new_method_call(
384 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
385 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
386 method.append(mctpEid);
387 auto reply = bus.call(method);
388 reply.read(instanceId);
389 }
Patrick Williams25613622021-09-02 09:29:54 -0500390 catch (const sdbusplus::exception::exception& e)
Patrick Williams05e95592021-09-02 09:28:14 -0500391 {
392 log<level::ERR>("pldm: GetInstanceId returned error",
393 entry("ERROR=%s", e.what()));
Eddie Jamescbad2192021-10-07 09:39:39 -0500394 return false;
Patrick Williams05e95592021-09-02 09:28:14 -0500395 }
396
Eddie Jamescbad2192021-10-07 09:39:39 -0500397 return true;
398}
Patrick Williams05e95592021-09-02 09:28:14 -0500399
Eddie Jamescbad2192021-10-07 09:39:39 -0500400void Interface::sendPldm(const std::vector<uint8_t>& request)
401{
Patrick Williams05e95592021-09-02 09:28:14 -0500402 // Connect to MCTP scoket
403 int fd = pldm_open();
404 if (fd == -1)
405 {
406 log<level::ERR>("pldm: Failed to connect to MCTP socket");
407 return;
408 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500409
Patrick Williams05e95592021-09-02 09:28:14 -0500410 open_power::occ::FileDescriptor fileFd(fd);
411
412 // Send the PLDM request message to HBRT
413 uint8_t* response = nullptr;
414 size_t responseSize{};
415 auto rc = pldm_send_recv(mctpEid, fileFd(), request.data(), request.size(),
416 &response, &responseSize);
417 std::unique_ptr<uint8_t, decltype(std::free)*> responsePtr{response,
418 std::free};
419 if (rc)
420 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500421 log<level::ERR>("pldm: pldm_send_recv failed", entry("RC=%d", rc));
Patrick Williams05e95592021-09-02 09:28:14 -0500422 }
423
424 uint8_t completionCode{};
425 auto responseMsg = reinterpret_cast<const pldm_msg*>(responsePtr.get());
426 auto rcDecode = decode_set_state_effecter_states_resp(
427 responseMsg, responseSize - sizeof(pldm_msg_hdr), &completionCode);
428 if (rcDecode || completionCode)
429 {
430 log<level::ERR>(
431 "pldm: decode_set_state_effecter_states_resp returned error",
432 entry("RC=%d", rcDecode),
433 entry("COMPLETION_CODE=%d", completionCode));
434 }
Patrick Williams05e95592021-09-02 09:28:14 -0500435}
436
437} // namespace pldm