blob: c00d4845ef5a2192bc3ee3898f861206901c0427 [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
Chris Cain0f516522022-02-07 14:48:28 -0600249 std::map<uint32_t, EffecterID> entityInstMap{};
Patrick Williams05e95592021-09-02 09:28:14 -0500250 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>(
Chris Cain0f516522022-02-07 14:48:28 -0600316 fmt::format(
317 "pldm: Failed to find a matching effecter for OCC instance {}",
318 occInstanceId)
319 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500320
321 return;
322 }
323
324 uint8_t instanceId{};
Eddie Jamescbad2192021-10-07 09:39:39 -0500325 if (!getMctpInstanceId(instanceId))
326 {
327 return;
328 }
Patrick Williams05e95592021-09-02 09:28:14 -0500329
Eddie Jamescbad2192021-10-07 09:39:39 -0500330 // Prepare the SetStateEffecterStates request to reset the OCC
331 auto request = prepareSetEffecterReq(
332 instanceId, effecterEntry->second, OCCEffecterCount,
333 bootRestartPosition, PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
334
335 if (request.empty())
336 {
337 log<level::ERR>("pldm: SetStateEffecterStates OCC reset request empty");
338 return;
339 }
340
Chris Caind1b68262022-02-28 09:56:50 -0600341 // Make asynchronous call to reset the OCCs/PM Complex
342 sendPldm(request, true);
Eddie Jamescbad2192021-10-07 09:39:39 -0500343}
344
345void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
346{
347 if (sbeInstanceToEffecter.empty())
348 {
Eddie James432dc482021-11-19 15:29:31 -0600349 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
Eddie Jamescbad2192021-10-07 09:39:39 -0500350 sbeInstanceToEffecter, SBEEffecterCount,
351 sbeMaintenanceStatePosition);
352 }
353
354 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
355 if (effecterEntry == sbeInstanceToEffecter.end())
356 {
357 log<level::ERR>(
358 "pldm: Failed to find a matching effecter for SBE instance",
359 entry("SBE=%d", sbeInstanceId));
360 return;
361 }
362
363 uint8_t instanceId{};
364 if (!getMctpInstanceId(instanceId))
365 {
366 return;
367 }
368
369 // Prepare the SetStateEffecterStates request to HRESET the SBE
370 auto request = prepareSetEffecterReq(
371 instanceId, effecterEntry->second, SBEEffecterCount,
372 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
373
374 if (request.empty())
375 {
376 log<level::ERR>("pldm: SetStateEffecterStates HRESET request empty");
377 return;
378 }
379
380 sendPldm(request);
381}
382
383bool Interface::getMctpInstanceId(uint8_t& instanceId)
384{
Patrick Williams05e95592021-09-02 09:28:14 -0500385 auto& bus = open_power::occ::utils::getBus();
386 try
387 {
388 auto method = bus.new_method_call(
389 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
390 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
391 method.append(mctpEid);
392 auto reply = bus.call(method);
393 reply.read(instanceId);
394 }
Patrick Williams25613622021-09-02 09:29:54 -0500395 catch (const sdbusplus::exception::exception& e)
Patrick Williams05e95592021-09-02 09:28:14 -0500396 {
397 log<level::ERR>("pldm: GetInstanceId returned error",
398 entry("ERROR=%s", e.what()));
Eddie Jamescbad2192021-10-07 09:39:39 -0500399 return false;
Patrick Williams05e95592021-09-02 09:28:14 -0500400 }
401
Eddie Jamescbad2192021-10-07 09:39:39 -0500402 return true;
403}
Patrick Williams05e95592021-09-02 09:28:14 -0500404
Chris Caind1b68262022-02-28 09:56:50 -0600405void Interface::sendPldm(const std::vector<uint8_t>& request, const bool async)
Eddie Jamescbad2192021-10-07 09:39:39 -0500406{
Patrick Williams05e95592021-09-02 09:28:14 -0500407 // Connect to MCTP scoket
408 int fd = pldm_open();
409 if (fd == -1)
410 {
Chris Caind1b68262022-02-28 09:56:50 -0600411 log<level::ERR>(
412 fmt::format("sendPldm: Failed to connect to MCTP socket, errno={}",
413 errno)
414 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500415 return;
416 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500417
Patrick Williams05e95592021-09-02 09:28:14 -0500418 open_power::occ::FileDescriptor fileFd(fd);
419
420 // Send the PLDM request message to HBRT
Chris Caind1b68262022-02-28 09:56:50 -0600421 if (async == false)
Patrick Williams05e95592021-09-02 09:28:14 -0500422 {
Chris Caind1b68262022-02-28 09:56:50 -0600423 uint8_t* response = nullptr;
424 size_t responseSize{};
425 auto rc = pldm_send_recv(mctpEid, fileFd(), request.data(),
426 request.size(), &response, &responseSize);
427 std::unique_ptr<uint8_t, decltype(std::free)*> responsePtr{response,
428 std::free};
429 if (rc)
430 {
431 log<level::ERR>(
432 fmt::format(
433 "sendPldm: pldm_send_recv({},{},req,{},...) failed with rc={} and errno={}",
434 mctpEid, fileFd(), request.size(), rc, errno)
435 .c_str());
436 }
Patrick Williams05e95592021-09-02 09:28:14 -0500437
Chris Caind1b68262022-02-28 09:56:50 -0600438 uint8_t completionCode{};
439 auto responseMsg = reinterpret_cast<const pldm_msg*>(responsePtr.get());
440 auto rcDecode = decode_set_state_effecter_states_resp(
441 responseMsg, responseSize - sizeof(pldm_msg_hdr), &completionCode);
442 if (rcDecode || completionCode)
443 {
444 log<level::ERR>(
445 fmt::format(
446 "sendPldm: decode_set_state_effecter_states_resp failed with rc={} and compCode={}",
447 rcDecode, completionCode)
448 .c_str());
449 }
450 }
451 else
Patrick Williams05e95592021-09-02 09:28:14 -0500452 {
Chris Caind1b68262022-02-28 09:56:50 -0600453 log<level::INFO>(fmt::format("sendPldm: calling pldm_send({}, {})",
454 mctpEid, fileFd())
455 .c_str());
456 auto rc = pldm_send(mctpEid, fileFd(), request.data(), request.size());
457 if (rc)
458 {
459 log<level::ERR>(
460 fmt::format(
461 "sendPldm: pldm_send({},{},req,{}) failed with rc={} and errno={}",
462 mctpEid, fileFd(), request.size(), rc, errno)
463 .c_str());
464 }
Patrick Williams05e95592021-09-02 09:28:14 -0500465 }
Patrick Williams05e95592021-09-02 09:28:14 -0500466}
467
468} // namespace pldm