blob: f3cdf9ba0e9522b08346e3a317ee57da6b0ce13b [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
Chris Cain48330572021-06-22 09:09:47 -050076 auto& bus = open_power::occ::utils::getBus();
Tom Joseph815f9f52020-07-27 12:12:13 +053077 try
78 {
79 auto method = bus.new_method_call(
80 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
81 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
82 method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE,
83 (uint16_t)PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS);
84
85 auto responseMsg = bus.call(method);
86 responseMsg.read(pdrs);
87 }
88 catch (const SdBusError& e)
89 {
90 log<level::ERR>("pldm: Failed to fetch the OCC state sensor PDRs",
91 entry("ERROR=%s", e.what()));
92 }
93
94 if (!pdrs.size())
95 {
96 log<level::ERR>("pldm: OCC state sensor PDRs not present");
97 return;
98 }
99
100 fetchOCCSensorInfo(pdrs, sensorToOCCInstance, sensorOffset);
101 }
102
103 TerminusID tid{};
104 SensorID sensorId{};
105 SensorOffset msgSensorOffset{};
106 EventState eventState{};
107 EventState previousEventState{};
108
George Liua17f6e82021-02-23 17:43:51 +0800109 msg.read(tid, sensorId, msgSensorOffset, eventState, previousEventState);
Tom Joseph815f9f52020-07-27 12:12:13 +0530110
111 auto sensorEntry = sensorToOCCInstance.find(sensorId);
112 if (sensorEntry == sensorToOCCInstance.end() ||
113 (msgSensorOffset != sensorOffset))
114 {
115 // No action for non matching sensorEvents
116 return;
117 }
118
Tom Joseph815f9f52020-07-27 12:12:13 +0530119 if (eventState == static_cast<EventState>(
120 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
121 {
Chris Caina8857c52021-01-27 11:53:05 -0600122 log<level::INFO>(
123 fmt::format("PLDM: OCC{} is RUNNING", sensorEntry->second).c_str());
124 callBack(sensorEntry->second, true);
Tom Joseph815f9f52020-07-27 12:12:13 +0530125 }
126 else if (eventState ==
127 static_cast<EventState>(
128 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
129 {
Chris Caina8857c52021-01-27 11:53:05 -0600130 log<level::INFO>(
131 fmt::format("PLDM: OCC{} has now STOPPED", sensorEntry->second)
132 .c_str());
133 callBack(sensorEntry->second, false);
Tom Joseph815f9f52020-07-27 12:12:13 +0530134 }
135
Tom Joseph815f9f52020-07-27 12:12:13 +0530136 return;
137}
138
139void Interface::hostStateEvent(sdbusplus::message::message& msg)
140{
141 std::map<std::string, std::variant<std::string>> properties{};
142 std::string interface;
143 msg.read(interface, properties);
144 const auto stateEntry = properties.find("CurrentHostState");
145 if (stateEntry != properties.end())
146 {
147 auto stateEntryValue = stateEntry->second;
148 auto propVal = std::get<std::string>(stateEntryValue);
149 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
150 {
151 sensorToOCCInstance.clear();
Tom Joseph00325232020-07-29 17:51:48 +0530152 occInstanceToEffecter.clear();
Tom Joseph815f9f52020-07-27 12:12:13 +0530153 }
154 }
155}
156
Tom Joseph00325232020-07-29 17:51:48 +0530157void Interface::fetchOCCEffecterInfo(
158 const PdrList& pdrs, OccInstanceToEffecter& instanceToEffecterMap,
159 CompositeEffecterCount& count, uint8_t& bootRestartPos)
160{
161 bool offsetFound = false;
162 auto pdr =
163 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
164 auto possibleStatesPtr = pdr->possible_states;
165 for (auto offset = 0; offset < pdr->composite_effecter_count; offset++)
166 {
167 auto possibleStates =
168 reinterpret_cast<const state_effecter_possible_states*>(
169 possibleStatesPtr);
170
171 if (possibleStates->state_set_id == PLDM_STATE_SET_BOOT_RESTART_CAUSE)
172 {
173 bootRestartPos = offset;
174 effecterCount = pdr->composite_effecter_count;
175 offsetFound = true;
176 break;
177 }
178 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
179 sizeof(possibleStates->possible_states_size) +
180 possibleStates->possible_states_size;
181 }
182
183 if (!offsetFound)
184 {
185 return;
186 }
187
188 std::map<EntityInstance, EffecterID> entityInstMap{};
189 for (auto& pdr : pdrs)
190 {
191 auto pdrPtr =
192 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
193 entityInstMap.emplace(
194 static_cast<EntityInstance>(pdrPtr->entity_instance),
195 static_cast<SensorID>(pdrPtr->effecter_id));
196 }
197
198 open_power::occ::instanceID position = start;
199 for (auto const& pair : entityInstMap)
200 {
201 occInstanceToEffecter.emplace(position, pair.second);
202 position++;
203 }
204}
205
206std::vector<uint8_t>
207 Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId,
208 CompositeEffecterCount effecterCount,
209 uint8_t bootRestartPos)
210{
211 std::vector<uint8_t> request(
212 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
213 (effecterCount * sizeof(set_effecter_state_field)));
214 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
215 std::vector<set_effecter_state_field> stateField;
216
217 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
218 {
219 if (effecterPos == bootRestartPos)
220 {
221 stateField.emplace_back(set_effecter_state_field{
222 PLDM_REQUEST_SET,
223 PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET});
224 }
225 else
226 {
227 stateField.emplace_back(
228 set_effecter_state_field{PLDM_NO_CHANGE, 0});
229 }
230 }
231 auto rc = encode_set_state_effecter_states_req(
232 instanceId, effecterId, effecterCount, stateField.data(), requestMsg);
233 if (rc != PLDM_SUCCESS)
234 {
235 log<level::ERR>("encode set effecter states request returned error ",
236 entry("RC=%d", rc));
237 request.clear();
238 }
239 return request;
240}
241
242void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
243{
244 if (!isPDREffecterCacheValid())
245 {
246 PdrList pdrs{};
247
Chris Cain48330572021-06-22 09:09:47 -0500248 auto& bus = open_power::occ::utils::getBus();
Tom Joseph00325232020-07-29 17:51:48 +0530249 try
250 {
251 auto method = bus.new_method_call(
252 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
253 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
254 method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE,
255 (uint16_t)PLDM_STATE_SET_BOOT_RESTART_CAUSE);
256
257 auto responseMsg = bus.call(method);
258 responseMsg.read(pdrs);
259 }
260 catch (const SdBusError& e)
261 {
262 log<level::ERR>("pldm: Failed to fetch the OCC state effecter PDRs",
263 entry("ERROR=%s", e.what()));
264 }
265
266 if (!pdrs.size())
267 {
268 log<level::ERR>("pldm: OCC state effecter PDRs not present");
269 return;
270 }
271
272 fetchOCCEffecterInfo(pdrs, occInstanceToEffecter, effecterCount,
273 bootRestartPosition);
274 }
275
276 // Find the matching effecter for the OCC instance
277 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
278 if (effecterEntry == occInstanceToEffecter.end())
279 {
280 log<level::ERR>(
281 "pldm: Failed to find a matching effecter for OCC instance",
282 entry("OCC_INSTANCE_ID=%d", occInstanceId));
283
284 return;
285 }
286
287 uint8_t instanceId{};
288
Chris Cain48330572021-06-22 09:09:47 -0500289 auto& bus = open_power::occ::utils::getBus();
Tom Joseph00325232020-07-29 17:51:48 +0530290 try
291 {
292 auto method = bus.new_method_call(
293 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
294 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
295 method.append(mctpEid);
296 auto reply = bus.call(method);
297 reply.read(instanceId);
298 }
299 catch (const SdBusError& e)
300 {
301 log<level::ERR>("pldm: GetInstanceId returned error",
302 entry("ERROR=%s", e.what()));
303 return;
304 }
305
306 // Prepare the SetStateEffecterStates request to reset the OCC
307 auto request = prepareSetEffecterReq(instanceId, effecterEntry->second,
308 effecterCount, bootRestartPosition);
309
310 if (request.empty())
311 {
312 log<level::ERR>("pldm: SetStateEffecterStates request message empty");
313 return;
314 }
315
316 // Connect to MCTP scoket
317 int fd = pldm_open();
318 if (fd == -1)
319 {
320 log<level::ERR>("pldm: Failed to connect to MCTP socket");
321 return;
322 }
323 open_power::occ::FileDescriptor fileFd(fd);
324
325 // Send the PLDM request message to HBRT
326 uint8_t* response = nullptr;
327 size_t responseSize{};
328 auto rc = pldm_send_recv(mctpEid, fileFd(), request.data(), request.size(),
329 &response, &responseSize);
330 std::unique_ptr<uint8_t, decltype(std::free)*> responsePtr{response,
331 std::free};
332 if (rc)
333 {
334 log<level::ERR>("pldm: pldm_send_recv failed for OCC reset",
335 entry("RC=%d", rc));
336 }
337
338 uint8_t completionCode{};
339 auto responseMsg = reinterpret_cast<const pldm_msg*>(responsePtr.get());
340 auto rcDecode = decode_set_state_effecter_states_resp(
341 responseMsg, responseSize - sizeof(pldm_msg_hdr), &completionCode);
342 if (rcDecode || completionCode)
343 {
344 log<level::ERR>(
345 "pldm: decode_set_state_effecter_states_resp returned error",
346 entry("RC=%d", rcDecode),
347 entry("COMPLETION_CODE=%d", completionCode));
348 }
349
350 return;
351}
352
Chris Caina8857c52021-01-27 11:53:05 -0600353} // namespace pldm