blob: 2da382d0bd93902d79f9d4e34efa0ddb6f6994e3 [file] [log] [blame]
Ben Tynerbb90afc2022-12-14 20:50:33 -06001#include <libpldm/platform.h>
2#include <libpldm/pldm.h>
3#include <libpldm/state_set_oem_ibm.h>
4
5#include <util/dbus.hpp>
6#include <util/trace.hpp>
7
8namespace util
9{
10namespace pldm
11{
12/** @brief Send PLDM request
13 *
14 * @param[in] request - the request data
15 * @param[in] mcptEid - the mctp endpoint ID
16 * @param[out] pldmFd - pldm socket file descriptor
17 *
18 * @pre a mctp instance must have been
19 * @return true if send is successful false otherwise
20 */
21bool sendPldm(const std::vector<uint8_t>& request, uint8_t mctpEid, int& pldmFd)
22{
23 // connect to socket
24 pldmFd = pldm_open();
25 if (-1 == pldmFd)
26 {
27 trace::err("failed to connect to pldm");
28 return false;
29 }
30
31 // send PLDM request
32 auto pldmRc = pldm_send(mctpEid, pldmFd, request.data(), request.size());
33
34 trace::inf("sent pldm request");
35
36 return pldmRc == PLDM_REQUESTER_SUCCESS ? true : false;
37}
38
39/** @brief Prepare a request for SetStateEffecterStates
40 *
41 * @param[in] effecterId - the effecter ID
42 * @param[in] effecterCount - composite effecter count
43 * @param[in] stateIdPos - position of the state set
44 * @param[in] stateSetValue - the value to set the state
45 * @param[in] mcptEid - the MCTP endpoint ID
46 *
47 * @return PLDM request message to be sent to host, empty message on error
48 */
49std::vector<uint8_t> prepareSetEffecterReq(uint16_t effecterId,
50 uint8_t effecterCount,
51 uint8_t stateIdPos,
52 uint8_t stateSetValue,
53 uint8_t mctpEid)
54{
55 // get mctp instance associated with the endpoint ID
56 uint8_t mctpInstance;
57 if (!util::dbus::getMctpInstance(mctpInstance, mctpEid))
58 {
59 return std::vector<uint8_t>();
60 }
61
62 // form the request message
63 std::vector<uint8_t> request(
64 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
65 (effecterCount * sizeof(set_effecter_state_field)));
66
67 // encode the state data with the change we want to elicit
68 std::vector<set_effecter_state_field> stateField;
69 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
70 {
71 if (effecterPos == stateIdPos)
72 {
73 stateField.emplace_back(
74 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
75 }
76 else
77 {
78 stateField.emplace_back(
79 set_effecter_state_field{PLDM_NO_CHANGE, 0});
80 }
81 }
82
83 // encode the message with state data
84 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
Patrick Williams27dd6362023-05-10 07:51:20 -050085 auto rc = encode_set_state_effecter_states_req(
Ben Tynerbb90afc2022-12-14 20:50:33 -060086 mctpInstance, effecterId, effecterCount, stateField.data(), requestMsg);
87
88 if (rc != PLDM_SUCCESS)
89 {
90 trace::err("encode set effecter states request failed");
91 request.clear();
92 }
93
94 return request;
95}
96
97/** @brief Return map of sensor ID to SBE instance
98 *
99 * @param[in] stateSetId - the state set ID of interest
100 * @param[out] sensorInstanceMap - map of sensor to SBE instance
101 * @param[out] sensorOffset - position of sensor with state set ID within map
102 *
103 * @return true if sensor info is available false otherwise
104 */
105bool fetchSensorInfo(uint16_t stateSetId,
106 std::map<uint16_t, unsigned int>& sensorInstanceMap,
107 uint8_t& sensorOffset)
108{
109 // get state sensor PDRs
110 std::vector<std::vector<uint8_t>> pdrs{};
111 if (!util::dbus::getStateSensorPdrs(pdrs, stateSetId))
112 {
113 return false;
114 }
115
116 // check for any PDRs available
117 if (!pdrs.size())
118 {
119 trace::err("state sensor PDRs not present");
120 return false;
121 }
122
123 // find the offset of specified sensor withing PDRs
124 bool offsetFound = false;
125 auto stateSensorPDR =
126 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
127 auto possibleStatesPtr = stateSensorPDR->possible_states;
128
129 for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count;
130 offset++)
131 {
132 auto possibleStates =
133 reinterpret_cast<const state_sensor_possible_states*>(
134 possibleStatesPtr);
135
136 if (possibleStates->state_set_id == stateSetId)
137 {
138 sensorOffset = offset;
Patrick Williams27dd6362023-05-10 07:51:20 -0500139 offsetFound = true;
Ben Tynerbb90afc2022-12-14 20:50:33 -0600140 break;
141 }
142 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
143 sizeof(possibleStates->possible_states_size) +
144 possibleStates->possible_states_size;
145 }
146
147 if (!offsetFound)
148 {
149 trace::err("state sensor not found");
150 return false;
151 }
152
153 // map sensor ID to equivelent 16 bit value
154 std::map<uint32_t, uint16_t> entityInstMap{};
155 for (auto& pdr : pdrs)
156 {
157 auto pdrPtr =
158 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
159 uint32_t key = pdrPtr->sensor_id;
160 entityInstMap.emplace(key, static_cast<uint16_t>(pdrPtr->sensor_id));
161 }
162
163 // map sensor ID to zero based SBE instance
164 unsigned int position = 0;
Patrick Williams27dd6362023-05-10 07:51:20 -0500165 for (const auto& pair : entityInstMap)
Ben Tynerbb90afc2022-12-14 20:50:33 -0600166 {
167 sensorInstanceMap.emplace(pair.second, position);
168 position++;
169 }
170
171 return true;
172}
173
174/** @brief Return map of SBE instance to effecter ID
175 *
176 * @param[in] stateSetId - the state set ID of interest
177 * @param[out] instanceToEffecterMap - map of sbe instance to effecter ID
178 * @param[out] effecterCount - composite effecter count
179 * @param[out] stateIdPos - position of effecter with state set ID within map
180 *
181 * @return true if effector info is available false otherwise
182 */
183bool fetchEffecterInfo(uint16_t stateSetId,
184 std::map<unsigned int, uint16_t>& instanceToEffecterMap,
185 uint8_t& effecterCount, uint8_t& stateIdPos)
186{
187 // get state effecter PDRs
188 std::vector<std::vector<uint8_t>> pdrs{};
189 if (!util::dbus::getStateEffecterPdrs(pdrs, stateSetId))
190 {
191 return false;
192 }
193
194 // check for any PDRs available
195 if (!pdrs.size())
196 {
197 trace::err("state effecter PDRs not present");
198 return false;
199 }
200
201 // find the offset of specified effector within PDRs
202 bool offsetFound = false;
203 auto stateEffecterPDR =
204 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
205 auto possibleStatesPtr = stateEffecterPDR->possible_states;
206
207 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
208 offset++)
209 {
210 auto possibleStates =
211 reinterpret_cast<const state_effecter_possible_states*>(
212 possibleStatesPtr);
213
214 if (possibleStates->state_set_id == stateSetId)
215 {
Patrick Williams27dd6362023-05-10 07:51:20 -0500216 stateIdPos = offset;
Ben Tynerbb90afc2022-12-14 20:50:33 -0600217 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams27dd6362023-05-10 07:51:20 -0500218 offsetFound = true;
Ben Tynerbb90afc2022-12-14 20:50:33 -0600219 break;
220 }
221 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
222 sizeof(possibleStates->possible_states_size) +
223 possibleStates->possible_states_size;
224 }
225
226 if (!offsetFound)
227 {
228 trace::err("state set effecter not found");
229 return false;
230 }
231
232 // map effecter ID to equivelent 16 bit value
233 std::map<uint32_t, uint16_t> entityInstMap{};
234 for (auto& pdr : pdrs)
235 {
236 auto pdrPtr =
237 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
238 uint32_t key = pdrPtr->effecter_id;
239 entityInstMap.emplace(key, static_cast<uint16_t>(pdrPtr->effecter_id));
240 }
241
242 // map zero based SBE instance to effecter ID
243 unsigned int position = 0;
Patrick Williams27dd6362023-05-10 07:51:20 -0500244 for (const auto& pair : entityInstMap)
Ben Tynerbb90afc2022-12-14 20:50:33 -0600245 {
246 instanceToEffecterMap.emplace(position, pair.second);
247 position++;
248 }
249
250 return true;
251}
252
253/** @brief Reset SBE using HBRT PLDM interface */
254bool hresetSbe(unsigned int sbeInstance)
255{
256 trace::inf("requesting sbe hreset");
257
258 // get effecter info
259 std::map<unsigned int, uint16_t> sbeInstanceToEffecter;
Patrick Williams27dd6362023-05-10 07:51:20 -0500260 uint8_t SBEEffecterCount = 0;
Ben Tynerbb90afc2022-12-14 20:50:33 -0600261 uint8_t sbeMaintenanceStatePosition = 0;
262
263 if (!fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
264 sbeInstanceToEffecter, SBEEffecterCount,
265 sbeMaintenanceStatePosition))
266 {
267 return false;
268 }
269
270 // find the state effecter ID for the given SBE instance
271 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstance);
272 if (effecterEntry == sbeInstanceToEffecter.end())
273 {
274 trace::err("failed to find effecter for SBE");
275 return false;
276 }
277
278 // create request to HRESET the SBE
279 constexpr uint8_t hbrtMctpEid = 10; // HBRT MCTP EID
280
281 auto request = prepareSetEffecterReq(
282 effecterEntry->second, SBEEffecterCount, sbeMaintenanceStatePosition,
283 SBE_RETRY_REQUIRED, hbrtMctpEid);
284
285 if (request.empty())
286 {
287 trace::err("HRESET effecter request empty");
288 return false;
289 }
290
291 // get sensor info for validating sensor change
292 std::map<uint16_t, unsigned int> sensorToSbeInstance;
293 uint8_t sbeSensorOffset = 0;
294 if (!fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSbeInstance,
295 sbeSensorOffset))
296 {
297 return false;
298 }
299
300 // register signal change listener
301 std::string hresetStatus = "requested";
302 constexpr auto interface = "xyz.openbmc_project.PLDM.Event";
Patrick Williams27dd6362023-05-10 07:51:20 -0500303 constexpr auto path = "/xyz/openbmc_project/pldm";
304 constexpr auto member = "StateSensorEvent";
Ben Tynerbb90afc2022-12-14 20:50:33 -0600305
306 auto bus = sdbusplus::bus::new_default();
307 std::unique_ptr<sdbusplus::bus::match_t> match =
308 std::make_unique<sdbusplus::bus::match_t>(
309 bus,
310 sdbusplus::bus::match::rules::type::signal() +
311 sdbusplus::bus::match::rules::member(member) +
312 sdbusplus::bus::match::rules::path(path) +
313 sdbusplus::bus::match::rules::interface(interface),
314 [&](auto& msg) {
Patrick Williams27dd6362023-05-10 07:51:20 -0500315 uint8_t sensorTid{};
316 uint16_t sensorId{};
317 uint8_t msgSensorOffset{};
318 uint8_t eventState{};
319 uint8_t previousEventState{};
Ben Tynerbb90afc2022-12-14 20:50:33 -0600320
Patrick Williams27dd6362023-05-10 07:51:20 -0500321 // get sensor event details
322 msg.read(sensorTid, sensorId, msgSensorOffset, eventState,
323 previousEventState);
Ben Tynerbb90afc2022-12-14 20:50:33 -0600324
Patrick Williams27dd6362023-05-10 07:51:20 -0500325 // does sensor offset match?
326 if (sbeSensorOffset == msgSensorOffset)
327 {
328 // does sensor ID match?
329 auto sensorEntry = sensorToSbeInstance.find(sensorId);
330 if (sensorEntry != sensorToSbeInstance.end())
331 {
332 const uint8_t instance = sensorEntry->second;
333
334 // if instances matche check status
335 if (instance == sbeInstance)
Ben Tynerbb90afc2022-12-14 20:50:33 -0600336 {
Patrick Williams27dd6362023-05-10 07:51:20 -0500337 if (eventState == static_cast<uint8_t>(SBE_HRESET_READY))
Ben Tynerbb90afc2022-12-14 20:50:33 -0600338 {
Patrick Williams27dd6362023-05-10 07:51:20 -0500339 hresetStatus = "success";
340 }
341 else if (eventState ==
342 static_cast<uint8_t>(SBE_HRESET_FAILED))
343 {
344 hresetStatus = "fail";
Ben Tynerbb90afc2022-12-14 20:50:33 -0600345 }
346 }
Patrick Williams27dd6362023-05-10 07:51:20 -0500347 }
348 }
Ben Tynerbb90afc2022-12-14 20:50:33 -0600349 });
350
351 // send request to issue hreset of sbe
352 int pldmFd = -1; // mctp socket file descriptor
353 if (!sendPldm(request, hbrtMctpEid, pldmFd))
354 {
355 trace::err("send pldm request failed");
356 if (-1 != pldmFd)
357 {
358 close(pldmFd);
359 }
360 return false;
361 }
362
363 // keep track of elapsed time
364 uint64_t timeRemaining = 60000000; // microseconds, 1 minute
365 std::chrono::steady_clock::time_point begin =
366 std::chrono::steady_clock::now();
367
368 // wait for status update or timeout
369 trace::inf("waiting on sbe hreset");
370 while ("requested" == hresetStatus && 0 != timeRemaining)
371 {
372 bus.wait(timeRemaining);
373 uint64_t timeElapsed =
374 std::chrono::duration_cast<std::chrono::microseconds>(
375 std::chrono::steady_clock::now() - begin)
376 .count();
377
378 timeRemaining =
379 timeElapsed > timeRemaining ? 0 : timeRemaining - timeElapsed;
380
381 bus.process_discard();
382 }
383
384 if (0 == timeRemaining)
385 {
386 trace::err("hreset timed out");
387 }
388
389 close(pldmFd); // close pldm socket
390
391 return hresetStatus == "success" ? true : false;
392}
393
394} // namespace pldm
395} // namespace util