blob: b96b8ebfa87e4118bd33dbd8290157507a93ea96 [file] [log] [blame]
Patrick Williams05e95592021-09-02 09:28:14 -05001#include "pldm.hpp"
2
Rashmica Guptadb38e912023-05-25 10:33:46 +10003#include "libpldm/instance-id.h"
4
Patrick Williams05e95592021-09-02 09:28:14 -05005#include "file.hpp"
6
Patrick Williams05e95592021-09-02 09:28:14 -05007#include <libpldm/entity.h>
Andrew Jeffery97476a12024-06-19 21:07:29 +09308#include <libpldm/oem/ibm/state_set.h>
Patrick Williams05e95592021-09-02 09:28:14 -05009#include <libpldm/platform.h>
10#include <libpldm/state_set.h>
Rashmica Gupta52328cb2023-02-15 10:38:16 +110011#include <libpldm/transport.h>
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -050012#include <libpldm/transport/af-mctp.h>
Rashmica Gupta52328cb2023-02-15 10:38:16 +110013#include <libpldm/transport/mctp-demux.h>
14#include <poll.h>
Patrick Williams05e95592021-09-02 09:28:14 -050015
Chris Cain37abe9b2024-10-31 17:20:31 -050016#include <phosphor-logging/lg2.hpp>
Chris Cainbae4d072022-02-28 09:46:50 -060017#include <sdbusplus/bus.hpp>
18#include <sdeventplus/clock.hpp>
19#include <sdeventplus/exception.hpp>
20#include <sdeventplus/source/io.hpp>
21#include <sdeventplus/source/time.hpp>
22
23#include <algorithm>
Patrick Williams05e95592021-09-02 09:28:14 -050024
25namespace pldm
26{
27
Chris Cainbae4d072022-02-28 09:46:50 -060028using namespace sdeventplus;
29using namespace sdeventplus::source;
30constexpr auto clockId = sdeventplus::ClockId::RealTime;
31using Clock = sdeventplus::Clock<clockId>;
32using Timer = Time<clockId>;
Chris Cain755af102024-02-27 16:09:51 -060033bool Interface::throttleTraces = false;
Chris Cainf0295f52024-09-12 15:41:14 -050034enum pldm_msg_type Interface::msgType = MSG_UNDEFINED;
35open_power::occ::instanceID Interface::resetInstance = 0;
Chris Cainbae4d072022-02-28 09:46:50 -060036
Eddie Jamescbad2192021-10-07 09:39:39 -050037void Interface::fetchSensorInfo(uint16_t stateSetId,
38 SensorToInstance& sensorInstanceMap,
39 SensorOffset& sensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -050040{
Eddie Jamescbad2192021-10-07 09:39:39 -050041 PdrList pdrs{};
Chris Cainbae4d072022-02-28 09:46:50 -060042 static bool tracedError = false;
Eddie Jamescbad2192021-10-07 09:39:39 -050043
44 auto& bus = open_power::occ::utils::getBus();
45 try
46 {
47 auto method = bus.new_method_call(
48 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
49 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
Chris Cainbae4d072022-02-28 09:46:50 -060050 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -050051
52 auto responseMsg = bus.call(method);
53 responseMsg.read(pdrs);
54 }
Patrick Williamsaf408082022-07-22 19:26:54 -050055 catch (const sdbusplus::exception_t& e)
Eddie Jamescbad2192021-10-07 09:39:39 -050056 {
Chris Cainbae4d072022-02-28 09:46:50 -060057 if (!tracedError)
58 {
Chris Cain37abe9b2024-10-31 17:20:31 -050059 lg2::error(
60 "fetchSensorInfo: Failed to find stateSetID:{ID} PDR: {ERR}",
61 "ID", stateSetId, "ERR", e.what());
Chris Cainbae4d072022-02-28 09:46:50 -060062 tracedError = true;
63 }
Eddie Jamescbad2192021-10-07 09:39:39 -050064 }
65
66 if (pdrs.empty())
67 {
Chris Cainbae4d072022-02-28 09:46:50 -060068 if (!tracedError)
69 {
Chris Cain37abe9b2024-10-31 17:20:31 -050070 lg2::error("fetchSensorInfo: state sensor PDRs ({ID}) not present",
71 "ID", stateSetId);
Chris Cainbae4d072022-02-28 09:46:50 -060072 tracedError = true;
73 }
Eddie Jamescbad2192021-10-07 09:39:39 -050074 return;
75 }
76
Chris Cainbae4d072022-02-28 09:46:50 -060077 // Found PDR
78 if (tracedError)
79 {
Chris Cain37abe9b2024-10-31 17:20:31 -050080 lg2::info("fetchSensorInfo: found {NUM} PDRs", "NUM", pdrs.size());
Chris Cainbae4d072022-02-28 09:46:50 -060081 tracedError = false;
82 }
83
Patrick Williams05e95592021-09-02 09:28:14 -050084 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +080085 auto stateSensorPDR =
Patrick Williams05e95592021-09-02 09:28:14 -050086 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +080087 auto possibleStatesPtr = stateSensorPDR->possible_states;
88 for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count;
89 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -050090 {
91 auto possibleStates =
92 reinterpret_cast<const state_sensor_possible_states*>(
93 possibleStatesPtr);
94
Eddie Jamescbad2192021-10-07 09:39:39 -050095 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -050096 {
97 sensorOffset = offset;
98 offsetFound = true;
99 break;
100 }
101 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
102 sizeof(possibleStates->possible_states_size) +
103 possibleStates->possible_states_size;
104 }
105
106 if (!offsetFound)
107 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500108 lg2::error("pldm: state sensor PDR not found");
Patrick Williams05e95592021-09-02 09:28:14 -0500109 return;
110 }
111
112 // To order SensorID based on the EntityInstance.
113 // Note that when a proc is on a DCM, the PDRs for these sensors
114 // could have the same instance IDs but different container IDs.
115 std::map<uint32_t, SensorID> entityInstMap{};
116 for (auto& pdr : pdrs)
117 {
118 auto pdrPtr =
119 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
Chris Cain72d01aa2022-06-14 16:28:03 -0500120 uint32_t key = pdrPtr->sensor_id;
Patrick Williams05e95592021-09-02 09:28:14 -0500121 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->sensor_id));
122 }
123
124 open_power::occ::instanceID count = start;
Patrick Williamsa49c9872023-05-10 07:50:35 -0500125 for (const auto& pair : entityInstMap)
Patrick Williams05e95592021-09-02 09:28:14 -0500126 {
127 sensorInstanceMap.emplace(pair.second, count);
128 count++;
129 }
130}
131
Patrick Williamsaf408082022-07-22 19:26:54 -0500132void Interface::sensorEvent(sdbusplus::message_t& msg)
Patrick Williams05e95592021-09-02 09:28:14 -0500133{
134 if (!isOCCSensorCacheValid())
135 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500136 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
137 sensorToOCCInstance, OCCSensorOffset);
138 }
Patrick Williams05e95592021-09-02 09:28:14 -0500139
Eddie Jamescbad2192021-10-07 09:39:39 -0500140 if (sensorToSBEInstance.empty())
141 {
142 fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSBEInstance,
143 SBESensorOffset);
Patrick Williams05e95592021-09-02 09:28:14 -0500144 }
145
Chris Cain72d01aa2022-06-14 16:28:03 -0500146 TerminusID sensorTid{};
Patrick Williams05e95592021-09-02 09:28:14 -0500147 SensorID sensorId{};
148 SensorOffset msgSensorOffset{};
149 EventState eventState{};
150 EventState previousEventState{};
151
Chris Cain72d01aa2022-06-14 16:28:03 -0500152 msg.read(sensorTid, sensorId, msgSensorOffset, eventState,
153 previousEventState);
Patrick Williams05e95592021-09-02 09:28:14 -0500154
Eddie Jamescbad2192021-10-07 09:39:39 -0500155 if (msgSensorOffset == OCCSensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -0500156 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500157 auto sensorEntry = sensorToOCCInstance.find(sensorId);
Patrick Williams05e95592021-09-02 09:28:14 -0500158
Eddie James432dc482021-11-19 15:29:31 -0600159 if (sensorEntry != sensorToOCCInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500160 {
Chris Cain8b508bf2022-05-26 14:01:31 -0500161 const uint8_t instance = sensorEntry->second;
Chris Cain755af102024-02-27 16:09:51 -0600162 bool validEvent = true;
Chris Cain7b00cde2023-03-14 15:47:12 -0500163 bool isRunning = false;
Eddie James432dc482021-11-19 15:29:31 -0600164 if (eventState ==
165 static_cast<EventState>(
166 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
167 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500168 lg2::info("PLDM: OCC{INST} is RUNNING", "INST", instance);
Chris Cain7b00cde2023-03-14 15:47:12 -0500169 isRunning = true;
Eddie James432dc482021-11-19 15:29:31 -0600170 }
171 else if (eventState ==
172 static_cast<EventState>(
173 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
174 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500175 lg2::info("PLDM: OCC{INST} has now STOPPED", "INST", instance);
Eddie James432dc482021-11-19 15:29:31 -0600176 }
Chris Cainbae4d072022-02-28 09:46:50 -0600177 else if (eventState ==
178 static_cast<EventState>(
179 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT))
180 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500181 lg2::error(
182 "PLDM: OCC{INST} has now STOPPED and system is in SAFE MODE",
183 "INST", instance);
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500184
185 // Setting safe mode true
186 safeModeCallBack(true);
Chris Cainbae4d072022-02-28 09:46:50 -0600187 }
188 else
189 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500190 lg2::warning(
191 "PLDM: Unexpected OCC Active sensor state {STATE} for OCC{INST}",
192 "STATE", eventState, "INST", instance);
Chris Cain755af102024-02-27 16:09:51 -0600193 validEvent = false;
Chris Cainbae4d072022-02-28 09:46:50 -0600194 }
Chris Cain755af102024-02-27 16:09:51 -0600195 if (validEvent)
196 {
197 if ((pldmFd > 0) && (instance == pldmResponseOcc))
198 {
199 // Waiting for a response for this OCC, can stop waiting
200 pldmClose();
201 }
Chris Cainf0295f52024-09-12 15:41:14 -0500202 occActiveCallBack(instance, isRunning);
Chris Cain755af102024-02-27 16:09:51 -0600203 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500204 return;
205 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500206 }
Eddie James432dc482021-11-19 15:29:31 -0600207
208 if (msgSensorOffset == SBESensorOffset)
Eddie Jamescbad2192021-10-07 09:39:39 -0500209 {
210 auto sensorEntry = sensorToSBEInstance.find(sensorId);
211
Eddie James432dc482021-11-19 15:29:31 -0600212 if (sensorEntry != sensorToSBEInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500213 {
Chris Cain12d0b822022-04-22 17:29:18 -0500214 const uint8_t instance = sensorEntry->second;
215 auto match = std::find(outstandingHResets.begin(),
216 outstandingHResets.end(), instance);
217 if (match != outstandingHResets.end())
Eddie James432dc482021-11-19 15:29:31 -0600218 {
Chris Cain12d0b822022-04-22 17:29:18 -0500219 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
220 {
Chris Cain92dfb272025-02-13 12:20:27 -0600221 lg2::warning("pldm: HRESET is NOT READY (OCC{INST})",
222 "INST", instance);
223 // Keep waiting for status from HRESET
Chris Cain12d0b822022-04-22 17:29:18 -0500224 }
225 else if (eventState ==
226 static_cast<EventState>(SBE_HRESET_READY))
227 {
Chris Cain92dfb272025-02-13 12:20:27 -0600228 // Reset success, clear reset request
229 outstandingHResets.erase(match);
Chris Cain12d0b822022-04-22 17:29:18 -0500230 sbeCallBack(instance, true);
231 }
232 else if (eventState ==
233 static_cast<EventState>(SBE_HRESET_FAILED))
234 {
Chris Cain92dfb272025-02-13 12:20:27 -0600235 // Reset failed, clear reset request and collect SBE dump
236 outstandingHResets.erase(match);
Chris Cain12d0b822022-04-22 17:29:18 -0500237 sbeCallBack(instance, false);
238 }
Chris Cainf0295f52024-09-12 15:41:14 -0500239 else
240 {
Chris Cain92dfb272025-02-13 12:20:27 -0600241 lg2::warning(
242 "pldm: Unexpected HRESET state {STATE} (OCC{INST})",
243 "STATE", eventState, "INST", instance);
Chris Cainf0295f52024-09-12 15:41:14 -0500244 }
Eddie James432dc482021-11-19 15:29:31 -0600245 }
Chris Cain92dfb272025-02-13 12:20:27 -0600246 else // request was not due to our HRESET request
247 {
248 if (eventState == static_cast<EventState>(SBE_HRESET_FAILED))
249 {
250 lg2::error(
251 "pldm: Unexpected HRESET state {FAILED} (OCC{INST}) when HRESET not outstanding",
252 "INST", instance);
253
254 // No recovery from failed state, so ensure comm was stopped
255 occActiveCallBack(instance, false);
256 }
257 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500258 }
259 }
Patrick Williams05e95592021-09-02 09:28:14 -0500260}
261
Patrick Williamsaf408082022-07-22 19:26:54 -0500262void Interface::hostStateEvent(sdbusplus::message_t& msg)
Chris Cain157467d2022-06-24 11:25:23 -0500263{
264 std::map<std::string, std::variant<std::string>> properties{};
265 std::string interface;
266 msg.read(interface, properties);
267 const auto stateEntry = properties.find("CurrentHostState");
268 if (stateEntry != properties.end())
269 {
270 auto stateEntryValue = stateEntry->second;
271 auto propVal = std::get<std::string>(stateEntryValue);
272 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
273 {
274 clearData();
Chris Cainc488bac2025-03-17 09:01:15 -0500275 // Notify manager that host is now off
276 poweredOffCallBack();
Chris Cain157467d2022-06-24 11:25:23 -0500277 }
278 }
279}
280
Chris Cainbae4d072022-02-28 09:46:50 -0600281void Interface::clearData()
282{
Chris Cain72d01aa2022-06-14 16:28:03 -0500283 if (!sensorToOCCInstance.empty())
284 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500285 lg2::info("clearData: Clearing sensorToOCCInstance ({NUM} entries)",
286 "NUM", sensorToOCCInstance.size());
Chris Cain72d01aa2022-06-14 16:28:03 -0500287 for (auto entry : sensorToOCCInstance)
288 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500289 lg2::info("clearData: OCC{INST} / sensorID: {ID}", "INST",
290 entry.second, "ID", lg2::hex, entry.first);
Chris Cainf0295f52024-09-12 15:41:14 -0500291 occActiveCallBack(entry.second, false);
Chris Cain72d01aa2022-06-14 16:28:03 -0500292 }
293 sensorToOCCInstance.clear();
294 }
295 if (!occInstanceToEffecter.empty())
296 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500297 lg2::debug("clearData: Clearing occInstanceToEffecter ({NUM} entries)",
298 "NUM", occInstanceToEffecter.size());
Chris Cain72d01aa2022-06-14 16:28:03 -0500299 occInstanceToEffecter.clear();
300 }
301 if (!sensorToSBEInstance.empty())
302 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500303 lg2::debug("clearData: Clearing sensorToSBEInstance ({NUM} entries)",
304 "NUM", sensorToSBEInstance.size());
Chris Cain72d01aa2022-06-14 16:28:03 -0500305 sensorToSBEInstance.clear();
306 }
307 if (!sbeInstanceToEffecter.empty())
308 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500309 lg2::debug("clearData: Clearing sbeInstanceToEffecter ({NUM} entries)",
310 "NUM", sbeInstanceToEffecter.size());
Chris Cain72d01aa2022-06-14 16:28:03 -0500311 sbeInstanceToEffecter.clear();
312 }
Chris Cainc488bac2025-03-17 09:01:15 -0500313 if (!outstandingHResets.empty())
314 {
315 lg2::info("clearData: clearing {NUM} outstanding HRESET requests",
316 "NUM", outstandingHResets.size());
317 outstandingHResets.clear();
318 }
Chris Cainbae4d072022-02-28 09:46:50 -0600319}
320
Patrick Williamsd7542c82024-08-16 15:20:28 -0400321void Interface::fetchEffecterInfo(
322 uint16_t stateSetId, InstanceToEffecter& instanceToEffecterMap,
323 CompositeEffecterCount& effecterCount, uint8_t& stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500324{
Eddie Jamescbad2192021-10-07 09:39:39 -0500325 PdrList pdrs{};
326
327 auto& bus = open_power::occ::utils::getBus();
328 try
329 {
330 auto method = bus.new_method_call(
331 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
332 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Chris Cainbae4d072022-02-28 09:46:50 -0600333 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -0500334
335 auto responseMsg = bus.call(method);
336 responseMsg.read(pdrs);
337 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500338 catch (const sdbusplus::exception_t& e)
Eddie Jamescbad2192021-10-07 09:39:39 -0500339 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500340 lg2::error("pldm: Failed to fetch the state effecter PDRs: {ERR}",
341 "ERR", e.what());
Eddie Jamescbad2192021-10-07 09:39:39 -0500342 }
343
344 if (!pdrs.size())
345 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500346 lg2::error("pldm: state effecter PDRs not present");
Eddie Jamescbad2192021-10-07 09:39:39 -0500347 return;
348 }
349
Patrick Williams05e95592021-09-02 09:28:14 -0500350 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +0800351 auto stateEffecterPDR =
Patrick Williams05e95592021-09-02 09:28:14 -0500352 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +0800353 auto possibleStatesPtr = stateEffecterPDR->possible_states;
354 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
355 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -0500356 {
357 auto possibleStates =
358 reinterpret_cast<const state_effecter_possible_states*>(
359 possibleStatesPtr);
360
Eddie Jamescbad2192021-10-07 09:39:39 -0500361 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500362 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500363 stateIdPos = offset;
George Liuf3a4a692021-12-28 13:59:51 +0800364 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams05e95592021-09-02 09:28:14 -0500365 offsetFound = true;
366 break;
367 }
368 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
369 sizeof(possibleStates->possible_states_size) +
370 possibleStates->possible_states_size;
371 }
372
373 if (!offsetFound)
374 {
375 return;
376 }
377
Chris Cain0f516522022-02-07 14:48:28 -0600378 std::map<uint32_t, EffecterID> entityInstMap{};
Patrick Williams05e95592021-09-02 09:28:14 -0500379 for (auto& pdr : pdrs)
380 {
381 auto pdrPtr =
382 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
Chris Cain72d01aa2022-06-14 16:28:03 -0500383 uint32_t key = pdrPtr->effecter_id;
Patrick Williams05e95592021-09-02 09:28:14 -0500384 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
385 }
386
387 open_power::occ::instanceID position = start;
Patrick Williamsa49c9872023-05-10 07:50:35 -0500388 for (const auto& pair : entityInstMap)
Patrick Williams05e95592021-09-02 09:28:14 -0500389 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500390 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500391 position++;
392 }
393}
394
Patrick Williamsd7542c82024-08-16 15:20:28 -0400395std::vector<uint8_t> Interface::prepareSetEffecterReq(
396 EffecterID effecterId, CompositeEffecterCount effecterCount,
397 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500398{
Rashmica Guptaaeba51c2023-02-17 12:30:46 +1100399 if (!getPldmInstanceId())
Chris Cain8b508bf2022-05-26 14:01:31 -0500400 {
401 return std::vector<uint8_t>();
402 }
403
Patrick Williams05e95592021-09-02 09:28:14 -0500404 std::vector<uint8_t> request(
405 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
406 (effecterCount * sizeof(set_effecter_state_field)));
407 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
408 std::vector<set_effecter_state_field> stateField;
409
410 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
411 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500412 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500413 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500414 stateField.emplace_back(
415 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500416 }
417 else
418 {
419 stateField.emplace_back(
420 set_effecter_state_field{PLDM_NO_CHANGE, 0});
421 }
422 }
423 auto rc = encode_set_state_effecter_states_req(
Rashmica Guptaaeba51c2023-02-17 12:30:46 +1100424 pldmInstanceID.value(), effecterId, effecterCount, stateField.data(),
Chris Cain8b508bf2022-05-26 14:01:31 -0500425 requestMsg);
Patrick Williams05e95592021-09-02 09:28:14 -0500426 if (rc != PLDM_SUCCESS)
427 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500428 lg2::error("encode set effecter states request returned error rc={RC}",
429 "RC", rc);
Patrick Williams05e95592021-09-02 09:28:14 -0500430 request.clear();
431 }
432 return request;
433}
434
435void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
436{
Chris Cainbae4d072022-02-28 09:46:50 -0600437 if (open_power::occ::utils::isHostRunning())
Patrick Williams05e95592021-09-02 09:28:14 -0500438 {
Chris Cainbae4d072022-02-28 09:46:50 -0600439 if (!isPDREffecterCacheValid())
440 {
441 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
442 occInstanceToEffecter, OCCEffecterCount,
443 bootRestartPosition);
444 }
Patrick Williams05e95592021-09-02 09:28:14 -0500445
Chris Cainbae4d072022-02-28 09:46:50 -0600446 // Find the matching effecter for the OCC instance
447 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
448 if (effecterEntry == occInstanceToEffecter.end())
449 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500450 lg2::error(
451 "pldm: Failed to find a matching effecter for OCC instance {INST}",
452 "INST", occInstanceId);
Chris Cainbae4d072022-02-28 09:46:50 -0600453
454 return;
455 }
456
Chris Cainbae4d072022-02-28 09:46:50 -0600457 // Prepare the SetStateEffecterStates request to reset the OCC
458 auto request = prepareSetEffecterReq(
Chris Cain8b508bf2022-05-26 14:01:31 -0500459 effecterEntry->second, OCCEffecterCount, bootRestartPosition,
460 PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
Chris Cainbae4d072022-02-28 09:46:50 -0600461
462 if (request.empty())
463 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500464 lg2::error("pldm: SetStateEffecterStates OCC reset request empty");
Chris Cainbae4d072022-02-28 09:46:50 -0600465 return;
466 }
467
Chris Cainf0295f52024-09-12 15:41:14 -0500468 // Send request to reset the OCCs/PM Complex (and wait for response)
469 msgType = MSG_OCC_RESET;
470 resetInstance = occInstanceId;
471 sendPldm(request, occInstanceId, true);
Chris Cainbae4d072022-02-28 09:46:50 -0600472 }
473 else
Patrick Williams05e95592021-09-02 09:28:14 -0500474 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500475 lg2::error("resetOCC: HOST is not running (OCC{INST})", "INST",
476 occInstanceId);
Chris Cainbae4d072022-02-28 09:46:50 -0600477 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500478 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500479}
480
481void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
482{
Chris Cainbae4d072022-02-28 09:46:50 -0600483 if (open_power::occ::utils::isHostRunning())
Eddie Jamescbad2192021-10-07 09:39:39 -0500484 {
Chris Cainbae4d072022-02-28 09:46:50 -0600485 if (sbeInstanceToEffecter.empty())
486 {
487 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
488 sbeInstanceToEffecter, SBEEffecterCount,
489 sbeMaintenanceStatePosition);
490 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500491
Chris Cainbae4d072022-02-28 09:46:50 -0600492 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
493 if (effecterEntry == sbeInstanceToEffecter.end())
494 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500495 lg2::error(
496 "pldm: Failed to find a matching effecter for SBE instance {INST}",
497 "INST", sbeInstanceId);
Chris Cainbae4d072022-02-28 09:46:50 -0600498 return;
499 }
500
Chris Cainbae4d072022-02-28 09:46:50 -0600501 // Prepare the SetStateEffecterStates request to HRESET the SBE
502 auto request = prepareSetEffecterReq(
Chris Cain8b508bf2022-05-26 14:01:31 -0500503 effecterEntry->second, SBEEffecterCount,
Chris Cainbae4d072022-02-28 09:46:50 -0600504 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
505
506 if (request.empty())
507 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500508 lg2::error("pldm: SetStateEffecterStates HRESET request empty");
Chris Cainbae4d072022-02-28 09:46:50 -0600509 return;
510 }
511
Chris Cainf0295f52024-09-12 15:41:14 -0500512 // Send request to issue HRESET of SBE (and wait for response)
513 msgType = MSG_HRESET;
514 resetInstance = sbeInstanceId;
515 sendPldm(request, sbeInstanceId, true);
Chris Cain12d0b822022-04-22 17:29:18 -0500516 outstandingHResets.insert(sbeInstanceId);
Chris Cainbae4d072022-02-28 09:46:50 -0600517 }
518 else
Eddie Jamescbad2192021-10-07 09:39:39 -0500519 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500520 lg2::error("sendHRESET: HOST is not running (OCC{INST})", "INST",
521 sbeInstanceId);
Chris Cainbae4d072022-02-28 09:46:50 -0600522 clearData();
Eddie Jamescbad2192021-10-07 09:39:39 -0500523 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500524}
525
Rashmica Guptaaeba51c2023-02-17 12:30:46 +1100526bool Interface::getPldmInstanceId()
Eddie Jamescbad2192021-10-07 09:39:39 -0500527{
Rashmica Guptadb38e912023-05-25 10:33:46 +1000528 pldm_instance_id_t id;
Rashmica Guptaaeba51c2023-02-17 12:30:46 +1100529 if (!pldmInstanceID)
Patrick Williams05e95592021-09-02 09:28:14 -0500530 {
Chris Cain8b508bf2022-05-26 14:01:31 -0500531 // Request new instance ID
Rashmica Guptadb38e912023-05-25 10:33:46 +1000532 int rc = pldm_instance_id_alloc(pldmInstanceIdDb, tid, &id);
533 if (rc == -EAGAIN)
Chris Cain8b508bf2022-05-26 14:01:31 -0500534 {
Rashmica Guptadb38e912023-05-25 10:33:46 +1000535 std::this_thread::sleep_for(std::chrono::milliseconds(100));
536 rc = pldm_instance_id_alloc(pldmInstanceIdDb, tid, &id);
Chris Cain8b508bf2022-05-26 14:01:31 -0500537 }
Rashmica Guptadb38e912023-05-25 10:33:46 +1000538
539 if (rc)
Chris Cain8b508bf2022-05-26 14:01:31 -0500540 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500541 lg2::error(
542 "getPldmInstanceId: Failed to alloc ID for TID {TID}. RC{RC}",
543 "TID", tid, "RC", rc);
Chris Cain8b508bf2022-05-26 14:01:31 -0500544 return false;
545 }
Rashmica Guptadb38e912023-05-25 10:33:46 +1000546 pldmInstanceID.emplace(id);
547 if (!throttleTraces)
548 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500549 lg2::info("got id {ID} and set PldmInstanceId to {INST}", "ID", id,
550 "INST", pldmInstanceID.value());
Rashmica Guptadb38e912023-05-25 10:33:46 +1000551 }
Patrick Williams05e95592021-09-02 09:28:14 -0500552 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500553 return true;
554}
Patrick Williams05e95592021-09-02 09:28:14 -0500555
Rashmica Guptadb38e912023-05-25 10:33:46 +1000556void Interface::freePldmInstanceId()
557{
558 if (pldmInstanceID)
559 {
560 int rc = pldm_instance_id_free(pldmInstanceIdDb, tid,
561 pldmInstanceID.value());
562 if (rc)
563 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500564 lg2::error(
565 "freePldmInstanceId: Failed to free ID {ID} for TID {TID}. RC{RC}",
566 "ID", pldmInstanceID.value(), "TID", tid, "RC", rc);
Rashmica Guptadb38e912023-05-25 10:33:46 +1000567 return;
568 }
569 if (!throttleTraces)
570 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500571 lg2::info("Freed PLDM instance ID {ID}", "ID",
572 pldmInstanceID.value());
Rashmica Guptadb38e912023-05-25 10:33:46 +1000573 }
574 pldmInstanceID = std::nullopt;
575 }
576}
577
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500578[[maybe_unused]] int Interface::openMctpDemuxTransport()
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100579{
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500580 impl.mctpDemux = nullptr;
581 int rc = pldm_transport_mctp_demux_init(&impl.mctpDemux);
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100582 if (rc)
583 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500584 lg2::error(
585 "openMctpDemuxTransport: Failed to init MCTP demux transport, errno={ERR}/{STR}",
586 "ERR", rc, "STR", strerror(rc));
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100587 return -1;
588 }
589
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500590 if (pldm_transport_mctp_demux_map_tid(impl.mctpDemux, mctpEid, mctpEid))
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100591 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500592 lg2::error(
593 "openMctpDemuxTransport: Failed to setup tid to eid mapping, errno={ERR}/{STR}",
594 "ERR", errno, "STR", strerror(errno));
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100595 pldmClose();
596 return -1;
597 }
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500598 pldmTransport = pldm_transport_mctp_demux_core(impl.mctpDemux);
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100599
600 struct pollfd pollfd;
601 if (pldm_transport_mctp_demux_init_pollfd(pldmTransport, &pollfd))
602 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500603 lg2::error(
604 "openMctpDemuxTransport: Failed to get pollfd , errno={ERR}/{STR}",
605 "ERR", errno, "STR", strerror(errno));
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100606 pldmClose();
607 return -1;
608 }
609 pldmFd = pollfd.fd;
610 if (!throttleTraces)
611 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500612 lg2::info("openMctpDemuxTransport: pldmFd has fd={FD}", "FD", pldmFd);
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100613 }
614 return 0;
615}
616
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500617[[maybe_unused]] int Interface::openAfMctpTransport()
618{
619 impl.afMctp = nullptr;
620 int rc = pldm_transport_af_mctp_init(&impl.afMctp);
621 if (rc)
622 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500623 lg2::error(
624 "openAfMctpTransport: Failed to init af MCTP transport, errno={ERR}/{STR}",
625 "ERR", rc, "STR", strerror(rc));
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500626 return -1;
627 }
628
629 if (pldm_transport_af_mctp_map_tid(impl.afMctp, mctpEid, mctpEid))
630 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500631 lg2::error(
632 "openAfMctpTransport: Failed to setup tid to eid mapping, errno={ERR}/{STR}",
633 "ERR", errno, "STR", strerror(errno));
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500634 pldmClose();
635 return -1;
636 }
637 pldmTransport = pldm_transport_af_mctp_core(impl.afMctp);
638
639 struct pollfd pollfd;
640 if (pldm_transport_af_mctp_init_pollfd(pldmTransport, &pollfd))
641 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500642 lg2::error(
643 "openAfMctpTransport: Failed to get pollfd , errno={ERR}/{STR}",
644 "ERR", errno, "STR", strerror(errno));
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500645 pldmClose();
646 return -1;
647 }
648 pldmFd = pollfd.fd;
649 if (!throttleTraces)
650 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500651 lg2::info("openAfMctpTransport: pldmFd has fd={FD}", "FD", pldmFd);
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500652 }
653 return 0;
654}
655
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100656int Interface::pldmOpen()
657{
658 if (pldmTransport)
659 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500660 lg2::error("pldmOpen: pldmTransport already setup!, errno={ERR}/{STR}",
661 "ERR", errno, "STR", strerror(errno));
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100662 return -1;
663 }
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500664#if defined(PLDM_TRANSPORT_WITH_MCTP_DEMUX)
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100665 return openMctpDemuxTransport();
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500666#elif defined(PLDM_TRANSPORT_WITH_AF_MCTP)
667 return openAfMctpTransport();
668#else
Chris Cain37abe9b2024-10-31 17:20:31 -0500669 lg2::error("pldmOpen: Undefined pldmTransport!, errno={ERR}/{STR}", "ERR",
670 errno, "STR", strerror(errno));
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500671 return -1;
672#endif
673
674 return 0;
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100675}
676
Chris Cainbae4d072022-02-28 09:46:50 -0600677void Interface::sendPldm(const std::vector<uint8_t>& request,
678 const uint8_t instance, const bool rspExpected)
Eddie Jamescbad2192021-10-07 09:39:39 -0500679{
Rashmica Guptaaeba51c2023-02-17 12:30:46 +1100680 if (!pldmInstanceID)
Chris Cain8b508bf2022-05-26 14:01:31 -0500681 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500682 lg2::error("sendPldm: No PLDM Instance ID found!");
Chris Cain8b508bf2022-05-26 14:01:31 -0500683 return;
684 }
685
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100686 auto rc = pldmOpen();
687 if (rc)
Patrick Williams05e95592021-09-02 09:28:14 -0500688 {
Eddie James88811ad2024-08-27 13:39:05 -0500689 if (!throttleTraces)
690 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500691 lg2::error("sendPldm: pldmOpen failed rc={RC}", "RC", rc);
Eddie James88811ad2024-08-27 13:39:05 -0500692 }
Rashmica Guptadb38e912023-05-25 10:33:46 +1000693 freePldmInstanceId();
Patrick Williams05e95592021-09-02 09:28:14 -0500694 return;
695 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500696
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100697 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEid);
Patrick Williams05e95592021-09-02 09:28:14 -0500698 // Send the PLDM request message to HBRT
Chris Cainbae4d072022-02-28 09:46:50 -0600699 if (rspExpected)
Patrick Williams05e95592021-09-02 09:28:14 -0500700 {
Chris Cainbae4d072022-02-28 09:46:50 -0600701 // Register callback when response is available
702 registerPldmRspCallback();
703
Chris Cainf0295f52024-09-12 15:41:14 -0500704 using namespace std::literals::chrono_literals;
705 std::chrono::duration timeout = 8s;
706 if ((msgType == MSG_OCC_RESET) || (msgType == MSG_HRESET))
707 {
708 timeout = 30s;
709 }
710
Chris Cainbae4d072022-02-28 09:46:50 -0600711 // Send PLDM request
Chris Cain755af102024-02-27 16:09:51 -0600712 if (!throttleTraces)
713 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500714 lg2::info("sendPldm: calling pldm_transport_send_msg(OCC{INST}, "
715 "instance:{ID}, {LEN} bytes, timeout {TO})",
716 "INST", instance, "ID", pldmInstanceID.value(), "LEN",
717 request.size(), "TO", timeout.count());
Chris Cain755af102024-02-27 16:09:51 -0600718 }
Chris Cainbae4d072022-02-28 09:46:50 -0600719 pldmResponseReceived = false;
720 pldmResponseTimeout = false;
721 pldmResponseOcc = instance;
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100722 auto pldmRc = pldm_transport_send_msg(pldmTransport, pldmTID,
723 request.data(), request.size());
Chris Cainbae4d072022-02-28 09:46:50 -0600724 auto sendErrno = errno;
725 if (pldmRc != PLDM_REQUESTER_SUCCESS)
726 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500727 lg2::error(
728 "sendPldm: pldm_transport_send_msg failed with rc={RC} and errno={ERR}/{STR}",
729 "RC",
730 static_cast<std::underlying_type_t<pldm_requester_error_codes>>(
731 pldmRc),
732 "ERR", sendErrno, "STR", strerror(sendErrno));
Chris Cainbae4d072022-02-28 09:46:50 -0600733 pldmClose();
734 return;
735 }
736
Chris Cainee364512025-04-16 16:08:34 -0500737 // Save header to confirm response matches
738 auto requestPtr = reinterpret_cast<const pldm_msg*>(&request[0]);
739 memcpy(&_requestHeader, requestPtr, sizeof(pldm_msg_hdr));
740
Chris Cainbae4d072022-02-28 09:46:50 -0600741 // start timer waiting for the response
Chris Cainf0295f52024-09-12 15:41:14 -0500742 pldmRspTimer.restartOnce(timeout);
Chris Cainbae4d072022-02-28 09:46:50 -0600743
744 // Wait for response/timeout
745 }
746 else // not expecting the response
747 {
Chris Cain755af102024-02-27 16:09:51 -0600748 if (!throttleTraces)
749 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500750 lg2::info(
751 "sendPldm: calling pldm_transport_send_msg(mctpID:{ID}, fd:{FD}, "
752 "{LEN} bytes) for OCC{INST}",
753 "ID", mctpEid, "FD", pldmFd, "LEN", request.size(), "INST",
754 instance);
Chris Cain755af102024-02-27 16:09:51 -0600755 }
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100756 auto rc = pldm_transport_send_msg(pldmTransport, pldmTID,
757 request.data(), request.size());
Chris Cainbae4d072022-02-28 09:46:50 -0600758 auto sendErrno = errno;
Chris Caind1b68262022-02-28 09:56:50 -0600759 if (rc)
760 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500761 lg2::error(
762 "sendPldm: pldm_transport_send_msg(mctpID:{ID}, fd:{FD}, {LEN} bytes) "
763 "failed with rc={RC} and errno={ERR}/{STR}",
764 "ID", mctpEid, "FD", pldmFd, "LEN", request.size(), "RC",
765 static_cast<std::underlying_type_t<pldm_requester_error_codes>>(
766 rc),
767 "ERR", sendErrno, "STR", strerror(sendErrno));
Chris Caind1b68262022-02-28 09:56:50 -0600768 }
Chris Cainbae4d072022-02-28 09:46:50 -0600769 pldmClose();
770 }
771}
Patrick Williams05e95592021-09-02 09:28:14 -0500772
Chris Cainbae4d072022-02-28 09:46:50 -0600773// Attaches the FD to event loop and registers the callback handler
774void Interface::registerPldmRspCallback()
775{
776 decltype(eventSource.get()) sourcePtr = nullptr;
Chris Cainf0295f52024-09-12 15:41:14 -0500777 int rc = 0;
778 if ((msgType == MSG_OCC_RESET) || (msgType == MSG_HRESET))
779 {
780 rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN,
781 pldmResetCallback, this);
782 }
783 else
784 {
785 rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN,
786 pldmRspCallback, this);
787 }
Chris Cainbae4d072022-02-28 09:46:50 -0600788 if (rc < 0)
789 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500790 lg2::error(
791 "registerPldmRspCallback: sd_event_add_io: Error({ERR})={STR} : fd={FD} (msgType={MSG})",
792 "ERR", rc, "STR", strerror(-rc), "FD", pldmFd, "MSG", msgType);
Chris Caind1b68262022-02-28 09:56:50 -0600793 }
794 else
Patrick Williams05e95592021-09-02 09:28:14 -0500795 {
Chris Cainbae4d072022-02-28 09:46:50 -0600796 // puts sourcePtr in the event source.
797 eventSource.reset(sourcePtr);
798 }
799}
800
801// Add a timer to the event loop, default 30s.
802void Interface::pldmRspExpired()
803{
804 if (!pldmResponseReceived)
805 {
Chris Cain755af102024-02-27 16:09:51 -0600806 if (!throttleTraces)
807 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500808 lg2::warning(
809 "pldmRspExpired: timerCallback - timeout waiting for pldm "
810 "response to msg:{MSG} for OCC{INST}",
811 "MSG", msgType, "INST", pldmResponseOcc);
Chris Cain755af102024-02-27 16:09:51 -0600812 }
Chris Cainbae4d072022-02-28 09:46:50 -0600813 pldmResponseTimeout = true;
814 if (pldmFd)
815 {
816 pldmClose();
817 }
Chris Cainf0295f52024-09-12 15:41:14 -0500818 if (msgType == MSG_OCC_RESET)
819 {
820 // reset not acked, try again
Chris Cain37abe9b2024-10-31 17:20:31 -0500821 lg2::error("pldmRspExpired: retrying reset request for OCC{INST}",
822 "INST", pldmResponseOcc);
Chris Cainf0295f52024-09-12 15:41:14 -0500823 resetOCC(pldmResponseOcc);
824 }
Chris Cainbae4d072022-02-28 09:46:50 -0600825 }
826 return;
827};
828
829void Interface::pldmClose()
830{
Rashmica Guptadb38e912023-05-25 10:33:46 +1000831 freePldmInstanceId();
Chris Cainbae4d072022-02-28 09:46:50 -0600832 if (pldmRspTimer.isEnabled())
833 {
834 // stop PLDM response timer
835 pldmRspTimer.setEnabled(false);
836 }
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100837
Lakshmi Yadlapati6213f192024-07-01 11:50:09 -0500838#if defined(PLDM_TRANSPORT_WITH_MCTP_DEMUX)
839 pldm_transport_mctp_demux_destroy(impl.mctpDemux);
840 impl.mctpDemux = NULL;
841#elif defined(PLDM_TRANSPORT_WITH_AF_MCTP)
842 pldm_transport_af_mctp_destroy(impl.afMctp);
843 impl.afMctp = NULL;
844#endif
Chris Cainbae4d072022-02-28 09:46:50 -0600845 pldmFd = -1;
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100846 pldmTransport = NULL;
Chris Cainbae4d072022-02-28 09:46:50 -0600847 eventSource.reset();
848}
849
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100850int Interface::pldmRspCallback(sd_event_source* /*es*/,
851 __attribute__((unused)) int fd, uint32_t revents,
852 void* userData)
Chris Cainbae4d072022-02-28 09:46:50 -0600853{
854 if (!(revents & EPOLLIN))
855 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500856 lg2::info("pldmRspCallback - revents={NUM}", "NUM", lg2::hex, revents);
Chris Cainbae4d072022-02-28 09:46:50 -0600857 return -1;
858 }
859
860 auto pldmIface = static_cast<Interface*>(userData);
861
Rashmica Guptaaeba51c2023-02-17 12:30:46 +1100862 if (!pldmIface->pldmInstanceID)
Chris Cain8b508bf2022-05-26 14:01:31 -0500863 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500864 lg2::error("pldmRspCallback: No outstanding PLDM Instance ID found");
Chris Cain8b508bf2022-05-26 14:01:31 -0500865 return -1;
866 }
867
Chris Cainbae4d072022-02-28 09:46:50 -0600868 uint8_t* responseMsg = nullptr;
869 size_t responseMsgSize{};
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100870 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEid);
Chris Cainbae4d072022-02-28 09:46:50 -0600871
Chris Cain755af102024-02-27 16:09:51 -0600872 if (!throttleTraces)
873 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500874 lg2::info(
875 "pldmRspCallback: calling pldm_transport_recv_msg() instance:{INST}",
876 "INST", pldmIface->pldmInstanceID.value());
Chris Cain755af102024-02-27 16:09:51 -0600877 }
Rashmica Gupta52328cb2023-02-15 10:38:16 +1100878 auto rc = pldm_transport_recv_msg(pldmIface->pldmTransport, &pldmTID,
879 (void**)&responseMsg, &responseMsgSize);
Chris Cainbae4d072022-02-28 09:46:50 -0600880 int lastErrno = errno;
Chris Cainee364512025-04-16 16:08:34 -0500881 if (rc != PLDM_REQUESTER_SUCCESS)
Chris Cainbae4d072022-02-28 09:46:50 -0600882 {
Chris Cain755af102024-02-27 16:09:51 -0600883 if (!throttleTraces)
884 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500885 lg2::error(
886 "pldmRspCallback: pldm_transport_recv_msg failed with rc={RC}, errno={ERR}/{STR}",
887 "RC",
888 static_cast<std::underlying_type_t<pldm_requester_error_codes>>(
889 rc),
890 "ERR", lastErrno, "STR", strerror(lastErrno));
Chris Cain755af102024-02-27 16:09:51 -0600891 }
Chris Cainbae4d072022-02-28 09:46:50 -0600892 return -1;
893 }
Chris Cain8b508bf2022-05-26 14:01:31 -0500894
Chris Cainee364512025-04-16 16:08:34 -0500895 // Verify the response header matches our request
896 struct pldm_msg_hdr* hdr = (struct pldm_msg_hdr*)responseMsg;
897 if ((pldmTID != mctpEid) ||
898 !pldm_msg_hdr_correlate_response(&pldmIface->_requestHeader, hdr))
899 {
900 // We got a response to someone else's message. Ignore it.
901 return 0;
902 }
903
Chris Cain8b508bf2022-05-26 14:01:31 -0500904 // We got the response for the PLDM request msg that was sent
Chris Cain755af102024-02-27 16:09:51 -0600905 if (!throttleTraces)
906 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500907 lg2::info(
908 "pldmRspCallback: pldm_transport_recv_msg() rsp was {LEN} bytes",
909 "LEN", responseMsgSize);
Chris Cain755af102024-02-27 16:09:51 -0600910 }
Chris Cainbae4d072022-02-28 09:46:50 -0600911
912 if (pldmIface->pldmRspTimer.isEnabled())
913 {
914 // stop PLDM response timer
915 pldmIface->pldmRspTimer.setEnabled(false);
916 }
917
Chris Cain92dfb272025-02-13 12:20:27 -0600918 // instance ID will get freed on pldmClose()
Chris Cain8b508bf2022-05-26 14:01:31 -0500919
Chris Cainbae4d072022-02-28 09:46:50 -0600920 // Set pointer to autodelete
Patrick Williamsd7542c82024-08-16 15:20:28 -0400921 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{
922 responseMsg, std::free};
Chris Cainbae4d072022-02-28 09:46:50 -0600923
Chris Cainbae4d072022-02-28 09:46:50 -0600924 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
925 if (response->payload[0] != PLDM_SUCCESS)
926 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500927 lg2::error("pldmRspCallback: payload[0] was not success: {STATUS}",
928 "STATUS", response->payload[0]);
Chris Cainbae4d072022-02-28 09:46:50 -0600929 pldmIface->pldmClose();
930 return -1;
931 }
932
933 // Decode the response
934 uint8_t compCode = 0, sensorCount = 1;
935 get_sensor_state_field field[6];
936 responseMsgSize -= sizeof(pldm_msg_hdr);
937 auto msgRc = decode_get_state_sensor_readings_resp(
938 response, responseMsgSize, &compCode, &sensorCount, field);
939 if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS))
940 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500941 lg2::error(
942 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={RC} and compCode={CC}",
943 "RC", msgRc, "CC", compCode);
Chris Cainbae4d072022-02-28 09:46:50 -0600944 pldmIface->pldmClose();
945 return -1;
946 }
947
948 pldmIface->pldmClose();
949
950 const uint8_t instance = pldmIface->pldmResponseOcc;
951 const uint8_t occSensorState = field[0].present_state;
952 pldmIface->pldmResponseReceived = true;
953
954 if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)
955 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500956 lg2::info("pldmRspCallback: OCC{INST} is RUNNING", "INST", instance);
Chris Cainf0295f52024-09-12 15:41:14 -0500957 pldmIface->occActiveCallBack(instance, true);
Chris Cainbae4d072022-02-28 09:46:50 -0600958 }
Chris Cain733b2012022-05-04 11:54:06 -0500959 else if (occSensorState ==
960 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT)
961 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500962 lg2::error(
963 "pldmRspCallback: OCC{INST} has now STOPPED and system is in SAFE MODE",
964 "INST", instance);
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500965
966 // Setting safe mode true
967 pldmIface->safeModeCallBack(true);
968
Chris Cainf0295f52024-09-12 15:41:14 -0500969 pldmIface->occActiveCallBack(instance, false);
Chris Cain733b2012022-05-04 11:54:06 -0500970 }
Chris Cain755af102024-02-27 16:09:51 -0600971 else if (occSensorState ==
972 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED)
Chris Cainbae4d072022-02-28 09:46:50 -0600973 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500974 lg2::info("pldmRspCallback: OCC{INST} is not running", "INST",
975 instance);
Chris Cainf0295f52024-09-12 15:41:14 -0500976 pldmIface->occActiveCallBack(instance, false);
Chris Cain755af102024-02-27 16:09:51 -0600977 }
978 else
979 {
980 const size_t rspLength = responseMsgSize + sizeof(pldm_msg_hdr);
981 std::vector<std::uint8_t> pldmResponse(rspLength);
982 memcpy(&pldmResponse[0], reinterpret_cast<std::uint8_t*>(response),
983 rspLength);
984 if (!throttleTraces)
Chris Cainc9dc4412023-03-06 15:56:34 -0600985 {
Chris Cain37abe9b2024-10-31 17:20:31 -0500986 lg2::warning(
987 "pldmRspCallback: Unexpected State: {STATE} - PLDM response "
988 "({LEN} bytes) for OCC{INST}:",
989 "STATE", occSensorState, "LEN", rspLength, "INST", instance);
Chris Cainc9dc4412023-03-06 15:56:34 -0600990 dump_hex(pldmResponse);
991 }
Chris Cainbae4d072022-02-28 09:46:50 -0600992 }
993
994 return 0;
995};
996
Chris Cainf0295f52024-09-12 15:41:14 -0500997int Interface::pldmResetCallback(sd_event_source* /*es*/,
998 __attribute__((unused)) int fd,
999 uint32_t revents, void* userData)
1000{
1001 if (!(revents & EPOLLIN))
1002 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001003 lg2::info("pldmResetCallback - revents={NUM}", "NUM", lg2::hex,
1004 revents);
Chris Cainf0295f52024-09-12 15:41:14 -05001005 return -1;
1006 }
1007
1008 auto pldmIface = static_cast<Interface*>(userData);
1009
1010 if (!pldmIface->pldmInstanceID)
1011 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001012 lg2::error("pldmResetCallback: No outstanding PLDM Instance ID found");
Chris Cainf0295f52024-09-12 15:41:14 -05001013 return -1;
1014 }
1015
1016 uint8_t* responseMsg = nullptr;
1017 size_t responseMsgSize{};
1018 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEid);
1019
1020 if (!throttleTraces)
1021 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001022 lg2::info(
1023 "pldmResetCallback: calling pldm_transport_recv_msg() instance:{ID}",
1024 "ID", pldmIface->pldmInstanceID.value());
Chris Cainf0295f52024-09-12 15:41:14 -05001025 }
1026 auto rc = pldm_transport_recv_msg(pldmIface->pldmTransport, &pldmTID,
1027 (void**)&responseMsg, &responseMsgSize);
1028 int lastErrno = errno;
Chris Cainee364512025-04-16 16:08:34 -05001029 if (rc != PLDM_REQUESTER_SUCCESS)
Chris Cainf0295f52024-09-12 15:41:14 -05001030 {
1031 if (!throttleTraces)
1032 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001033 lg2::error(
1034 "pldmResetCallback: pldm_transport_recv_msg failed with rc={RC}, errno={ERR}/{STR}",
1035 "RC",
1036 static_cast<std::underlying_type_t<pldm_requester_error_codes>>(
1037 rc),
1038 "ERR", lastErrno, "STR", strerror(lastErrno));
Chris Cainf0295f52024-09-12 15:41:14 -05001039 }
1040 return -1;
1041 }
1042
Chris Cainee364512025-04-16 16:08:34 -05001043 // Verify the response header matches our request
1044 struct pldm_msg_hdr* hdr = (struct pldm_msg_hdr*)responseMsg;
1045 if ((pldmTID != mctpEid) ||
1046 !pldm_msg_hdr_correlate_response(&pldmIface->_requestHeader, hdr))
1047 {
1048 // We got a response to someone else's message. Ignore it.
1049 return 0;
1050 }
1051
Chris Cainf0295f52024-09-12 15:41:14 -05001052 // We got the response for the PLDM request msg that was sent
1053 if (!throttleTraces)
1054 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001055 lg2::info(
1056 "pldmResetCallback: pldm_transport_recv_msg() rsp was {LEN} bytes",
1057 "LEN", responseMsgSize);
Chris Cainf0295f52024-09-12 15:41:14 -05001058 }
1059
1060 if (pldmIface->pldmRspTimer.isEnabled())
1061 {
1062 // stop PLDM response timer
1063 pldmIface->pldmRspTimer.setEnabled(false);
1064 }
1065
Chris Cain92dfb272025-02-13 12:20:27 -06001066 // instance ID will get freed on pldmClose()
Chris Cainf0295f52024-09-12 15:41:14 -05001067
1068 // Set pointer to autodelete
1069 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{
1070 responseMsg, std::free};
1071
1072 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
1073 if (response->payload[0] != PLDM_SUCCESS)
1074 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001075 lg2::error(
1076 "pldmResetCallback: Reset FAILED ({MSG}) - payload[0] was not success: {STATUS}",
1077 "MSG", msgType, "STATUS", response->payload[0]);
Chris Cainf0295f52024-09-12 15:41:14 -05001078 pldmIface->pldmClose();
1079
1080 if (msgType == MSG_OCC_RESET)
1081 {
1082 // Retry reset request
Chris Cain37abe9b2024-10-31 17:20:31 -05001083 lg2::error(
1084 "pldmResetCallback: retrying reset request for OCC{INST}",
1085 "INST", resetInstance);
Chris Cainf0295f52024-09-12 15:41:14 -05001086 pldmIface->resetOCC(resetInstance);
1087 }
1088 return -1;
1089 }
1090 else
1091 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001092 lg2::info("pldmResetCallback: Reset has been successfully started");
Chris Cainf0295f52024-09-12 15:41:14 -05001093 }
1094
1095 pldmIface->pldmClose();
1096
1097 pldmIface->pldmResponseReceived = true;
1098
1099 return 0;
1100}
1101
Patrick Williams2d6ec902025-02-01 08:22:13 -05001102std::vector<uint8_t> Interface::encodeGetStateSensorRequest(uint8_t instance,
1103 uint16_t sensorId)
Chris Cainbae4d072022-02-28 09:46:50 -06001104{
Rashmica Guptaaeba51c2023-02-17 12:30:46 +11001105 if (!getPldmInstanceId())
Chris Cain8b508bf2022-05-26 14:01:31 -05001106 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001107 lg2::error("encodeGetStateSensorRequest: failed to getPldmInstanceId");
Chris Cain8b508bf2022-05-26 14:01:31 -05001108 return std::vector<uint8_t>();
1109 }
1110
Chris Cainbae4d072022-02-28 09:46:50 -06001111 bitfield8_t sRearm = {0};
Patrick Williamsd7542c82024-08-16 15:20:28 -04001112 const size_t msgSize =
1113 sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES;
Chris Cainbae4d072022-02-28 09:46:50 -06001114 std::vector<uint8_t> request(msgSize);
Chris Cain8b508bf2022-05-26 14:01:31 -05001115
Chris Cainbae4d072022-02-28 09:46:50 -06001116 auto msg = reinterpret_cast<pldm_msg*>(request.data());
Rashmica Guptaaeba51c2023-02-17 12:30:46 +11001117 auto msgRc = encode_get_state_sensor_readings_req(pldmInstanceID.value(),
Chris Cain8b508bf2022-05-26 14:01:31 -05001118 sensorId, sRearm, 0, msg);
Chris Cainbae4d072022-02-28 09:46:50 -06001119 if (msgRc != PLDM_SUCCESS)
1120 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001121 lg2::error(
1122 "encodeGetStateSensorRequest: Failed to encode sensorId:{ID} for OCC{INST} (rc={RC})",
1123 "ID", lg2::hex, sensorId, "INST", instance, "RC", msgRc);
Chris Cainbae4d072022-02-28 09:46:50 -06001124 }
1125 return request;
1126}
1127
1128// Initiate query of the specified OCC Active Sensor
1129void Interface::checkActiveSensor(uint8_t instance)
1130{
1131 static bool tracedOnce = false;
1132 if (pldmFd > 0)
1133 {
Chris Cain755af102024-02-27 16:09:51 -06001134 if (!throttleTraces && !tracedOnce)
Chris Caind1b68262022-02-28 09:56:50 -06001135 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001136 lg2::warning(
1137 "checkActiveSensor: already waiting on OCC{INST} (fd={FD})",
1138 "INST", pldmResponseOcc, "FD", pldmFd);
Chris Cainbae4d072022-02-28 09:46:50 -06001139 tracedOnce = true;
Chris Caind1b68262022-02-28 09:56:50 -06001140 }
Chris Cainbae4d072022-02-28 09:46:50 -06001141 return;
1142 }
1143 tracedOnce = false;
1144
1145 if (!isOCCSensorCacheValid())
1146 {
1147 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
1148 sensorToOCCInstance, OCCSensorOffset);
1149 }
1150
1151 // look up sensor id (key) based on instance
1152 auto entry = std::find_if(
1153 sensorToOCCInstance.begin(), sensorToOCCInstance.end(),
1154 [instance](const auto& entry) { return instance == entry.second; });
1155 if (entry != sensorToOCCInstance.end())
1156 {
1157 // Query the OCC Active Sensor state for this instance
Chris Cain755af102024-02-27 16:09:51 -06001158 if (!throttleTraces)
1159 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001160 lg2::info("checkActiveSensor: OCC{INST} / sensorID: {ID}", "INST",
1161 instance, "ID", lg2::hex, entry->first);
Chris Cain755af102024-02-27 16:09:51 -06001162 }
Chris Cainbae4d072022-02-28 09:46:50 -06001163
Chris Cainbae4d072022-02-28 09:46:50 -06001164 // Encode GetStateSensorReadings PLDM message
1165 auto request = encodeGetStateSensorRequest(instance, entry->first);
1166 if (request.empty())
1167 {
1168 return;
1169 }
1170
1171 // Send request to PLDM and setup callback for response
Chris Cainf0295f52024-09-12 15:41:14 -05001172 msgType = MSG_SENSOR_STATUS;
Chris Cainbae4d072022-02-28 09:46:50 -06001173 sendPldm(request, instance, true);
1174 }
1175 else
1176 {
Chris Cain755af102024-02-27 16:09:51 -06001177 if (!throttleTraces)
1178 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001179 lg2::error(
1180 "checkActiveSensor: Unable to find PLDM sensor for OCC{INST}",
1181 "INST", instance);
1182 lg2::info(
Chris Cain755af102024-02-27 16:09:51 -06001183 "checkActiveSensor: fetching STATE_SET_OPERATIONAL_RUNNING_STATUS");
1184 }
Chris Cain8cf74962022-06-29 08:45:16 -05001185 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
1186 sensorToOCCInstance, OCCSensorOffset);
Patrick Williams05e95592021-09-02 09:28:14 -05001187 }
Patrick Williams05e95592021-09-02 09:28:14 -05001188}
1189
Chris Cain755af102024-02-27 16:09:51 -06001190void Interface::setTraceThrottle(const bool throttle)
1191{
1192 if (throttle != throttleTraces)
1193 {
1194 if (throttle)
1195 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001196 lg2::warning("PLDM traces being throttled");
Chris Cain755af102024-02-27 16:09:51 -06001197 }
1198 else
1199 {
Chris Cain37abe9b2024-10-31 17:20:31 -05001200 lg2::info("PLDM traces no longer being throttled");
Chris Cain755af102024-02-27 16:09:51 -06001201 }
1202 throttleTraces = throttle;
1203 }
1204}
1205
Patrick Williams05e95592021-09-02 09:28:14 -05001206} // namespace pldm