blob: 43b86abde458b5523d5d2f94a83c9d99cb47328e [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;
George Liuf3a4a692021-12-28 13:59:51 +080048 auto stateSensorPDR =
Patrick Williams05e95592021-09-02 09:28:14 -050049 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +080050 auto possibleStatesPtr = stateSensorPDR->possible_states;
51 for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count;
52 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -050053 {
54 auto possibleStates =
55 reinterpret_cast<const state_sensor_possible_states*>(
56 possibleStatesPtr);
57
Eddie Jamescbad2192021-10-07 09:39:39 -050058 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -050059 {
60 sensorOffset = offset;
61 offsetFound = true;
62 break;
63 }
64 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
65 sizeof(possibleStates->possible_states_size) +
66 possibleStates->possible_states_size;
67 }
68
69 if (!offsetFound)
70 {
Eddie Jamescbad2192021-10-07 09:39:39 -050071 log<level::ERR>("pldm: state sensor PDR not found");
Patrick Williams05e95592021-09-02 09:28:14 -050072 return;
73 }
74
75 // To order SensorID based on the EntityInstance.
76 // Note that when a proc is on a DCM, the PDRs for these sensors
77 // could have the same instance IDs but different container IDs.
78 std::map<uint32_t, SensorID> entityInstMap{};
79 for (auto& pdr : pdrs)
80 {
81 auto pdrPtr =
82 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
83 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
84 static_cast<uint32_t>(pdrPtr->entity_instance);
85 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->sensor_id));
86 }
87
88 open_power::occ::instanceID count = start;
89 for (auto const& pair : entityInstMap)
90 {
91 sensorInstanceMap.emplace(pair.second, count);
92 count++;
93 }
94}
95
96void Interface::sensorEvent(sdbusplus::message::message& msg)
97{
98 if (!isOCCSensorCacheValid())
99 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500100 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
101 sensorToOCCInstance, OCCSensorOffset);
102 }
Patrick Williams05e95592021-09-02 09:28:14 -0500103
Eddie Jamescbad2192021-10-07 09:39:39 -0500104 if (sensorToSBEInstance.empty())
105 {
106 fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSBEInstance,
107 SBESensorOffset);
Patrick Williams05e95592021-09-02 09:28:14 -0500108 }
109
110 TerminusID tid{};
111 SensorID sensorId{};
112 SensorOffset msgSensorOffset{};
113 EventState eventState{};
114 EventState previousEventState{};
115
116 msg.read(tid, sensorId, msgSensorOffset, eventState, previousEventState);
117
Eddie Jamescbad2192021-10-07 09:39:39 -0500118 if (msgSensorOffset == OCCSensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -0500119 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500120 auto sensorEntry = sensorToOCCInstance.find(sensorId);
Patrick Williams05e95592021-09-02 09:28:14 -0500121
Eddie James432dc482021-11-19 15:29:31 -0600122 if (sensorEntry != sensorToOCCInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500123 {
Eddie James432dc482021-11-19 15:29:31 -0600124 if (eventState ==
125 static_cast<EventState>(
126 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
127 {
128 log<level::INFO>(
129 fmt::format("PLDM: OCC{} is RUNNING", sensorEntry->second)
130 .c_str());
131 callBack(sensorEntry->second, true);
132 }
133 else if (eventState ==
134 static_cast<EventState>(
135 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
136 {
137 log<level::INFO>(fmt::format("PLDM: OCC{} has now STOPPED",
138 sensorEntry->second)
139 .c_str());
140 callBack(sensorEntry->second, false);
141 }
142
Eddie Jamescbad2192021-10-07 09:39:39 -0500143 return;
144 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500145 }
Eddie James432dc482021-11-19 15:29:31 -0600146
147 if (msgSensorOffset == SBESensorOffset)
Eddie Jamescbad2192021-10-07 09:39:39 -0500148 {
149 auto sensorEntry = sensorToSBEInstance.find(sensorId);
150
Eddie James432dc482021-11-19 15:29:31 -0600151 if (sensorEntry != sensorToSBEInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500152 {
Eddie James432dc482021-11-19 15:29:31 -0600153 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
154 {
155 log<level::INFO>("pldm: HRESET is NOT READY",
156 entry("SBE=%d", sensorEntry->second));
157 }
158 else if (eventState == static_cast<EventState>(SBE_HRESET_READY))
159 {
160 sbeCallBack(sensorEntry->second, true);
161 }
162 else if (eventState == static_cast<EventState>(SBE_HRESET_FAILED))
163 {
164 sbeCallBack(sensorEntry->second, false);
165 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500166 }
167 }
Patrick Williams05e95592021-09-02 09:28:14 -0500168}
169
170void Interface::hostStateEvent(sdbusplus::message::message& msg)
171{
172 std::map<std::string, std::variant<std::string>> properties{};
173 std::string interface;
174 msg.read(interface, properties);
175 const auto stateEntry = properties.find("CurrentHostState");
176 if (stateEntry != properties.end())
177 {
178 auto stateEntryValue = stateEntry->second;
179 auto propVal = std::get<std::string>(stateEntryValue);
180 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
181 {
182 sensorToOCCInstance.clear();
183 occInstanceToEffecter.clear();
Eddie Jamescbad2192021-10-07 09:39:39 -0500184
185 sensorToSBEInstance.clear();
186 sbeInstanceToEffecter.clear();
Patrick Williams05e95592021-09-02 09:28:14 -0500187 }
188 }
189}
190
Eddie James432dc482021-11-19 15:29:31 -0600191void Interface::fetchEffecterInfo(uint16_t stateSetId,
Eddie Jamescbad2192021-10-07 09:39:39 -0500192 InstanceToEffecter& instanceToEffecterMap,
193 CompositeEffecterCount& effecterCount,
194 uint8_t& stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500195{
Eddie Jamescbad2192021-10-07 09:39:39 -0500196 PdrList pdrs{};
197
198 auto& bus = open_power::occ::utils::getBus();
199 try
200 {
201 auto method = bus.new_method_call(
202 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
203 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Eddie James432dc482021-11-19 15:29:31 -0600204 method.append(tid, (uint16_t)PLDM_ENTITY_PROC, stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -0500205
206 auto responseMsg = bus.call(method);
207 responseMsg.read(pdrs);
208 }
209 catch (const sdbusplus::exception::exception& e)
210 {
211 log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
212 entry("ERROR=%s", e.what()));
213 }
214
215 if (!pdrs.size())
216 {
217 log<level::ERR>("pldm: state effecter PDRs not present");
218 return;
219 }
220
Patrick Williams05e95592021-09-02 09:28:14 -0500221 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +0800222 auto stateEffecterPDR =
Patrick Williams05e95592021-09-02 09:28:14 -0500223 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +0800224 auto possibleStatesPtr = stateEffecterPDR->possible_states;
225 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
226 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -0500227 {
228 auto possibleStates =
229 reinterpret_cast<const state_effecter_possible_states*>(
230 possibleStatesPtr);
231
Eddie Jamescbad2192021-10-07 09:39:39 -0500232 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500233 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500234 stateIdPos = offset;
George Liuf3a4a692021-12-28 13:59:51 +0800235 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams05e95592021-09-02 09:28:14 -0500236 offsetFound = true;
237 break;
238 }
239 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
240 sizeof(possibleStates->possible_states_size) +
241 possibleStates->possible_states_size;
242 }
243
244 if (!offsetFound)
245 {
246 return;
247 }
248
249 std::map<EntityInstance, EffecterID> entityInstMap{};
250 for (auto& pdr : pdrs)
251 {
252 auto pdrPtr =
253 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
254 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
255 static_cast<uint32_t>(pdrPtr->entity_instance);
256 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
257 }
258
259 open_power::occ::instanceID position = start;
260 for (auto const& pair : entityInstMap)
261 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500262 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500263 position++;
264 }
265}
266
267std::vector<uint8_t>
268 Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId,
269 CompositeEffecterCount effecterCount,
Eddie Jamescbad2192021-10-07 09:39:39 -0500270 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500271{
272 std::vector<uint8_t> request(
273 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
274 (effecterCount * sizeof(set_effecter_state_field)));
275 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
276 std::vector<set_effecter_state_field> stateField;
277
278 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
279 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500280 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500281 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500282 stateField.emplace_back(
283 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500284 }
285 else
286 {
287 stateField.emplace_back(
288 set_effecter_state_field{PLDM_NO_CHANGE, 0});
289 }
290 }
291 auto rc = encode_set_state_effecter_states_req(
292 instanceId, effecterId, effecterCount, stateField.data(), requestMsg);
293 if (rc != PLDM_SUCCESS)
294 {
295 log<level::ERR>("encode set effecter states request returned error ",
296 entry("RC=%d", rc));
297 request.clear();
298 }
299 return request;
300}
301
302void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
303{
304 if (!isPDREffecterCacheValid())
305 {
Eddie James432dc482021-11-19 15:29:31 -0600306 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
307 occInstanceToEffecter, OCCEffecterCount,
308 bootRestartPosition);
Patrick Williams05e95592021-09-02 09:28:14 -0500309 }
310
311 // Find the matching effecter for the OCC instance
312 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
313 if (effecterEntry == occInstanceToEffecter.end())
314 {
315 log<level::ERR>(
316 "pldm: Failed to find a matching effecter for OCC instance",
317 entry("OCC_INSTANCE_ID=%d", occInstanceId));
318
319 return;
320 }
321
322 uint8_t instanceId{};
Eddie Jamescbad2192021-10-07 09:39:39 -0500323 if (!getMctpInstanceId(instanceId))
324 {
325 return;
326 }
Patrick Williams05e95592021-09-02 09:28:14 -0500327
Eddie Jamescbad2192021-10-07 09:39:39 -0500328 // Prepare the SetStateEffecterStates request to reset the OCC
329 auto request = prepareSetEffecterReq(
330 instanceId, effecterEntry->second, OCCEffecterCount,
331 bootRestartPosition, PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
332
333 if (request.empty())
334 {
335 log<level::ERR>("pldm: SetStateEffecterStates OCC reset request empty");
336 return;
337 }
338
339 sendPldm(request);
340}
341
342void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
343{
344 if (sbeInstanceToEffecter.empty())
345 {
Eddie James432dc482021-11-19 15:29:31 -0600346 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
Eddie Jamescbad2192021-10-07 09:39:39 -0500347 sbeInstanceToEffecter, SBEEffecterCount,
348 sbeMaintenanceStatePosition);
349 }
350
351 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
352 if (effecterEntry == sbeInstanceToEffecter.end())
353 {
354 log<level::ERR>(
355 "pldm: Failed to find a matching effecter for SBE instance",
356 entry("SBE=%d", sbeInstanceId));
357 return;
358 }
359
360 uint8_t instanceId{};
361 if (!getMctpInstanceId(instanceId))
362 {
363 return;
364 }
365
366 // Prepare the SetStateEffecterStates request to HRESET the SBE
367 auto request = prepareSetEffecterReq(
368 instanceId, effecterEntry->second, SBEEffecterCount,
369 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
370
371 if (request.empty())
372 {
373 log<level::ERR>("pldm: SetStateEffecterStates HRESET request empty");
374 return;
375 }
376
377 sendPldm(request);
378}
379
380bool Interface::getMctpInstanceId(uint8_t& instanceId)
381{
Patrick Williams05e95592021-09-02 09:28:14 -0500382 auto& bus = open_power::occ::utils::getBus();
383 try
384 {
385 auto method = bus.new_method_call(
386 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
387 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
388 method.append(mctpEid);
389 auto reply = bus.call(method);
390 reply.read(instanceId);
391 }
Patrick Williams25613622021-09-02 09:29:54 -0500392 catch (const sdbusplus::exception::exception& e)
Patrick Williams05e95592021-09-02 09:28:14 -0500393 {
394 log<level::ERR>("pldm: GetInstanceId returned error",
395 entry("ERROR=%s", e.what()));
Eddie Jamescbad2192021-10-07 09:39:39 -0500396 return false;
Patrick Williams05e95592021-09-02 09:28:14 -0500397 }
398
Eddie Jamescbad2192021-10-07 09:39:39 -0500399 return true;
400}
Patrick Williams05e95592021-09-02 09:28:14 -0500401
Eddie Jamescbad2192021-10-07 09:39:39 -0500402void Interface::sendPldm(const std::vector<uint8_t>& request)
403{
Patrick Williams05e95592021-09-02 09:28:14 -0500404 // Connect to MCTP scoket
405 int fd = pldm_open();
406 if (fd == -1)
407 {
408 log<level::ERR>("pldm: Failed to connect to MCTP socket");
409 return;
410 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500411
Patrick Williams05e95592021-09-02 09:28:14 -0500412 open_power::occ::FileDescriptor fileFd(fd);
413
414 // Send the PLDM request message to HBRT
415 uint8_t* response = nullptr;
416 size_t responseSize{};
417 auto rc = pldm_send_recv(mctpEid, fileFd(), request.data(), request.size(),
418 &response, &responseSize);
419 std::unique_ptr<uint8_t, decltype(std::free)*> responsePtr{response,
420 std::free};
421 if (rc)
422 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500423 log<level::ERR>("pldm: pldm_send_recv failed", entry("RC=%d", rc));
Patrick Williams05e95592021-09-02 09:28:14 -0500424 }
425
426 uint8_t completionCode{};
427 auto responseMsg = reinterpret_cast<const pldm_msg*>(responsePtr.get());
428 auto rcDecode = decode_set_state_effecter_states_resp(
429 responseMsg, responseSize - sizeof(pldm_msg_hdr), &completionCode);
430 if (rcDecode || completionCode)
431 {
432 log<level::ERR>(
433 "pldm: decode_set_state_effecter_states_resp returned error",
434 entry("RC=%d", rcDecode),
435 entry("COMPLETION_CODE=%d", completionCode));
436 }
Patrick Williams05e95592021-09-02 09:28:14 -0500437}
438
439} // namespace pldm