blob: 2552183ecb049264820e22b77f37f4406cc66823 [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
12namespace pldm
13{
14
Patrick Williams05e95592021-09-02 09:28:14 -050015using 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 // Note that when a proc is on a DCM, the PDRs for these sensors
52 // could have the same instance IDs but different container IDs.
53 std::map<uint32_t, SensorID> entityInstMap{};
54 for (auto& pdr : pdrs)
55 {
56 auto pdrPtr =
57 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
58 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
59 static_cast<uint32_t>(pdrPtr->entity_instance);
60 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->sensor_id));
61 }
62
63 open_power::occ::instanceID count = start;
64 for (auto const& pair : entityInstMap)
65 {
66 sensorInstanceMap.emplace(pair.second, count);
67 count++;
68 }
69}
70
71void Interface::sensorEvent(sdbusplus::message::message& msg)
72{
73 if (!isOCCSensorCacheValid())
74 {
75 PdrList pdrs{};
76
77 auto& bus = open_power::occ::utils::getBus();
78 try
79 {
80 auto method = bus.new_method_call(
81 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
82 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
83 method.append(tid, (uint16_t)PLDM_ENTITY_PROC,
84 (uint16_t)PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS);
85
86 auto responseMsg = bus.call(method);
87 responseMsg.read(pdrs);
88 }
Patrick Williams25613622021-09-02 09:29:54 -050089 catch (const sdbusplus::exception::exception& e)
Patrick Williams05e95592021-09-02 09:28:14 -050090 {
91 log<level::ERR>("pldm: Failed to fetch the OCC state sensor PDRs",
92 entry("ERROR=%s", e.what()));
93 }
94
95 if (!pdrs.size())
96 {
97 log<level::ERR>("pldm: OCC state sensor PDRs not present");
98 return;
99 }
100
101 fetchOCCSensorInfo(pdrs, sensorToOCCInstance, sensorOffset);
102 }
103
104 TerminusID tid{};
105 SensorID sensorId{};
106 SensorOffset msgSensorOffset{};
107 EventState eventState{};
108 EventState previousEventState{};
109
110 msg.read(tid, sensorId, msgSensorOffset, eventState, previousEventState);
111
112 auto sensorEntry = sensorToOCCInstance.find(sensorId);
113 if (sensorEntry == sensorToOCCInstance.end() ||
114 (msgSensorOffset != sensorOffset))
115 {
116 // No action for non matching sensorEvents
117 return;
118 }
119
120 if (eventState == static_cast<EventState>(
121 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
122 {
123 log<level::INFO>(
124 fmt::format("PLDM: OCC{} is RUNNING", sensorEntry->second).c_str());
125 callBack(sensorEntry->second, true);
126 }
127 else if (eventState ==
128 static_cast<EventState>(
129 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
130 {
131 log<level::INFO>(
132 fmt::format("PLDM: OCC{} has now STOPPED", sensorEntry->second)
133 .c_str());
134 callBack(sensorEntry->second, false);
135 }
136
137 return;
138}
139
140void Interface::hostStateEvent(sdbusplus::message::message& msg)
141{
142 std::map<std::string, std::variant<std::string>> properties{};
143 std::string interface;
144 msg.read(interface, properties);
145 const auto stateEntry = properties.find("CurrentHostState");
146 if (stateEntry != properties.end())
147 {
148 auto stateEntryValue = stateEntry->second;
149 auto propVal = std::get<std::string>(stateEntryValue);
150 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
151 {
152 sensorToOCCInstance.clear();
153 occInstanceToEffecter.clear();
154 }
155 }
156}
157
158void Interface::fetchOCCEffecterInfo(
159 const PdrList& pdrs, OccInstanceToEffecter& instanceToEffecterMap,
160 CompositeEffecterCount& count, uint8_t& bootRestartPos)
161{
162 bool offsetFound = false;
163 auto pdr =
164 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
165 auto possibleStatesPtr = pdr->possible_states;
166 for (auto offset = 0; offset < pdr->composite_effecter_count; offset++)
167 {
168 auto possibleStates =
169 reinterpret_cast<const state_effecter_possible_states*>(
170 possibleStatesPtr);
171
172 if (possibleStates->state_set_id == PLDM_STATE_SET_BOOT_RESTART_CAUSE)
173 {
174 bootRestartPos = offset;
175 effecterCount = pdr->composite_effecter_count;
176 offsetFound = true;
177 break;
178 }
179 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
180 sizeof(possibleStates->possible_states_size) +
181 possibleStates->possible_states_size;
182 }
183
184 if (!offsetFound)
185 {
186 return;
187 }
188
189 std::map<EntityInstance, EffecterID> entityInstMap{};
190 for (auto& pdr : pdrs)
191 {
192 auto pdrPtr =
193 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
194 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
195 static_cast<uint32_t>(pdrPtr->entity_instance);
196 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
197 }
198
199 open_power::occ::instanceID position = start;
200 for (auto const& pair : entityInstMap)
201 {
202 occInstanceToEffecter.emplace(position, pair.second);
203 position++;
204 }
205}
206
207std::vector<uint8_t>
208 Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId,
209 CompositeEffecterCount effecterCount,
210 uint8_t bootRestartPos)
211{
212 std::vector<uint8_t> request(
213 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
214 (effecterCount * sizeof(set_effecter_state_field)));
215 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
216 std::vector<set_effecter_state_field> stateField;
217
218 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
219 {
220 if (effecterPos == bootRestartPos)
221 {
222 stateField.emplace_back(set_effecter_state_field{
223 PLDM_REQUEST_SET,
224 PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET});
225 }
226 else
227 {
228 stateField.emplace_back(
229 set_effecter_state_field{PLDM_NO_CHANGE, 0});
230 }
231 }
232 auto rc = encode_set_state_effecter_states_req(
233 instanceId, effecterId, effecterCount, stateField.data(), requestMsg);
234 if (rc != PLDM_SUCCESS)
235 {
236 log<level::ERR>("encode set effecter states request returned error ",
237 entry("RC=%d", rc));
238 request.clear();
239 }
240 return request;
241}
242
243void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
244{
245 if (!isPDREffecterCacheValid())
246 {
247 PdrList pdrs{};
248
249 auto& bus = open_power::occ::utils::getBus();
250 try
251 {
252 auto method = bus.new_method_call(
253 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
254 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
255 method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE,
256 (uint16_t)PLDM_STATE_SET_BOOT_RESTART_CAUSE);
257
258 auto responseMsg = bus.call(method);
259 responseMsg.read(pdrs);
260 }
Patrick Williams25613622021-09-02 09:29:54 -0500261 catch (const sdbusplus::exception::exception& e)
Patrick Williams05e95592021-09-02 09:28:14 -0500262 {
263 log<level::ERR>("pldm: Failed to fetch the OCC state effecter PDRs",
264 entry("ERROR=%s", e.what()));
265 }
266
267 if (!pdrs.size())
268 {
269 log<level::ERR>("pldm: OCC state effecter PDRs not present");
270 return;
271 }
272
273 fetchOCCEffecterInfo(pdrs, occInstanceToEffecter, effecterCount,
274 bootRestartPosition);
275 }
276
277 // Find the matching effecter for the OCC instance
278 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
279 if (effecterEntry == occInstanceToEffecter.end())
280 {
281 log<level::ERR>(
282 "pldm: Failed to find a matching effecter for OCC instance",
283 entry("OCC_INSTANCE_ID=%d", occInstanceId));
284
285 return;
286 }
287
288 uint8_t instanceId{};
289
290 auto& bus = open_power::occ::utils::getBus();
291 try
292 {
293 auto method = bus.new_method_call(
294 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
295 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
296 method.append(mctpEid);
297 auto reply = bus.call(method);
298 reply.read(instanceId);
299 }
Patrick Williams25613622021-09-02 09:29:54 -0500300 catch (const sdbusplus::exception::exception& e)
Patrick Williams05e95592021-09-02 09:28:14 -0500301 {
302 log<level::ERR>("pldm: GetInstanceId returned error",
303 entry("ERROR=%s", e.what()));
304 return;
305 }
306
307 // Prepare the SetStateEffecterStates request to reset the OCC
308 auto request = prepareSetEffecterReq(instanceId, effecterEntry->second,
309 effecterCount, bootRestartPosition);
310
311 if (request.empty())
312 {
313 log<level::ERR>("pldm: SetStateEffecterStates request message empty");
314 return;
315 }
316
317 // Connect to MCTP scoket
318 int fd = pldm_open();
319 if (fd == -1)
320 {
321 log<level::ERR>("pldm: Failed to connect to MCTP socket");
322 return;
323 }
324 open_power::occ::FileDescriptor fileFd(fd);
325
326 // Send the PLDM request message to HBRT
327 uint8_t* response = nullptr;
328 size_t responseSize{};
329 auto rc = pldm_send_recv(mctpEid, fileFd(), request.data(), request.size(),
330 &response, &responseSize);
331 std::unique_ptr<uint8_t, decltype(std::free)*> responsePtr{response,
332 std::free};
333 if (rc)
334 {
335 log<level::ERR>("pldm: pldm_send_recv failed for OCC reset",
336 entry("RC=%d", rc));
337 }
338
339 uint8_t completionCode{};
340 auto responseMsg = reinterpret_cast<const pldm_msg*>(responsePtr.get());
341 auto rcDecode = decode_set_state_effecter_states_resp(
342 responseMsg, responseSize - sizeof(pldm_msg_hdr), &completionCode);
343 if (rcDecode || completionCode)
344 {
345 log<level::ERR>(
346 "pldm: decode_set_state_effecter_states_resp returned error",
347 entry("RC=%d", rcDecode),
348 entry("COMPLETION_CODE=%d", completionCode));
349 }
350
351 return;
352}
353
354} // namespace pldm