blob: a86d4409b67e500027fdfe9c426bf19ac92eebe8 [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>
Pavithra Barithaya36b043e2024-10-14 15:37:53 +05306#include <util/pldm.hpp>
Ben Tynerbb90afc2022-12-14 20:50:33 -06007#include <util/trace.hpp>
8
9namespace util
10{
11namespace pldm
12{
Pavithra Barithaya36b043e2024-10-14 15:37:53 +053013
14class PLDMInstanceManager
15{
16 public:
17 // Singleton access method
18 static PLDMInstanceManager& getInstance()
19 {
20 static PLDMInstanceManager instance;
21 return instance;
22 }
23
24 bool getPldmInstanceID(uint8_t& pldmInstance, uint8_t tid);
25 void freePLDMInstanceID(pldm_instance_id_t instanceID, uint8_t tid);
26
27 private:
28 // Private constructor and destructor to prevent creating multiple instances
29 PLDMInstanceManager();
30 ~PLDMInstanceManager();
31
32 // Deleted copy constructor and assignment operator to prevent copying
33 PLDMInstanceManager(const PLDMInstanceManager&) = delete;
34 PLDMInstanceManager& operator=(const PLDMInstanceManager&) = delete;
35
36 // Private member for the instance database
37 pldm_instance_db* pldmInstanceIdDb;
38};
39
40PLDMInstanceManager::PLDMInstanceManager() : pldmInstanceIdDb(nullptr)
41{
42 // Initialize the database object directly in the constructor
43 auto rc = pldm_instance_db_init_default(&pldmInstanceIdDb);
44 if (rc)
45 {
46 trace::err("Error calling pldm_instance_db_init_default, rc = %d",
47 (unsigned)rc);
48 }
49}
50
51PLDMInstanceManager::~PLDMInstanceManager()
52{
53 // Directly destroy the database object in the destructor
54 if (pldmInstanceIdDb)
55 {
56 auto rc = pldm_instance_db_destroy(pldmInstanceIdDb);
57 if (rc)
58 {
59 trace::err("pldm_instance_db_destroy failed rc = %d", (unsigned)rc);
60 }
61 }
62}
63
64// Get the PLDM instance ID for the given terminus ID
65bool PLDMInstanceManager::getPldmInstanceID(uint8_t& pldmInstance, uint8_t tid)
66{
67 pldm_instance_id_t id;
68 int rc = pldm_instance_id_alloc(pldmInstanceIdDb, tid, &id);
69 if (rc == -EAGAIN)
70 {
71 std::this_thread::sleep_for(
72 std::chrono::milliseconds(100)); // Retry after 100ms
73 rc = pldm_instance_id_alloc(pldmInstanceIdDb, tid,
74 &id); // Retry allocation
75 }
76
77 if (rc)
78 {
79 trace::err("getPldmInstanceId: Failed to alloc ID for TID = %d, RC= %d",
80 (unsigned)tid, (unsigned)rc);
81 return false;
82 }
83
84 pldmInstance = id; // Return the allocated instance ID
85 trace::inf("Got instanceId: %d, for PLDM TID: %d", (unsigned)pldmInstance,
86 (unsigned)tid);
87 return true;
88}
89
90// Free the PLDM instance ID associated with the terminus ID
91void PLDMInstanceManager::freePLDMInstanceID(pldm_instance_id_t instanceID,
92 uint8_t tid)
93{
94 int rc = pldm_instance_id_free(pldmInstanceIdDb, tid, instanceID);
95 if (rc)
96 {
97 trace::err(
98 "pldm_instance_id_free failed to free id=%d of TID=%d with rc= %d",
99 (unsigned)instanceID, (unsigned)tid, (unsigned)rc);
100 }
101}
102
Ben Tynerbb90afc2022-12-14 20:50:33 -0600103/** @brief Send PLDM request
104 *
105 * @param[in] request - the request data
106 * @param[in] mcptEid - the mctp endpoint ID
107 * @param[out] pldmFd - pldm socket file descriptor
108 *
109 * @pre a mctp instance must have been
110 * @return true if send is successful false otherwise
111 */
112bool sendPldm(const std::vector<uint8_t>& request, uint8_t mctpEid, int& pldmFd)
113{
114 // connect to socket
115 pldmFd = pldm_open();
116 if (-1 == pldmFd)
117 {
118 trace::err("failed to connect to pldm");
119 return false;
120 }
121
122 // send PLDM request
123 auto pldmRc = pldm_send(mctpEid, pldmFd, request.data(), request.size());
124
125 trace::inf("sent pldm request");
126
127 return pldmRc == PLDM_REQUESTER_SUCCESS ? true : false;
128}
129
130/** @brief Prepare a request for SetStateEffecterStates
131 *
132 * @param[in] effecterId - the effecter ID
133 * @param[in] effecterCount - composite effecter count
134 * @param[in] stateIdPos - position of the state set
135 * @param[in] stateSetValue - the value to set the state
136 * @param[in] mcptEid - the MCTP endpoint ID
137 *
138 * @return PLDM request message to be sent to host, empty message on error
139 */
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400140std::vector<uint8_t> prepareSetEffecterReq(
141 uint16_t effecterId, uint8_t effecterCount, uint8_t stateIdPos,
142 uint8_t stateSetValue, uint8_t mctpEid)
Ben Tynerbb90afc2022-12-14 20:50:33 -0600143{
Pavithra Barithaya36b043e2024-10-14 15:37:53 +0530144 PLDMInstanceManager& manager = PLDMInstanceManager::getInstance();
145
Pavithra Barithaya08f25b22024-10-14 14:38:57 +0530146 // get pldm instance associated with the endpoint ID
147 uint8_t pldmInstanceID;
Pavithra Barithaya36b043e2024-10-14 15:37:53 +0530148 if (!manager.getPldmInstanceID(pldmInstanceID, mctpEid))
Ben Tynerbb90afc2022-12-14 20:50:33 -0600149 {
150 return std::vector<uint8_t>();
151 }
152
153 // form the request message
154 std::vector<uint8_t> request(
155 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
156 (effecterCount * sizeof(set_effecter_state_field)));
157
158 // encode the state data with the change we want to elicit
159 std::vector<set_effecter_state_field> stateField;
160 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
161 {
162 if (effecterPos == stateIdPos)
163 {
164 stateField.emplace_back(
165 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
166 }
167 else
168 {
169 stateField.emplace_back(
170 set_effecter_state_field{PLDM_NO_CHANGE, 0});
171 }
172 }
173
174 // encode the message with state data
175 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
Patrick Williams27dd6362023-05-10 07:51:20 -0500176 auto rc = encode_set_state_effecter_states_req(
Pavithra Barithaya08f25b22024-10-14 14:38:57 +0530177 pldmInstanceID, effecterId, effecterCount, stateField.data(),
178 requestMsg);
Ben Tynerbb90afc2022-12-14 20:50:33 -0600179
180 if (rc != PLDM_SUCCESS)
181 {
182 trace::err("encode set effecter states request failed");
Pavithra Barithaya36b043e2024-10-14 15:37:53 +0530183 manager.freePLDMInstanceID(pldmInstanceID, mctpEid);
Ben Tynerbb90afc2022-12-14 20:50:33 -0600184 request.clear();
185 }
186
187 return request;
188}
189
190/** @brief Return map of sensor ID to SBE instance
191 *
192 * @param[in] stateSetId - the state set ID of interest
193 * @param[out] sensorInstanceMap - map of sensor to SBE instance
194 * @param[out] sensorOffset - position of sensor with state set ID within map
195 *
196 * @return true if sensor info is available false otherwise
197 */
198bool fetchSensorInfo(uint16_t stateSetId,
199 std::map<uint16_t, unsigned int>& sensorInstanceMap,
200 uint8_t& sensorOffset)
201{
202 // get state sensor PDRs
203 std::vector<std::vector<uint8_t>> pdrs{};
204 if (!util::dbus::getStateSensorPdrs(pdrs, stateSetId))
205 {
206 return false;
207 }
208
209 // check for any PDRs available
210 if (!pdrs.size())
211 {
212 trace::err("state sensor PDRs not present");
213 return false;
214 }
215
216 // find the offset of specified sensor withing PDRs
217 bool offsetFound = false;
218 auto stateSensorPDR =
219 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
220 auto possibleStatesPtr = stateSensorPDR->possible_states;
221
222 for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count;
223 offset++)
224 {
225 auto possibleStates =
226 reinterpret_cast<const state_sensor_possible_states*>(
227 possibleStatesPtr);
228
229 if (possibleStates->state_set_id == stateSetId)
230 {
231 sensorOffset = offset;
Patrick Williams27dd6362023-05-10 07:51:20 -0500232 offsetFound = true;
Ben Tynerbb90afc2022-12-14 20:50:33 -0600233 break;
234 }
235 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
236 sizeof(possibleStates->possible_states_size) +
237 possibleStates->possible_states_size;
238 }
239
240 if (!offsetFound)
241 {
242 trace::err("state sensor not found");
243 return false;
244 }
245
246 // map sensor ID to equivelent 16 bit value
247 std::map<uint32_t, uint16_t> entityInstMap{};
248 for (auto& pdr : pdrs)
249 {
250 auto pdrPtr =
251 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
252 uint32_t key = pdrPtr->sensor_id;
253 entityInstMap.emplace(key, static_cast<uint16_t>(pdrPtr->sensor_id));
254 }
255
256 // map sensor ID to zero based SBE instance
257 unsigned int position = 0;
Patrick Williams27dd6362023-05-10 07:51:20 -0500258 for (const auto& pair : entityInstMap)
Ben Tynerbb90afc2022-12-14 20:50:33 -0600259 {
260 sensorInstanceMap.emplace(pair.second, position);
261 position++;
262 }
263
264 return true;
265}
266
267/** @brief Return map of SBE instance to effecter ID
268 *
269 * @param[in] stateSetId - the state set ID of interest
270 * @param[out] instanceToEffecterMap - map of sbe instance to effecter ID
271 * @param[out] effecterCount - composite effecter count
272 * @param[out] stateIdPos - position of effecter with state set ID within map
273 *
274 * @return true if effector info is available false otherwise
275 */
276bool fetchEffecterInfo(uint16_t stateSetId,
277 std::map<unsigned int, uint16_t>& instanceToEffecterMap,
278 uint8_t& effecterCount, uint8_t& stateIdPos)
279{
280 // get state effecter PDRs
281 std::vector<std::vector<uint8_t>> pdrs{};
282 if (!util::dbus::getStateEffecterPdrs(pdrs, stateSetId))
283 {
284 return false;
285 }
286
287 // check for any PDRs available
288 if (!pdrs.size())
289 {
290 trace::err("state effecter PDRs not present");
291 return false;
292 }
293
294 // find the offset of specified effector within PDRs
295 bool offsetFound = false;
296 auto stateEffecterPDR =
297 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
298 auto possibleStatesPtr = stateEffecterPDR->possible_states;
299
300 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
301 offset++)
302 {
303 auto possibleStates =
304 reinterpret_cast<const state_effecter_possible_states*>(
305 possibleStatesPtr);
306
307 if (possibleStates->state_set_id == stateSetId)
308 {
Patrick Williams27dd6362023-05-10 07:51:20 -0500309 stateIdPos = offset;
Ben Tynerbb90afc2022-12-14 20:50:33 -0600310 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams27dd6362023-05-10 07:51:20 -0500311 offsetFound = true;
Ben Tynerbb90afc2022-12-14 20:50:33 -0600312 break;
313 }
314 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
315 sizeof(possibleStates->possible_states_size) +
316 possibleStates->possible_states_size;
317 }
318
319 if (!offsetFound)
320 {
321 trace::err("state set effecter not found");
322 return false;
323 }
324
325 // map effecter ID to equivelent 16 bit value
326 std::map<uint32_t, uint16_t> entityInstMap{};
327 for (auto& pdr : pdrs)
328 {
329 auto pdrPtr =
330 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
331 uint32_t key = pdrPtr->effecter_id;
332 entityInstMap.emplace(key, static_cast<uint16_t>(pdrPtr->effecter_id));
333 }
334
335 // map zero based SBE instance to effecter ID
336 unsigned int position = 0;
Patrick Williams27dd6362023-05-10 07:51:20 -0500337 for (const auto& pair : entityInstMap)
Ben Tynerbb90afc2022-12-14 20:50:33 -0600338 {
339 instanceToEffecterMap.emplace(position, pair.second);
340 position++;
341 }
342
343 return true;
344}
345
346/** @brief Reset SBE using HBRT PLDM interface */
347bool hresetSbe(unsigned int sbeInstance)
348{
349 trace::inf("requesting sbe hreset");
350
351 // get effecter info
352 std::map<unsigned int, uint16_t> sbeInstanceToEffecter;
Patrick Williams27dd6362023-05-10 07:51:20 -0500353 uint8_t SBEEffecterCount = 0;
Ben Tynerbb90afc2022-12-14 20:50:33 -0600354 uint8_t sbeMaintenanceStatePosition = 0;
355
356 if (!fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
357 sbeInstanceToEffecter, SBEEffecterCount,
358 sbeMaintenanceStatePosition))
359 {
360 return false;
361 }
362
363 // find the state effecter ID for the given SBE instance
364 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstance);
365 if (effecterEntry == sbeInstanceToEffecter.end())
366 {
367 trace::err("failed to find effecter for SBE");
368 return false;
369 }
370
371 // create request to HRESET the SBE
372 constexpr uint8_t hbrtMctpEid = 10; // HBRT MCTP EID
373
374 auto request = prepareSetEffecterReq(
375 effecterEntry->second, SBEEffecterCount, sbeMaintenanceStatePosition,
376 SBE_RETRY_REQUIRED, hbrtMctpEid);
377
378 if (request.empty())
379 {
380 trace::err("HRESET effecter request empty");
381 return false;
382 }
383
384 // get sensor info for validating sensor change
385 std::map<uint16_t, unsigned int> sensorToSbeInstance;
386 uint8_t sbeSensorOffset = 0;
387 if (!fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSbeInstance,
388 sbeSensorOffset))
389 {
Pavithra Barithaya36b043e2024-10-14 15:37:53 +0530390 PLDMInstanceManager& manager = PLDMInstanceManager::getInstance();
391 auto reqhdr = reinterpret_cast<const pldm_msg_hdr*>(&request);
392 manager.freePLDMInstanceID(reqhdr->instance_id, hbrtMctpEid);
Ben Tynerbb90afc2022-12-14 20:50:33 -0600393 return false;
394 }
395
396 // register signal change listener
397 std::string hresetStatus = "requested";
398 constexpr auto interface = "xyz.openbmc_project.PLDM.Event";
Patrick Williams27dd6362023-05-10 07:51:20 -0500399 constexpr auto path = "/xyz/openbmc_project/pldm";
400 constexpr auto member = "StateSensorEvent";
Ben Tynerbb90afc2022-12-14 20:50:33 -0600401
402 auto bus = sdbusplus::bus::new_default();
403 std::unique_ptr<sdbusplus::bus::match_t> match =
404 std::make_unique<sdbusplus::bus::match_t>(
405 bus,
406 sdbusplus::bus::match::rules::type::signal() +
407 sdbusplus::bus::match::rules::member(member) +
408 sdbusplus::bus::match::rules::path(path) +
409 sdbusplus::bus::match::rules::interface(interface),
410 [&](auto& msg) {
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400411 uint8_t sensorTid{};
412 uint16_t sensorId{};
413 uint8_t msgSensorOffset{};
414 uint8_t eventState{};
415 uint8_t previousEventState{};
Ben Tynerbb90afc2022-12-14 20:50:33 -0600416
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400417 // get sensor event details
418 msg.read(sensorTid, sensorId, msgSensorOffset, eventState,
419 previousEventState);
Ben Tynerbb90afc2022-12-14 20:50:33 -0600420
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400421 // does sensor offset match?
422 if (sbeSensorOffset == msgSensorOffset)
Ben Tynerbb90afc2022-12-14 20:50:33 -0600423 {
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400424 // does sensor ID match?
425 auto sensorEntry = sensorToSbeInstance.find(sensorId);
426 if (sensorEntry != sensorToSbeInstance.end())
Ben Tynerbb90afc2022-12-14 20:50:33 -0600427 {
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400428 const uint8_t instance = sensorEntry->second;
429
430 // if instances matche check status
431 if (instance == sbeInstance)
432 {
433 if (eventState ==
434 static_cast<uint8_t>(SBE_HRESET_READY))
435 {
436 hresetStatus = "success";
437 }
438 else if (eventState ==
439 static_cast<uint8_t>(SBE_HRESET_FAILED))
440 {
441 hresetStatus = "fail";
442 }
443 }
Ben Tynerbb90afc2022-12-14 20:50:33 -0600444 }
445 }
Patrick Williamsa0c724d2024-08-16 15:21:54 -0400446 });
Ben Tynerbb90afc2022-12-14 20:50:33 -0600447
448 // send request to issue hreset of sbe
449 int pldmFd = -1; // mctp socket file descriptor
450 if (!sendPldm(request, hbrtMctpEid, pldmFd))
451 {
452 trace::err("send pldm request failed");
453 if (-1 != pldmFd)
454 {
Pavithra Barithaya36b043e2024-10-14 15:37:53 +0530455 trace::err("failed to connect to pldm");
Ben Tynerbb90afc2022-12-14 20:50:33 -0600456 close(pldmFd);
457 }
Pavithra Barithaya36b043e2024-10-14 15:37:53 +0530458 PLDMInstanceManager& manager = PLDMInstanceManager::getInstance();
459 auto reqhdr = reinterpret_cast<const pldm_msg_hdr*>(&request);
460 manager.freePLDMInstanceID(reqhdr->instance_id, hbrtMctpEid);
461
Ben Tynerbb90afc2022-12-14 20:50:33 -0600462 return false;
463 }
464
465 // keep track of elapsed time
466 uint64_t timeRemaining = 60000000; // microseconds, 1 minute
467 std::chrono::steady_clock::time_point begin =
468 std::chrono::steady_clock::now();
469
470 // wait for status update or timeout
471 trace::inf("waiting on sbe hreset");
472 while ("requested" == hresetStatus && 0 != timeRemaining)
473 {
474 bus.wait(timeRemaining);
475 uint64_t timeElapsed =
476 std::chrono::duration_cast<std::chrono::microseconds>(
477 std::chrono::steady_clock::now() - begin)
478 .count();
479
480 timeRemaining =
481 timeElapsed > timeRemaining ? 0 : timeRemaining - timeElapsed;
482
483 bus.process_discard();
484 }
485
486 if (0 == timeRemaining)
487 {
488 trace::err("hreset timed out");
489 }
490
Pavithra Barithaya36b043e2024-10-14 15:37:53 +0530491 PLDMInstanceManager& manager = PLDMInstanceManager::getInstance();
492 auto reqhdr = reinterpret_cast<const pldm_msg_hdr*>(&request);
493 manager.freePLDMInstanceID(reqhdr->instance_id, hbrtMctpEid);
Ben Tynerbb90afc2022-12-14 20:50:33 -0600494 close(pldmFd); // close pldm socket
495
496 return hresetStatus == "success" ? true : false;
497}
498
499} // namespace pldm
500} // namespace util