blob: 39437ad389ea4649f8814b1e522a0ddd9b0d276c [file] [log] [blame]
Tom Joseph815f9f52020-07-27 12:12:13 +05301#include "pldm.hpp"
2
Tom Joseph00325232020-07-29 17:51:48 +05303#include "file.hpp"
4
Chris Caina8857c52021-01-27 11:53:05 -06005#include <fmt/core.h>
Tom Joseph815f9f52020-07-27 12:12:13 +05306#include <libpldm/entity.h>
7#include <libpldm/platform.h>
8#include <libpldm/state_set.h>
9
10#include <phosphor-logging/log.hpp>
11
12namespace pldm
13{
14
15using sdbusplus::exception::SdBusError;
16using namespace phosphor::logging;
17
18void Interface::fetchOCCSensorInfo(const PdrList& pdrs,
19 SensorToOCCInstance& sensorInstanceMap,
20 SensorOffset& sensorOffset)
21{
22 bool offsetFound = false;
23 auto pdr =
24 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
25 auto possibleStatesPtr = pdr->possible_states;
26 for (auto offset = 0; offset < pdr->composite_sensor_count; offset++)
27 {
28 auto possibleStates =
29 reinterpret_cast<const state_sensor_possible_states*>(
30 possibleStatesPtr);
31
32 if (possibleStates->state_set_id ==
33 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS)
34 {
35 sensorOffset = offset;
36 offsetFound = true;
37 break;
38 }
39 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
40 sizeof(possibleStates->possible_states_size) +
41 possibleStates->possible_states_size;
42 }
43
44 if (!offsetFound)
45 {
46 log<level::ERR>("pldm: OCC state sensor PDR with StateSetId "
47 "PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS not found");
48 return;
49 }
50
51 // To order SensorID based on the EntityInstance
52 std::map<EntityInstance, SensorID> entityInstMap{};
53 for (auto& pdr : pdrs)
54 {
55 auto pdrPtr =
56 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
57 entityInstMap.emplace(
58 static_cast<EntityInstance>(pdrPtr->entity_instance),
59 static_cast<SensorID>(pdrPtr->sensor_id));
60 }
61
62 open_power::occ::instanceID count = start;
63 for (auto const& pair : entityInstMap)
64 {
65 sensorInstanceMap.emplace(pair.second, count);
66 count++;
67 }
68}
69
70void Interface::sensorEvent(sdbusplus::message::message& msg)
71{
72 if (!isOCCSensorCacheValid())
73 {
74 PdrList pdrs{};
75
76 try
77 {
78 auto method = bus.new_method_call(
79 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
80 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
81 method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE,
82 (uint16_t)PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS);
83
84 auto responseMsg = bus.call(method);
85 responseMsg.read(pdrs);
86 }
87 catch (const SdBusError& e)
88 {
89 log<level::ERR>("pldm: Failed to fetch the OCC state sensor PDRs",
90 entry("ERROR=%s", e.what()));
91 }
92
93 if (!pdrs.size())
94 {
95 log<level::ERR>("pldm: OCC state sensor PDRs not present");
96 return;
97 }
98
99 fetchOCCSensorInfo(pdrs, sensorToOCCInstance, sensorOffset);
100 }
101
102 TerminusID tid{};
103 SensorID sensorId{};
104 SensorOffset msgSensorOffset{};
105 EventState eventState{};
106 EventState previousEventState{};
107
George Liua17f6e82021-02-23 17:43:51 +0800108 msg.read(tid, sensorId, msgSensorOffset, eventState, previousEventState);
Tom Joseph815f9f52020-07-27 12:12:13 +0530109
110 auto sensorEntry = sensorToOCCInstance.find(sensorId);
111 if (sensorEntry == sensorToOCCInstance.end() ||
112 (msgSensorOffset != sensorOffset))
113 {
114 // No action for non matching sensorEvents
115 return;
116 }
117
Tom Joseph815f9f52020-07-27 12:12:13 +0530118 if (eventState == static_cast<EventState>(
119 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
120 {
Chris Caina8857c52021-01-27 11:53:05 -0600121 log<level::INFO>(
122 fmt::format("PLDM: OCC{} is RUNNING", sensorEntry->second).c_str());
123 callBack(sensorEntry->second, true);
Tom Joseph815f9f52020-07-27 12:12:13 +0530124 }
125 else if (eventState ==
126 static_cast<EventState>(
127 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
128 {
Chris Caina8857c52021-01-27 11:53:05 -0600129 log<level::INFO>(
130 fmt::format("PLDM: OCC{} has now STOPPED", sensorEntry->second)
131 .c_str());
132 callBack(sensorEntry->second, false);
Tom Joseph815f9f52020-07-27 12:12:13 +0530133 }
134
Tom Joseph815f9f52020-07-27 12:12:13 +0530135 return;
136}
137
138void Interface::hostStateEvent(sdbusplus::message::message& msg)
139{
140 std::map<std::string, std::variant<std::string>> properties{};
141 std::string interface;
142 msg.read(interface, properties);
143 const auto stateEntry = properties.find("CurrentHostState");
144 if (stateEntry != properties.end())
145 {
146 auto stateEntryValue = stateEntry->second;
147 auto propVal = std::get<std::string>(stateEntryValue);
148 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
149 {
150 sensorToOCCInstance.clear();
Tom Joseph00325232020-07-29 17:51:48 +0530151 occInstanceToEffecter.clear();
Tom Joseph815f9f52020-07-27 12:12:13 +0530152 }
153 }
154}
155
Tom Joseph00325232020-07-29 17:51:48 +0530156void Interface::fetchOCCEffecterInfo(
157 const PdrList& pdrs, OccInstanceToEffecter& instanceToEffecterMap,
158 CompositeEffecterCount& count, uint8_t& bootRestartPos)
159{
160 bool offsetFound = false;
161 auto pdr =
162 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
163 auto possibleStatesPtr = pdr->possible_states;
164 for (auto offset = 0; offset < pdr->composite_effecter_count; offset++)
165 {
166 auto possibleStates =
167 reinterpret_cast<const state_effecter_possible_states*>(
168 possibleStatesPtr);
169
170 if (possibleStates->state_set_id == PLDM_STATE_SET_BOOT_RESTART_CAUSE)
171 {
172 bootRestartPos = offset;
173 effecterCount = pdr->composite_effecter_count;
174 offsetFound = true;
175 break;
176 }
177 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
178 sizeof(possibleStates->possible_states_size) +
179 possibleStates->possible_states_size;
180 }
181
182 if (!offsetFound)
183 {
184 return;
185 }
186
187 std::map<EntityInstance, EffecterID> entityInstMap{};
188 for (auto& pdr : pdrs)
189 {
190 auto pdrPtr =
191 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
192 entityInstMap.emplace(
193 static_cast<EntityInstance>(pdrPtr->entity_instance),
194 static_cast<SensorID>(pdrPtr->effecter_id));
195 }
196
197 open_power::occ::instanceID position = start;
198 for (auto const& pair : entityInstMap)
199 {
200 occInstanceToEffecter.emplace(position, pair.second);
201 position++;
202 }
203}
204
205std::vector<uint8_t>
206 Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId,
207 CompositeEffecterCount effecterCount,
208 uint8_t bootRestartPos)
209{
210 std::vector<uint8_t> request(
211 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
212 (effecterCount * sizeof(set_effecter_state_field)));
213 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
214 std::vector<set_effecter_state_field> stateField;
215
216 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
217 {
218 if (effecterPos == bootRestartPos)
219 {
220 stateField.emplace_back(set_effecter_state_field{
221 PLDM_REQUEST_SET,
222 PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET});
223 }
224 else
225 {
226 stateField.emplace_back(
227 set_effecter_state_field{PLDM_NO_CHANGE, 0});
228 }
229 }
230 auto rc = encode_set_state_effecter_states_req(
231 instanceId, effecterId, effecterCount, stateField.data(), requestMsg);
232 if (rc != PLDM_SUCCESS)
233 {
234 log<level::ERR>("encode set effecter states request returned error ",
235 entry("RC=%d", rc));
236 request.clear();
237 }
238 return request;
239}
240
241void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
242{
243 if (!isPDREffecterCacheValid())
244 {
245 PdrList pdrs{};
246
247 try
248 {
249 auto method = bus.new_method_call(
250 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
251 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
252 method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE,
253 (uint16_t)PLDM_STATE_SET_BOOT_RESTART_CAUSE);
254
255 auto responseMsg = bus.call(method);
256 responseMsg.read(pdrs);
257 }
258 catch (const SdBusError& e)
259 {
260 log<level::ERR>("pldm: Failed to fetch the OCC state effecter PDRs",
261 entry("ERROR=%s", e.what()));
262 }
263
264 if (!pdrs.size())
265 {
266 log<level::ERR>("pldm: OCC state effecter PDRs not present");
267 return;
268 }
269
270 fetchOCCEffecterInfo(pdrs, occInstanceToEffecter, effecterCount,
271 bootRestartPosition);
272 }
273
274 // Find the matching effecter for the OCC instance
275 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
276 if (effecterEntry == occInstanceToEffecter.end())
277 {
278 log<level::ERR>(
279 "pldm: Failed to find a matching effecter for OCC instance",
280 entry("OCC_INSTANCE_ID=%d", occInstanceId));
281
282 return;
283 }
284
285 uint8_t instanceId{};
286
287 try
288 {
289 auto method = bus.new_method_call(
290 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
291 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
292 method.append(mctpEid);
293 auto reply = bus.call(method);
294 reply.read(instanceId);
295 }
296 catch (const SdBusError& e)
297 {
298 log<level::ERR>("pldm: GetInstanceId returned error",
299 entry("ERROR=%s", e.what()));
300 return;
301 }
302
303 // Prepare the SetStateEffecterStates request to reset the OCC
304 auto request = prepareSetEffecterReq(instanceId, effecterEntry->second,
305 effecterCount, bootRestartPosition);
306
307 if (request.empty())
308 {
309 log<level::ERR>("pldm: SetStateEffecterStates request message empty");
310 return;
311 }
312
313 // Connect to MCTP scoket
314 int fd = pldm_open();
315 if (fd == -1)
316 {
317 log<level::ERR>("pldm: Failed to connect to MCTP socket");
318 return;
319 }
320 open_power::occ::FileDescriptor fileFd(fd);
321
322 // Send the PLDM request message to HBRT
323 uint8_t* response = nullptr;
324 size_t responseSize{};
325 auto rc = pldm_send_recv(mctpEid, fileFd(), request.data(), request.size(),
326 &response, &responseSize);
327 std::unique_ptr<uint8_t, decltype(std::free)*> responsePtr{response,
328 std::free};
329 if (rc)
330 {
331 log<level::ERR>("pldm: pldm_send_recv failed for OCC reset",
332 entry("RC=%d", rc));
333 }
334
335 uint8_t completionCode{};
336 auto responseMsg = reinterpret_cast<const pldm_msg*>(responsePtr.get());
337 auto rcDecode = decode_set_state_effecter_states_resp(
338 responseMsg, responseSize - sizeof(pldm_msg_hdr), &completionCode);
339 if (rcDecode || completionCode)
340 {
341 log<level::ERR>(
342 "pldm: decode_set_state_effecter_states_resp returned error",
343 entry("RC=%d", rcDecode),
344 entry("COMPLETION_CODE=%d", completionCode));
345 }
346
347 return;
348}
349
Chris Caina8857c52021-01-27 11:53:05 -0600350} // namespace pldm