blob: bbf2ce706390321a1e3483603c37385c66c8b3dc [file] [log] [blame]
Andrew Jefferya0010202024-06-27 10:49:11 +00001#include <libpldm/oem/ibm/state_set.h>
Ben Tynerbb90afc2022-12-14 20:50:33 -06002#include <libpldm/platform.h>
3#include <libpldm/pldm.h>
Ben Tynerbb90afc2022-12-14 20:50:33 -06004
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 */
Patrick Williamsa0c724d2024-08-16 15:21:54 -040049std::vector<uint8_t> prepareSetEffecterReq(
50 uint16_t effecterId, uint8_t effecterCount, uint8_t stateIdPos,
51 uint8_t stateSetValue, uint8_t mctpEid)
Ben Tynerbb90afc2022-12-14 20:50:33 -060052{
53 // get mctp instance associated with the endpoint ID
54 uint8_t mctpInstance;
55 if (!util::dbus::getMctpInstance(mctpInstance, mctpEid))
56 {
57 return std::vector<uint8_t>();
58 }
59
60 // form the request message
61 std::vector<uint8_t> request(
62 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
63 (effecterCount * sizeof(set_effecter_state_field)));
64
65 // encode the state data with the change we want to elicit
66 std::vector<set_effecter_state_field> stateField;
67 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
68 {
69 if (effecterPos == stateIdPos)
70 {
71 stateField.emplace_back(
72 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
73 }
74 else
75 {
76 stateField.emplace_back(
77 set_effecter_state_field{PLDM_NO_CHANGE, 0});
78 }
79 }
80
81 // encode the message with state data
82 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
Patrick Williams27dd6362023-05-10 07:51:20 -050083 auto rc = encode_set_state_effecter_states_req(
Ben Tynerbb90afc2022-12-14 20:50:33 -060084 mctpInstance, effecterId, effecterCount, stateField.data(), requestMsg);
85
86 if (rc != PLDM_SUCCESS)
87 {
88 trace::err("encode set effecter states request failed");
89 request.clear();
90 }
91
92 return request;
93}
94
95/** @brief Return map of sensor ID to SBE instance
96 *
97 * @param[in] stateSetId - the state set ID of interest
98 * @param[out] sensorInstanceMap - map of sensor to SBE instance
99 * @param[out] sensorOffset - position of sensor with state set ID within map
100 *
101 * @return true if sensor info is available false otherwise
102 */
103bool fetchSensorInfo(uint16_t stateSetId,
104 std::map<uint16_t, unsigned int>& sensorInstanceMap,
105 uint8_t& sensorOffset)
106{
107 // get state sensor PDRs
108 std::vector<std::vector<uint8_t>> pdrs{};
109 if (!util::dbus::getStateSensorPdrs(pdrs, stateSetId))
110 {
111 return false;
112 }
113
114 // check for any PDRs available
115 if (!pdrs.size())
116 {
117 trace::err("state sensor PDRs not present");
118 return false;
119 }
120
121 // find the offset of specified sensor withing PDRs
122 bool offsetFound = false;
123 auto stateSensorPDR =
124 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
125 auto possibleStatesPtr = stateSensorPDR->possible_states;
126
127 for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count;
128 offset++)
129 {
130 auto possibleStates =
131 reinterpret_cast<const state_sensor_possible_states*>(
132 possibleStatesPtr);
133
134 if (possibleStates->state_set_id == stateSetId)
135 {
136 sensorOffset = offset;
Patrick Williams27dd6362023-05-10 07:51:20 -0500137 offsetFound = true;
Ben Tynerbb90afc2022-12-14 20:50:33 -0600138 break;
139 }
140 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
141 sizeof(possibleStates->possible_states_size) +
142 possibleStates->possible_states_size;
143 }
144
145 if (!offsetFound)
146 {
147 trace::err("state sensor not found");
148 return false;
149 }
150
151 // map sensor ID to equivelent 16 bit value
152 std::map<uint32_t, uint16_t> entityInstMap{};
153 for (auto& pdr : pdrs)
154 {
155 auto pdrPtr =
156 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
157 uint32_t key = pdrPtr->sensor_id;
158 entityInstMap.emplace(key, static_cast<uint16_t>(pdrPtr->sensor_id));
159 }
160
161 // map sensor ID to zero based SBE instance
162 unsigned int position = 0;
Patrick Williams27dd6362023-05-10 07:51:20 -0500163 for (const auto& pair : entityInstMap)
Ben Tynerbb90afc2022-12-14 20:50:33 -0600164 {
165 sensorInstanceMap.emplace(pair.second, position);
166 position++;
167 }
168
169 return true;
170}
171
172/** @brief Return map of SBE instance to effecter ID
173 *
174 * @param[in] stateSetId - the state set ID of interest
175 * @param[out] instanceToEffecterMap - map of sbe instance to effecter ID
176 * @param[out] effecterCount - composite effecter count
177 * @param[out] stateIdPos - position of effecter with state set ID within map
178 *
179 * @return true if effector info is available false otherwise
180 */
181bool fetchEffecterInfo(uint16_t stateSetId,
182 std::map<unsigned int, uint16_t>& instanceToEffecterMap,
183 uint8_t& effecterCount, uint8_t& stateIdPos)
184{
185 // get state effecter PDRs
186 std::vector<std::vector<uint8_t>> pdrs{};
187 if (!util::dbus::getStateEffecterPdrs(pdrs, stateSetId))
188 {
189 return false;
190 }
191
192 // check for any PDRs available
193 if (!pdrs.size())
194 {
195 trace::err("state effecter PDRs not present");
196 return false;
197 }
198
199 // find the offset of specified effector within PDRs
200 bool offsetFound = false;
201 auto stateEffecterPDR =
202 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
203 auto possibleStatesPtr = stateEffecterPDR->possible_states;
204
205 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
206 offset++)
207 {
208 auto possibleStates =
209 reinterpret_cast<const state_effecter_possible_states*>(
210 possibleStatesPtr);
211
212 if (possibleStates->state_set_id == stateSetId)
213 {
Patrick Williams27dd6362023-05-10 07:51:20 -0500214 stateIdPos = offset;
Ben Tynerbb90afc2022-12-14 20:50:33 -0600215 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams27dd6362023-05-10 07:51:20 -0500216 offsetFound = true;
Ben Tynerbb90afc2022-12-14 20:50:33 -0600217 break;
218 }
219 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
220 sizeof(possibleStates->possible_states_size) +
221 possibleStates->possible_states_size;
222 }
223
224 if (!offsetFound)
225 {
226 trace::err("state set effecter not found");
227 return false;
228 }
229
230 // map effecter ID to equivelent 16 bit value
231 std::map<uint32_t, uint16_t> entityInstMap{};
232 for (auto& pdr : pdrs)
233 {
234 auto pdrPtr =
235 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
236 uint32_t key = pdrPtr->effecter_id;
237 entityInstMap.emplace(key, static_cast<uint16_t>(pdrPtr->effecter_id));
238 }
239
240 // map zero based SBE instance to effecter ID
241 unsigned int position = 0;
Patrick Williams27dd6362023-05-10 07:51:20 -0500242 for (const auto& pair : entityInstMap)
Ben Tynerbb90afc2022-12-14 20:50:33 -0600243 {
244 instanceToEffecterMap.emplace(position, pair.second);
245 position++;
246 }
247
248 return true;
249}
250
251/** @brief Reset SBE using HBRT PLDM interface */
252bool hresetSbe(unsigned int sbeInstance)
253{
254 trace::inf("requesting sbe hreset");
255
256 // get effecter info
257 std::map<unsigned int, uint16_t> sbeInstanceToEffecter;
Patrick Williams27dd6362023-05-10 07:51:20 -0500258 uint8_t SBEEffecterCount = 0;
Ben Tynerbb90afc2022-12-14 20:50:33 -0600259 uint8_t sbeMaintenanceStatePosition = 0;
260
261 if (!fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
262 sbeInstanceToEffecter, SBEEffecterCount,
263 sbeMaintenanceStatePosition))
264 {
265 return false;
266 }
267
268 // find the state effecter ID for the given SBE instance
269 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstance);
270 if (effecterEntry == sbeInstanceToEffecter.end())
271 {
272 trace::err("failed to find effecter for SBE");
273 return false;
274 }
275
276 // create request to HRESET the SBE
277 constexpr uint8_t hbrtMctpEid = 10; // HBRT MCTP EID
278
279 auto request = prepareSetEffecterReq(
280 effecterEntry->second, SBEEffecterCount, sbeMaintenanceStatePosition,
281 SBE_RETRY_REQUIRED, hbrtMctpEid);
282
283 if (request.empty())
284 {
285 trace::err("HRESET effecter request empty");
286 return false;
287 }
288
289 // get sensor info for validating sensor change
290 std::map<uint16_t, unsigned int> sensorToSbeInstance;
291 uint8_t sbeSensorOffset = 0;
292 if (!fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSbeInstance,
293 sbeSensorOffset))
294 {
295 return false;
296 }
297
298 // register signal change listener
299 std::string hresetStatus = "requested";
300 constexpr auto interface = "xyz.openbmc_project.PLDM.Event";
Patrick Williams27dd6362023-05-10 07:51:20 -0500301 constexpr auto path = "/xyz/openbmc_project/pldm";
302 constexpr auto member = "StateSensorEvent";
Ben Tynerbb90afc2022-12-14 20:50:33 -0600303
304 auto bus = sdbusplus::bus::new_default();
305 std::unique_ptr<sdbusplus::bus::match_t> match =
306 std::make_unique<sdbusplus::bus::match_t>(
307 bus,
308 sdbusplus::bus::match::rules::type::signal() +
309 sdbusplus::bus::match::rules::member(member) +
310 sdbusplus::bus::match::rules::path(path) +
311 sdbusplus::bus::match::rules::interface(interface),
312 [&](auto& msg) {
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400313 uint8_t sensorTid{};
314 uint16_t sensorId{};
315 uint8_t msgSensorOffset{};
316 uint8_t eventState{};
317 uint8_t previousEventState{};
Ben Tynerbb90afc2022-12-14 20:50:33 -0600318
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400319 // get sensor event details
320 msg.read(sensorTid, sensorId, msgSensorOffset, eventState,
321 previousEventState);
Ben Tynerbb90afc2022-12-14 20:50:33 -0600322
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400323 // does sensor offset match?
324 if (sbeSensorOffset == msgSensorOffset)
Ben Tynerbb90afc2022-12-14 20:50:33 -0600325 {
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400326 // does sensor ID match?
327 auto sensorEntry = sensorToSbeInstance.find(sensorId);
328 if (sensorEntry != sensorToSbeInstance.end())
Ben Tynerbb90afc2022-12-14 20:50:33 -0600329 {
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400330 const uint8_t instance = sensorEntry->second;
331
332 // if instances matche check status
333 if (instance == sbeInstance)
334 {
335 if (eventState ==
336 static_cast<uint8_t>(SBE_HRESET_READY))
337 {
338 hresetStatus = "success";
339 }
340 else if (eventState ==
341 static_cast<uint8_t>(SBE_HRESET_FAILED))
342 {
343 hresetStatus = "fail";
344 }
345 }
Ben Tynerbb90afc2022-12-14 20:50:33 -0600346 }
347 }
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400348 });
Ben Tynerbb90afc2022-12-14 20:50:33 -0600349
350 // send request to issue hreset of sbe
351 int pldmFd = -1; // mctp socket file descriptor
352 if (!sendPldm(request, hbrtMctpEid, pldmFd))
353 {
354 trace::err("send pldm request failed");
355 if (-1 != pldmFd)
356 {
357 close(pldmFd);
358 }
359 return false;
360 }
361
362 // keep track of elapsed time
363 uint64_t timeRemaining = 60000000; // microseconds, 1 minute
364 std::chrono::steady_clock::time_point begin =
365 std::chrono::steady_clock::now();
366
367 // wait for status update or timeout
368 trace::inf("waiting on sbe hreset");
369 while ("requested" == hresetStatus && 0 != timeRemaining)
370 {
371 bus.wait(timeRemaining);
372 uint64_t timeElapsed =
373 std::chrono::duration_cast<std::chrono::microseconds>(
374 std::chrono::steady_clock::now() - begin)
375 .count();
376
377 timeRemaining =
378 timeElapsed > timeRemaining ? 0 : timeRemaining - timeElapsed;
379
380 bus.process_discard();
381 }
382
383 if (0 == timeRemaining)
384 {
385 trace::err("hreset timed out");
386 }
387
388 close(pldmFd); // close pldm socket
389
390 return hresetStatus == "success" ? true : false;
391}
392
393} // namespace pldm
394} // namespace util