blob: 2848ed9f9fa0df8d8f60aefb3f704519b3099633 [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 Jamescbad2192021-10-07 09:39:39 -0500121 if (sensorEntry == sensorToOCCInstance.end())
122 {
123 return;
124 }
Patrick Williams05e95592021-09-02 09:28:14 -0500125
Eddie Jamescbad2192021-10-07 09:39:39 -0500126 if (eventState ==
127 static_cast<EventState>(
128 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
129 {
130 log<level::INFO>(
131 fmt::format("PLDM: OCC{} is RUNNING", sensorEntry->second)
132 .c_str());
133 callBack(sensorEntry->second, true);
134 }
135 else if (eventState ==
136 static_cast<EventState>(
137 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
138 {
139 log<level::INFO>(
140 fmt::format("PLDM: OCC{} has now STOPPED", sensorEntry->second)
141 .c_str());
142 callBack(sensorEntry->second, false);
143 }
144 }
145 else if (msgSensorOffset == SBESensorOffset)
146 {
147 auto sensorEntry = sensorToSBEInstance.find(sensorId);
148
149 if (sensorEntry == sensorToSBEInstance.end())
150 {
151 return;
152 }
153
154 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
155 {
156 log<level::INFO>("pldm: HRESET is NOT READY",
157 entry("SBE=%d", sensorEntry->second));
158 }
159 else if (eventState == static_cast<EventState>(SBE_HRESET_READY))
160 {
161 sbeCallBack(sensorEntry->second, true);
162 }
163 else if (eventState == static_cast<EventState>(SBE_HRESET_FAILED))
164 {
165 sbeCallBack(sensorEntry->second, false);
166 }
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 Jamescbad2192021-10-07 09:39:39 -0500191void Interface::fetchEffecterInfo(uint16_t entityId, uint16_t stateSetId,
192 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");
204 method.append(tid, entityId, stateSetId);
205
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;
222 auto pdr =
223 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
224 auto possibleStatesPtr = pdr->possible_states;
225 for (auto offset = 0; offset < pdr->composite_effecter_count; offset++)
226 {
227 auto possibleStates =
228 reinterpret_cast<const state_effecter_possible_states*>(
229 possibleStatesPtr);
230
Eddie Jamescbad2192021-10-07 09:39:39 -0500231 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500232 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500233 stateIdPos = offset;
Patrick Williams05e95592021-09-02 09:28:14 -0500234 effecterCount = pdr->composite_effecter_count;
235 offsetFound = true;
236 break;
237 }
238 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
239 sizeof(possibleStates->possible_states_size) +
240 possibleStates->possible_states_size;
241 }
242
243 if (!offsetFound)
244 {
245 return;
246 }
247
248 std::map<EntityInstance, EffecterID> entityInstMap{};
249 for (auto& pdr : pdrs)
250 {
251 auto pdrPtr =
252 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
253 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
254 static_cast<uint32_t>(pdrPtr->entity_instance);
255 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
256 }
257
258 open_power::occ::instanceID position = start;
259 for (auto const& pair : entityInstMap)
260 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500261 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500262 position++;
263 }
264}
265
266std::vector<uint8_t>
267 Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId,
268 CompositeEffecterCount effecterCount,
Eddie Jamescbad2192021-10-07 09:39:39 -0500269 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500270{
271 std::vector<uint8_t> request(
272 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
273 (effecterCount * sizeof(set_effecter_state_field)));
274 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
275 std::vector<set_effecter_state_field> stateField;
276
277 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
278 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500279 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500280 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500281 stateField.emplace_back(
282 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500283 }
284 else
285 {
286 stateField.emplace_back(
287 set_effecter_state_field{PLDM_NO_CHANGE, 0});
288 }
289 }
290 auto rc = encode_set_state_effecter_states_req(
291 instanceId, effecterId, effecterCount, stateField.data(), requestMsg);
292 if (rc != PLDM_SUCCESS)
293 {
294 log<level::ERR>("encode set effecter states request returned error ",
295 entry("RC=%d", rc));
296 request.clear();
297 }
298 return request;
299}
300
301void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
302{
303 if (!isPDREffecterCacheValid())
304 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500305 fetchEffecterInfo(
306 PLDM_ENTITY_PROC_MODULE, PLDM_STATE_SET_BOOT_RESTART_CAUSE,
307 occInstanceToEffecter, OCCEffecterCount, bootRestartPosition);
Patrick Williams05e95592021-09-02 09:28:14 -0500308 }
309
310 // Find the matching effecter for the OCC instance
311 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
312 if (effecterEntry == occInstanceToEffecter.end())
313 {
314 log<level::ERR>(
315 "pldm: Failed to find a matching effecter for OCC instance",
316 entry("OCC_INSTANCE_ID=%d", occInstanceId));
317
318 return;
319 }
320
321 uint8_t instanceId{};
Eddie Jamescbad2192021-10-07 09:39:39 -0500322 if (!getMctpInstanceId(instanceId))
323 {
324 return;
325 }
Patrick Williams05e95592021-09-02 09:28:14 -0500326
Eddie Jamescbad2192021-10-07 09:39:39 -0500327 // Prepare the SetStateEffecterStates request to reset the OCC
328 auto request = prepareSetEffecterReq(
329 instanceId, effecterEntry->second, OCCEffecterCount,
330 bootRestartPosition, PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
331
332 if (request.empty())
333 {
334 log<level::ERR>("pldm: SetStateEffecterStates OCC reset request empty");
335 return;
336 }
337
338 sendPldm(request);
339}
340
341void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
342{
343 if (sbeInstanceToEffecter.empty())
344 {
345 fetchEffecterInfo(PLDM_ENTITY_PROC, PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
346 sbeInstanceToEffecter, SBEEffecterCount,
347 sbeMaintenanceStatePosition);
348 }
349
350 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
351 if (effecterEntry == sbeInstanceToEffecter.end())
352 {
353 log<level::ERR>(
354 "pldm: Failed to find a matching effecter for SBE instance",
355 entry("SBE=%d", sbeInstanceId));
356 return;
357 }
358
359 uint8_t instanceId{};
360 if (!getMctpInstanceId(instanceId))
361 {
362 return;
363 }
364
365 // Prepare the SetStateEffecterStates request to HRESET the SBE
366 auto request = prepareSetEffecterReq(
367 instanceId, effecterEntry->second, SBEEffecterCount,
368 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
369
370 if (request.empty())
371 {
372 log<level::ERR>("pldm: SetStateEffecterStates HRESET request empty");
373 return;
374 }
375
376 sendPldm(request);
377}
378
379bool Interface::getMctpInstanceId(uint8_t& instanceId)
380{
Patrick Williams05e95592021-09-02 09:28:14 -0500381 auto& bus = open_power::occ::utils::getBus();
382 try
383 {
384 auto method = bus.new_method_call(
385 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
386 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
387 method.append(mctpEid);
388 auto reply = bus.call(method);
389 reply.read(instanceId);
390 }
Patrick Williams25613622021-09-02 09:29:54 -0500391 catch (const sdbusplus::exception::exception& e)
Patrick Williams05e95592021-09-02 09:28:14 -0500392 {
393 log<level::ERR>("pldm: GetInstanceId returned error",
394 entry("ERROR=%s", e.what()));
Eddie Jamescbad2192021-10-07 09:39:39 -0500395 return false;
Patrick Williams05e95592021-09-02 09:28:14 -0500396 }
397
Eddie Jamescbad2192021-10-07 09:39:39 -0500398 return true;
399}
Patrick Williams05e95592021-09-02 09:28:14 -0500400
Eddie Jamescbad2192021-10-07 09:39:39 -0500401void Interface::sendPldm(const std::vector<uint8_t>& request)
402{
Patrick Williams05e95592021-09-02 09:28:14 -0500403 // Connect to MCTP scoket
404 int fd = pldm_open();
405 if (fd == -1)
406 {
407 log<level::ERR>("pldm: Failed to connect to MCTP socket");
408 return;
409 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500410
Patrick Williams05e95592021-09-02 09:28:14 -0500411 open_power::occ::FileDescriptor fileFd(fd);
412
413 // Send the PLDM request message to HBRT
414 uint8_t* response = nullptr;
415 size_t responseSize{};
416 auto rc = pldm_send_recv(mctpEid, fileFd(), request.data(), request.size(),
417 &response, &responseSize);
418 std::unique_ptr<uint8_t, decltype(std::free)*> responsePtr{response,
419 std::free};
420 if (rc)
421 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500422 log<level::ERR>("pldm: pldm_send_recv failed", entry("RC=%d", rc));
Patrick Williams05e95592021-09-02 09:28:14 -0500423 }
424
425 uint8_t completionCode{};
426 auto responseMsg = reinterpret_cast<const pldm_msg*>(responsePtr.get());
427 auto rcDecode = decode_set_state_effecter_states_resp(
428 responseMsg, responseSize - sizeof(pldm_msg_hdr), &completionCode);
429 if (rcDecode || completionCode)
430 {
431 log<level::ERR>(
432 "pldm: decode_set_state_effecter_states_resp returned error",
433 entry("RC=%d", rcDecode),
434 entry("COMPLETION_CODE=%d", completionCode));
435 }
Patrick Williams05e95592021-09-02 09:28:14 -0500436}
437
438} // namespace pldm