blob: 085e19e653e1d6fb67ab10ef1bc31defb1cb3fe8 [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>
9
10#include <phosphor-logging/log.hpp>
11
Eddie Jamescbad2192021-10-07 09:39:39 -050012#define PLDM_OEM_IBM_SBE_MAINTENANCE_STATE 32772
13#define SBE_RETRY_REQUIRED 0x2
14
15#define PLDM_OEM_IBM_SBE_HRESET_STATE 32775
16#define SBE_HRESET_NOT_READY 0x1
17#define SBE_HRESET_READY 0x2
18#define SBE_HRESET_FAILED 0x3
19
Patrick Williams05e95592021-09-02 09:28:14 -050020namespace pldm
21{
22
Patrick Williams05e95592021-09-02 09:28:14 -050023using namespace phosphor::logging;
24
Eddie Jamescbad2192021-10-07 09:39:39 -050025void Interface::fetchSensorInfo(uint16_t stateSetId,
26 SensorToInstance& sensorInstanceMap,
27 SensorOffset& sensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -050028{
Eddie Jamescbad2192021-10-07 09:39:39 -050029 PdrList pdrs{};
30
31 auto& bus = open_power::occ::utils::getBus();
32 try
33 {
34 auto method = bus.new_method_call(
35 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
36 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
37 method.append(tid, (uint16_t)PLDM_ENTITY_PROC, stateSetId);
38
39 auto responseMsg = bus.call(method);
40 responseMsg.read(pdrs);
41 }
42 catch (const sdbusplus::exception::exception& e)
43 {
44 log<level::ERR>("pldm: Failed to fetch the state sensor PDRs",
45 entry("ERROR=%s", e.what()));
46 }
47
48 if (pdrs.empty())
49 {
50 log<level::ERR>("pldm: state sensor PDRs not present");
51 return;
52 }
53
Patrick Williams05e95592021-09-02 09:28:14 -050054 bool offsetFound = false;
55 auto pdr =
56 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
57 auto possibleStatesPtr = pdr->possible_states;
58 for (auto offset = 0; offset < pdr->composite_sensor_count; offset++)
59 {
60 auto possibleStates =
61 reinterpret_cast<const state_sensor_possible_states*>(
62 possibleStatesPtr);
63
Eddie Jamescbad2192021-10-07 09:39:39 -050064 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -050065 {
66 sensorOffset = offset;
67 offsetFound = true;
68 break;
69 }
70 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
71 sizeof(possibleStates->possible_states_size) +
72 possibleStates->possible_states_size;
73 }
74
75 if (!offsetFound)
76 {
Eddie Jamescbad2192021-10-07 09:39:39 -050077 log<level::ERR>("pldm: state sensor PDR not found");
Patrick Williams05e95592021-09-02 09:28:14 -050078 return;
79 }
80
81 // To order SensorID based on the EntityInstance.
82 // Note that when a proc is on a DCM, the PDRs for these sensors
83 // could have the same instance IDs but different container IDs.
84 std::map<uint32_t, SensorID> entityInstMap{};
85 for (auto& pdr : pdrs)
86 {
87 auto pdrPtr =
88 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
89 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
90 static_cast<uint32_t>(pdrPtr->entity_instance);
91 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->sensor_id));
92 }
93
94 open_power::occ::instanceID count = start;
95 for (auto const& pair : entityInstMap)
96 {
97 sensorInstanceMap.emplace(pair.second, count);
98 count++;
99 }
100}
101
102void Interface::sensorEvent(sdbusplus::message::message& msg)
103{
104 if (!isOCCSensorCacheValid())
105 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500106 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
107 sensorToOCCInstance, OCCSensorOffset);
108 }
Patrick Williams05e95592021-09-02 09:28:14 -0500109
Eddie Jamescbad2192021-10-07 09:39:39 -0500110 if (sensorToSBEInstance.empty())
111 {
112 fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSBEInstance,
113 SBESensorOffset);
Patrick Williams05e95592021-09-02 09:28:14 -0500114 }
115
116 TerminusID tid{};
117 SensorID sensorId{};
118 SensorOffset msgSensorOffset{};
119 EventState eventState{};
120 EventState previousEventState{};
121
122 msg.read(tid, sensorId, msgSensorOffset, eventState, previousEventState);
123
Eddie Jamescbad2192021-10-07 09:39:39 -0500124 if (msgSensorOffset == OCCSensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -0500125 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500126 auto sensorEntry = sensorToOCCInstance.find(sensorId);
Patrick Williams05e95592021-09-02 09:28:14 -0500127
Eddie Jamescbad2192021-10-07 09:39:39 -0500128 if (sensorEntry == sensorToOCCInstance.end())
129 {
130 return;
131 }
Patrick Williams05e95592021-09-02 09:28:14 -0500132
Eddie Jamescbad2192021-10-07 09:39:39 -0500133 if (eventState ==
134 static_cast<EventState>(
135 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
136 {
137 log<level::INFO>(
138 fmt::format("PLDM: OCC{} is RUNNING", sensorEntry->second)
139 .c_str());
140 callBack(sensorEntry->second, true);
141 }
142 else if (eventState ==
143 static_cast<EventState>(
144 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
145 {
146 log<level::INFO>(
147 fmt::format("PLDM: OCC{} has now STOPPED", sensorEntry->second)
148 .c_str());
149 callBack(sensorEntry->second, false);
150 }
151 }
152 else if (msgSensorOffset == SBESensorOffset)
153 {
154 auto sensorEntry = sensorToSBEInstance.find(sensorId);
155
156 if (sensorEntry == sensorToSBEInstance.end())
157 {
158 return;
159 }
160
161 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
162 {
163 log<level::INFO>("pldm: HRESET is NOT READY",
164 entry("SBE=%d", sensorEntry->second));
165 }
166 else if (eventState == static_cast<EventState>(SBE_HRESET_READY))
167 {
168 sbeCallBack(sensorEntry->second, true);
169 }
170 else if (eventState == static_cast<EventState>(SBE_HRESET_FAILED))
171 {
172 sbeCallBack(sensorEntry->second, false);
173 }
174 }
Patrick Williams05e95592021-09-02 09:28:14 -0500175}
176
177void Interface::hostStateEvent(sdbusplus::message::message& msg)
178{
179 std::map<std::string, std::variant<std::string>> properties{};
180 std::string interface;
181 msg.read(interface, properties);
182 const auto stateEntry = properties.find("CurrentHostState");
183 if (stateEntry != properties.end())
184 {
185 auto stateEntryValue = stateEntry->second;
186 auto propVal = std::get<std::string>(stateEntryValue);
187 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
188 {
189 sensorToOCCInstance.clear();
190 occInstanceToEffecter.clear();
Eddie Jamescbad2192021-10-07 09:39:39 -0500191
192 sensorToSBEInstance.clear();
193 sbeInstanceToEffecter.clear();
Patrick Williams05e95592021-09-02 09:28:14 -0500194 }
195 }
196}
197
Eddie Jamescbad2192021-10-07 09:39:39 -0500198void Interface::fetchEffecterInfo(uint16_t entityId, uint16_t stateSetId,
199 InstanceToEffecter& instanceToEffecterMap,
200 CompositeEffecterCount& effecterCount,
201 uint8_t& stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500202{
Eddie Jamescbad2192021-10-07 09:39:39 -0500203 PdrList pdrs{};
204
205 auto& bus = open_power::occ::utils::getBus();
206 try
207 {
208 auto method = bus.new_method_call(
209 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
210 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
211 method.append(tid, entityId, stateSetId);
212
213 auto responseMsg = bus.call(method);
214 responseMsg.read(pdrs);
215 }
216 catch (const sdbusplus::exception::exception& e)
217 {
218 log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
219 entry("ERROR=%s", e.what()));
220 }
221
222 if (!pdrs.size())
223 {
224 log<level::ERR>("pldm: state effecter PDRs not present");
225 return;
226 }
227
Patrick Williams05e95592021-09-02 09:28:14 -0500228 bool offsetFound = false;
229 auto pdr =
230 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
231 auto possibleStatesPtr = pdr->possible_states;
232 for (auto offset = 0; offset < pdr->composite_effecter_count; offset++)
233 {
234 auto possibleStates =
235 reinterpret_cast<const state_effecter_possible_states*>(
236 possibleStatesPtr);
237
Eddie Jamescbad2192021-10-07 09:39:39 -0500238 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500239 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500240 stateIdPos = offset;
Patrick Williams05e95592021-09-02 09:28:14 -0500241 effecterCount = pdr->composite_effecter_count;
242 offsetFound = true;
243 break;
244 }
245 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
246 sizeof(possibleStates->possible_states_size) +
247 possibleStates->possible_states_size;
248 }
249
250 if (!offsetFound)
251 {
252 return;
253 }
254
255 std::map<EntityInstance, EffecterID> entityInstMap{};
256 for (auto& pdr : pdrs)
257 {
258 auto pdrPtr =
259 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
260 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
261 static_cast<uint32_t>(pdrPtr->entity_instance);
262 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
263 }
264
265 open_power::occ::instanceID position = start;
266 for (auto const& pair : entityInstMap)
267 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500268 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500269 position++;
270 }
271}
272
273std::vector<uint8_t>
274 Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId,
275 CompositeEffecterCount effecterCount,
Eddie Jamescbad2192021-10-07 09:39:39 -0500276 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500277{
278 std::vector<uint8_t> request(
279 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
280 (effecterCount * sizeof(set_effecter_state_field)));
281 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
282 std::vector<set_effecter_state_field> stateField;
283
284 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
285 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500286 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500287 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500288 stateField.emplace_back(
289 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500290 }
291 else
292 {
293 stateField.emplace_back(
294 set_effecter_state_field{PLDM_NO_CHANGE, 0});
295 }
296 }
297 auto rc = encode_set_state_effecter_states_req(
298 instanceId, effecterId, effecterCount, stateField.data(), requestMsg);
299 if (rc != PLDM_SUCCESS)
300 {
301 log<level::ERR>("encode set effecter states request returned error ",
302 entry("RC=%d", rc));
303 request.clear();
304 }
305 return request;
306}
307
308void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
309{
310 if (!isPDREffecterCacheValid())
311 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500312 fetchEffecterInfo(
313 PLDM_ENTITY_PROC_MODULE, PLDM_STATE_SET_BOOT_RESTART_CAUSE,
314 occInstanceToEffecter, OCCEffecterCount, bootRestartPosition);
Patrick Williams05e95592021-09-02 09:28:14 -0500315 }
316
317 // Find the matching effecter for the OCC instance
318 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
319 if (effecterEntry == occInstanceToEffecter.end())
320 {
321 log<level::ERR>(
322 "pldm: Failed to find a matching effecter for OCC instance",
323 entry("OCC_INSTANCE_ID=%d", occInstanceId));
324
325 return;
326 }
327
328 uint8_t instanceId{};
Eddie Jamescbad2192021-10-07 09:39:39 -0500329 if (!getMctpInstanceId(instanceId))
330 {
331 return;
332 }
Patrick Williams05e95592021-09-02 09:28:14 -0500333
Eddie Jamescbad2192021-10-07 09:39:39 -0500334 // Prepare the SetStateEffecterStates request to reset the OCC
335 auto request = prepareSetEffecterReq(
336 instanceId, effecterEntry->second, OCCEffecterCount,
337 bootRestartPosition, PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
338
339 if (request.empty())
340 {
341 log<level::ERR>("pldm: SetStateEffecterStates OCC reset request empty");
342 return;
343 }
344
345 sendPldm(request);
346}
347
348void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
349{
350 if (sbeInstanceToEffecter.empty())
351 {
352 fetchEffecterInfo(PLDM_ENTITY_PROC, PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
353 sbeInstanceToEffecter, SBEEffecterCount,
354 sbeMaintenanceStatePosition);
355 }
356
357 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
358 if (effecterEntry == sbeInstanceToEffecter.end())
359 {
360 log<level::ERR>(
361 "pldm: Failed to find a matching effecter for SBE instance",
362 entry("SBE=%d", sbeInstanceId));
363 return;
364 }
365
366 uint8_t instanceId{};
367 if (!getMctpInstanceId(instanceId))
368 {
369 return;
370 }
371
372 // Prepare the SetStateEffecterStates request to HRESET the SBE
373 auto request = prepareSetEffecterReq(
374 instanceId, effecterEntry->second, SBEEffecterCount,
375 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
376
377 if (request.empty())
378 {
379 log<level::ERR>("pldm: SetStateEffecterStates HRESET request empty");
380 return;
381 }
382
383 sendPldm(request);
384}
385
386bool Interface::getMctpInstanceId(uint8_t& instanceId)
387{
Patrick Williams05e95592021-09-02 09:28:14 -0500388 auto& bus = open_power::occ::utils::getBus();
389 try
390 {
391 auto method = bus.new_method_call(
392 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
393 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
394 method.append(mctpEid);
395 auto reply = bus.call(method);
396 reply.read(instanceId);
397 }
Patrick Williams25613622021-09-02 09:29:54 -0500398 catch (const sdbusplus::exception::exception& e)
Patrick Williams05e95592021-09-02 09:28:14 -0500399 {
400 log<level::ERR>("pldm: GetInstanceId returned error",
401 entry("ERROR=%s", e.what()));
Eddie Jamescbad2192021-10-07 09:39:39 -0500402 return false;
Patrick Williams05e95592021-09-02 09:28:14 -0500403 }
404
Eddie Jamescbad2192021-10-07 09:39:39 -0500405 return true;
406}
Patrick Williams05e95592021-09-02 09:28:14 -0500407
Eddie Jamescbad2192021-10-07 09:39:39 -0500408void Interface::sendPldm(const std::vector<uint8_t>& request)
409{
Patrick Williams05e95592021-09-02 09:28:14 -0500410 // Connect to MCTP scoket
411 int fd = pldm_open();
412 if (fd == -1)
413 {
414 log<level::ERR>("pldm: Failed to connect to MCTP socket");
415 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
421 uint8_t* response = nullptr;
422 size_t responseSize{};
423 auto rc = pldm_send_recv(mctpEid, fileFd(), request.data(), request.size(),
424 &response, &responseSize);
425 std::unique_ptr<uint8_t, decltype(std::free)*> responsePtr{response,
426 std::free};
427 if (rc)
428 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500429 log<level::ERR>("pldm: pldm_send_recv failed", entry("RC=%d", rc));
Patrick Williams05e95592021-09-02 09:28:14 -0500430 }
431
432 uint8_t completionCode{};
433 auto responseMsg = reinterpret_cast<const pldm_msg*>(responsePtr.get());
434 auto rcDecode = decode_set_state_effecter_states_resp(
435 responseMsg, responseSize - sizeof(pldm_msg_hdr), &completionCode);
436 if (rcDecode || completionCode)
437 {
438 log<level::ERR>(
439 "pldm: decode_set_state_effecter_states_resp returned error",
440 entry("RC=%d", rcDecode),
441 entry("COMPLETION_CODE=%d", completionCode));
442 }
Patrick Williams05e95592021-09-02 09:28:14 -0500443}
444
445} // namespace pldm