blob: e45e5447067085d4c373f7261bac66d1daea17d0 [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
Tom Joseph815f9f52020-07-27 12:12:13 +05305#include <libpldm/entity.h>
6#include <libpldm/platform.h>
7#include <libpldm/state_set.h>
8
9#include <phosphor-logging/log.hpp>
10
11namespace pldm
12{
13
14using sdbusplus::exception::SdBusError;
15using namespace phosphor::logging;
16
17void Interface::fetchOCCSensorInfo(const PdrList& pdrs,
18 SensorToOCCInstance& sensorInstanceMap,
19 SensorOffset& sensorOffset)
20{
21 bool offsetFound = false;
22 auto pdr =
23 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
24 auto possibleStatesPtr = pdr->possible_states;
25 for (auto offset = 0; offset < pdr->composite_sensor_count; offset++)
26 {
27 auto possibleStates =
28 reinterpret_cast<const state_sensor_possible_states*>(
29 possibleStatesPtr);
30
31 if (possibleStates->state_set_id ==
32 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS)
33 {
34 sensorOffset = offset;
35 offsetFound = true;
36 break;
37 }
38 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
39 sizeof(possibleStates->possible_states_size) +
40 possibleStates->possible_states_size;
41 }
42
43 if (!offsetFound)
44 {
45 log<level::ERR>("pldm: OCC state sensor PDR with StateSetId "
46 "PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS not found");
47 return;
48 }
49
50 // To order SensorID based on the EntityInstance
51 std::map<EntityInstance, SensorID> entityInstMap{};
52 for (auto& pdr : pdrs)
53 {
54 auto pdrPtr =
55 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
56 entityInstMap.emplace(
57 static_cast<EntityInstance>(pdrPtr->entity_instance),
58 static_cast<SensorID>(pdrPtr->sensor_id));
59 }
60
61 open_power::occ::instanceID count = start;
62 for (auto const& pair : entityInstMap)
63 {
64 sensorInstanceMap.emplace(pair.second, count);
65 count++;
66 }
67}
68
69void Interface::sensorEvent(sdbusplus::message::message& msg)
70{
71 if (!isOCCSensorCacheValid())
72 {
73 PdrList pdrs{};
74
75 try
76 {
77 auto method = bus.new_method_call(
78 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
79 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
80 method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE,
81 (uint16_t)PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS);
82
83 auto responseMsg = bus.call(method);
84 responseMsg.read(pdrs);
85 }
86 catch (const SdBusError& e)
87 {
88 log<level::ERR>("pldm: Failed to fetch the OCC state sensor PDRs",
89 entry("ERROR=%s", e.what()));
90 }
91
92 if (!pdrs.size())
93 {
94 log<level::ERR>("pldm: OCC state sensor PDRs not present");
95 return;
96 }
97
98 fetchOCCSensorInfo(pdrs, sensorToOCCInstance, sensorOffset);
99 }
100
101 TerminusID tid{};
102 SensorID sensorId{};
103 SensorOffset msgSensorOffset{};
104 EventState eventState{};
105 EventState previousEventState{};
106
George Liua17f6e82021-02-23 17:43:51 +0800107 msg.read(tid, sensorId, msgSensorOffset, eventState, previousEventState);
Tom Joseph815f9f52020-07-27 12:12:13 +0530108
109 auto sensorEntry = sensorToOCCInstance.find(sensorId);
110 if (sensorEntry == sensorToOCCInstance.end() ||
111 (msgSensorOffset != sensorOffset))
112 {
113 // No action for non matching sensorEvents
114 return;
115 }
116
117 bool newState{};
118 if (eventState == static_cast<EventState>(
119 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
120 {
121 newState = callBack(sensorEntry->second, true);
122 }
123 else if (eventState ==
124 static_cast<EventState>(
125 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
126 {
127 newState = callBack(sensorEntry->second, false);
128 }
129 else
130 {
131 return;
132 }
133
134 log<level::INFO>("pldm: Updated OCCActive state",
135 entry("STATE=%s", newState ? "true" : "false"));
136 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
248 try
249 {
250 auto method = bus.new_method_call(
251 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
252 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
253 method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE,
254 (uint16_t)PLDM_STATE_SET_BOOT_RESTART_CAUSE);
255
256 auto responseMsg = bus.call(method);
257 responseMsg.read(pdrs);
258 }
259 catch (const SdBusError& e)
260 {
261 log<level::ERR>("pldm: Failed to fetch the OCC state effecter PDRs",
262 entry("ERROR=%s", e.what()));
263 }
264
265 if (!pdrs.size())
266 {
267 log<level::ERR>("pldm: OCC state effecter PDRs not present");
268 return;
269 }
270
271 fetchOCCEffecterInfo(pdrs, occInstanceToEffecter, effecterCount,
272 bootRestartPosition);
273 }
274
275 // Find the matching effecter for the OCC instance
276 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
277 if (effecterEntry == occInstanceToEffecter.end())
278 {
279 log<level::ERR>(
280 "pldm: Failed to find a matching effecter for OCC instance",
281 entry("OCC_INSTANCE_ID=%d", occInstanceId));
282
283 return;
284 }
285
286 uint8_t instanceId{};
287
288 try
289 {
290 auto method = bus.new_method_call(
291 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
292 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
293 method.append(mctpEid);
294 auto reply = bus.call(method);
295 reply.read(instanceId);
296 }
297 catch (const SdBusError& e)
298 {
299 log<level::ERR>("pldm: GetInstanceId returned error",
300 entry("ERROR=%s", e.what()));
301 return;
302 }
303
304 // Prepare the SetStateEffecterStates request to reset the OCC
305 auto request = prepareSetEffecterReq(instanceId, effecterEntry->second,
306 effecterCount, bootRestartPosition);
307
308 if (request.empty())
309 {
310 log<level::ERR>("pldm: SetStateEffecterStates request message empty");
311 return;
312 }
313
314 // Connect to MCTP scoket
315 int fd = pldm_open();
316 if (fd == -1)
317 {
318 log<level::ERR>("pldm: Failed to connect to MCTP socket");
319 return;
320 }
321 open_power::occ::FileDescriptor fileFd(fd);
322
323 // Send the PLDM request message to HBRT
324 uint8_t* response = nullptr;
325 size_t responseSize{};
326 auto rc = pldm_send_recv(mctpEid, fileFd(), request.data(), request.size(),
327 &response, &responseSize);
328 std::unique_ptr<uint8_t, decltype(std::free)*> responsePtr{response,
329 std::free};
330 if (rc)
331 {
332 log<level::ERR>("pldm: pldm_send_recv failed for OCC reset",
333 entry("RC=%d", rc));
334 }
335
336 uint8_t completionCode{};
337 auto responseMsg = reinterpret_cast<const pldm_msg*>(responsePtr.get());
338 auto rcDecode = decode_set_state_effecter_states_resp(
339 responseMsg, responseSize - sizeof(pldm_msg_hdr), &completionCode);
340 if (rcDecode || completionCode)
341 {
342 log<level::ERR>(
343 "pldm: decode_set_state_effecter_states_resp returned error",
344 entry("RC=%d", rcDecode),
345 entry("COMPLETION_CODE=%d", completionCode));
346 }
347
348 return;
349}
350
Tom Joseph815f9f52020-07-27 12:12:13 +0530351} // namespace pldm