xref: /openbmc/openpower-occ-control/pldm.hpp (revision c488bac124fbbcb0dbe83e48922c3087a5aaa7bd)
1 #pragma once
2 
3 #include "occ_events.hpp"
4 #include "occ_status.hpp"
5 #include "utils.hpp"
6 
7 #include <libpldm/instance-id.h>
8 #include <libpldm/pldm.h>
9 #include <libpldm/transport.h>
10 #include <libpldm/transport/af-mctp.h>
11 #include <libpldm/transport/mctp-demux.h>
12 
13 #include <sdbusplus/bus/match.hpp>
14 #include <sdeventplus/event.hpp>
15 #include <sdeventplus/utility/timer.hpp>
16 
17 enum pldm_msg_type
18 {
19     MSG_UNDEFINED = 0,
20     MSG_SENSOR_STATUS = 1,
21     MSG_OCC_RESET = 2,
22     MSG_HRESET = 3
23 };
24 
25 namespace pldm
26 {
27 
28 namespace MatchRules = sdbusplus::bus::match::rules;
29 using namespace open_power::occ;
30 
31 using CompositeEffecterCount = uint8_t;
32 using EffecterID = uint16_t;
33 using EntityType = uint16_t;
34 using EntityInstance = uint16_t;
35 using EventState = uint8_t;
36 using InstanceToEffecter = std::map<open_power::occ::instanceID, EffecterID>;
37 using PdrList = std::vector<std::vector<uint8_t>>;
38 using SensorID = uint16_t;
39 using SensorOffset = uint8_t;
40 using SensorToInstance = std::map<SensorID, open_power::occ::instanceID>;
41 using TerminusID = uint8_t;
42 
43 /** @brief OCC instance starts with 0 for example "occ0" */
44 constexpr open_power::occ::instanceID start = 0;
45 
46 /** @brief Hardcoded mctpEid for HBRT */
47 constexpr mctp_eid_t mctpEid = 10;
48 
49 /** @brief Hardcoded TID */
50 constexpr TerminusID tid = mctpEid;
51 
52 /** @class Interface
53  *
54  *  @brief Abstracts the PLDM details related to the OCC
55  */
56 class Interface
57 {
58   public:
59     Interface() = delete;
60     //~Interface() = default;
61     Interface(const Interface&) = delete;
62     Interface& operator=(const Interface&) = delete;
63     Interface(Interface&&) = delete;
64     Interface& operator=(Interface&&) = delete;
65 
66     /** @brief Constructs the PLDM Interface object for OCC functions
67      *
68      *  @param[in] occActiveCallBack - callBack handler to invoke when the OCC
69      *                                 state changes.
70      *  @param[in] sbeCallBack       - callBack handler to invoke when the SBE
71      *                                 state changes.
72      *  @param[in] safeModeCallBack  - callBack handler to invoke when the
73      *                                 system is in safe mode.
74      *  @param[in] poweredOffCallBack - callBack handler to invoke when the
75      *                                 host is powered off.
76      */
Interface(std::function<bool (open_power::occ::instanceID,bool)> occActiveCallBack,std::function<void (open_power::occ::instanceID,bool)> sbeCallBack,std::function<void (bool)> safeModeCallBack,std::function<void ()> poweredOffCallBack,EventPtr & event)77     explicit Interface(
78         std::function<bool(open_power::occ::instanceID, bool)>
79             occActiveCallBack,
80         std::function<void(open_power::occ::instanceID, bool)> sbeCallBack,
81         std::function<void(bool)> safeModeCallBack,
82         std::function<void()> poweredOffCallBack, EventPtr& event) :
83         occActiveCallBack(occActiveCallBack), sbeCallBack(sbeCallBack),
84         safeModeCallBack(safeModeCallBack),
85         poweredOffCallBack(poweredOffCallBack), event(event),
86         pldmEventSignal(
87             open_power::occ::utils::getBus(),
88             MatchRules::type::signal() +
89                 MatchRules::member("StateSensorEvent") +
90                 MatchRules::path("/xyz/openbmc_project/pldm") +
91                 MatchRules::interface("xyz.openbmc_project.PLDM.Event"),
92             std::bind(std::mem_fn(&Interface::sensorEvent), this,
93                       std::placeholders::_1)),
94         hostStateSignal(
95             open_power::occ::utils::getBus(),
96             MatchRules::propertiesChanged("/xyz/openbmc_project/state/host0",
97                                           "xyz.openbmc_project.State.Host"),
98             std::bind(std::mem_fn(&Interface::hostStateEvent), this,
99                       std::placeholders::_1)),
100         sdpEvent(sdeventplus::Event::get_default()),
101         pldmRspTimer(
102             sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>(
103                 sdpEvent, std::bind(&Interface::pldmRspExpired, this)))
104     {
105         int rc = pldm_instance_db_init_default(&pldmInstanceIdDb);
106         if (rc)
107         {
108             throw std::system_category().default_error_condition(rc);
109         }
110     }
111 
~Interface()112     ~Interface()
113     {
114         int rc = pldm_instance_db_destroy(pldmInstanceIdDb);
115         if (rc)
116         {
117             std::cout << "pldm_instance_db_destroy failed, rc =" << rc << "\n";
118         }
119     }
120 
121     /** @brief Fetch the state sensor PDRs and populate the cache with
122      *         sensorId to OCC/SBE instance mapping information and the sensor
123      *         offset for the relevent state set.
124      *
125      *  @param[in] stateSetId - the state set ID to look for
126      *  @param[out] sensorInstanceMap - map of sensorID to instance
127      *  @param[out] sensorOffset - sensor offset of interested state set ID
128      */
129     void fetchSensorInfo(uint16_t stateSetId,
130                          SensorToInstance& sensorInstanceMap,
131                          SensorOffset& sensorOffset);
132 
133     /** @brief Fetch the OCC/SBE state effecter PDRs and populate the cache
134      *         with OCC/SBE instance to EffecterID information.
135      *
136      *  @param[in] stateSetId - the state set ID to look for
137      *  @param[out] instanceToEffecterMap - map of instance to effecterID
138      *  @param[out] count - sensor offset of interested state set ID
139      *  @param[out] stateIdPos - position of the stateSetID
140      */
141     void fetchEffecterInfo(uint16_t stateSetId,
142                            InstanceToEffecter& instanceToEffecterMap,
143                            CompositeEffecterCount& count, uint8_t& stateIdPos);
144 
145     /** @brief Prepare the request for SetStateEffecterStates command
146      *
147      *  @param[in] effecterId - the instance effecter ID
148      *  @param[in] effecterCount - compositeEffecterCount for the effecter PDR
149      *  @param[in] stateIdPos - position of the stateSetID
150      *  @param[in] stateSetValue - the value to set the state set to
151      *
152      *  @return PLDM request message to be sent to host for OCC reset or SBE
153      *          HRESET, empty response in the case of failure.
154      */
155     std::vector<uint8_t> prepareSetEffecterReq(
156         EffecterID effecterId, CompositeEffecterCount effecterCount,
157         uint8_t stateIdPos, uint8_t stateSetValue);
158 
159     /** @brief Send the PLDM message to reset the OCC
160      *
161      *  @param[in] instanceId - OCC instance to reset
162      *
163      */
164     void resetOCC(open_power::occ::instanceID occInstanceId);
165 
166     /** @brief Send the PLDM message to perform the HRESET
167      *
168      *  @param[in] instanceID - SBE instance to HRESET
169      */
170     void sendHRESET(open_power::occ::instanceID sbeInstanceId);
171 
172     /** @brief Check if the OCC active sensor is available
173      *         On successful read, the Manager callback will be called to update
174      *         the status
175      *
176      *  @param[in] instance  - OCC instance to check
177      */
178     void checkActiveSensor(uint8_t instance);
179 
180     /** @brief Set the throttleTraces flag
181      *
182      * @param[in] throttle - Flag to indicate if traces should be throttled
183      */
184     void setTraceThrottle(const bool throttle);
185 
186   private:
187     /** @brief PLDM instance ID database object used to get instance IDs
188      */
189     pldm_instance_db* pldmInstanceIdDb = nullptr;
190 
191     /** @brief PLDM instance number used in PLDM requests
192      */
193     std::optional<uint8_t> pldmInstanceID;
194 
195     /** @brief Callback handler to be invoked when the state of the OCC
196      *         changes
197      */
198     std::function<bool(open_power::occ::instanceID, bool)> occActiveCallBack =
199         nullptr;
200 
201     /** @brief Callback handler to be invoked when the maintenance state of the
202      *         SBE changes
203      */
204     std::function<void(open_power::occ::instanceID, bool)> sbeCallBack =
205         nullptr;
206 
207     /** @brief Callback handler to be invoked when the OCC is in SAFE Mode =
208      *         true or when OCCs are in_service = false.
209      */
210     std::function<void(bool)> safeModeCallBack = nullptr;
211 
212     /** @brief Callback handler to be invoked when the host is powered off */
213     std::function<void()> poweredOffCallBack = nullptr;
214 
215     /** @brief reference to sd_event wrapped in unique_ptr */
216     EventPtr& event;
217 
218     /** @brief event source wrapped in unique_ptr */
219     EventSourcePtr eventSource;
220 
221     /** @brief Used to subscribe to D-Bus PLDM StateSensorEvent signal and
222      *         processes if the event corresponds to OCC state change.
223      */
224     sdbusplus::bus::match_t pldmEventSignal;
225 
226     /** @brief Used to subscribe for host state change signal */
227     sdbusplus::bus::match_t hostStateSignal;
228 
229     /** @brief PLDM Sensor ID to OCC Instance mapping
230      */
231     SensorToInstance sensorToOCCInstance;
232 
233     /** @brief PLDM Sensor ID to SBE Instance mapping
234      */
235     SensorToInstance sensorToSBEInstance;
236 
237     /** @brief Sensor offset of OCC state set ID
238      * PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS in state sensor PDR.
239      */
240     SensorOffset OCCSensorOffset = 0;
241 
242     /** @brief Sensor offset of the SBE state set ID
243      * PLDM_OEM_IBM_SBE_HRESET_STATE in state sensor PDR.
244      */
245     SensorOffset SBESensorOffset = 0;
246 
247     /** @brief OCC Instance mapping to PLDM Effecter ID
248      */
249     InstanceToEffecter occInstanceToEffecter;
250 
251     /** @brief SBE instance mapping to PLDM Effecter ID
252      */
253     InstanceToEffecter sbeInstanceToEffecter;
254 
255     /** @brief compositeEffecterCount for OCC reset state effecter PDR */
256     CompositeEffecterCount OCCEffecterCount = 0;
257 
258     /** @brief compositeEffecterCount for SBE HRESET state effecter PDR */
259     CompositeEffecterCount SBEEffecterCount = 0;
260 
261     /** @brief Position of Boot/Restart Cause stateSetID in OCC state
262      *         effecter PDR
263      */
264     uint8_t bootRestartPosition = 0;
265 
266     /** @brief Position of the SBE maintenance stateSetID in the state
267      *         effecter PDR
268      */
269     uint8_t sbeMaintenanceStatePosition = 0;
270 
271     /** @brief OCC instance number for the PLDM message */
272     uint8_t pldmResponseOcc = 0;
273 
274     /** @brief File descriptor for PLDM messages */
275     int pldmFd = -1;
276 
277     /** pldm transport instance  */
278     struct pldm_transport* pldmTransport = NULL;
279 
280     static enum pldm_msg_type msgType;
281 
282     union TransportImpl
283     {
284         struct pldm_transport_mctp_demux* mctpDemux;
285         struct pldm_transport_af_mctp* afMctp;
286     };
287 
288     TransportImpl impl;
289 
290     /** @brief The response for the PLDM request msg is received flag.
291      */
292     bool pldmResponseReceived = false;
293 
294     /** @brief The response for the PLDM request has timed out.
295      */
296     bool pldmResponseTimeout = false;
297 
298     /** @brief The instance ID for the OCC/HRESET request */
299     static open_power::occ::instanceID resetInstance;
300 
301     /** @brief timer event */
302     sdeventplus::Event sdpEvent;
303 
304     /** @brief Timer that is started when PLDM command is sent
305      */
306     sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> pldmRspTimer;
307 
308     std::set<uint8_t> outstandingHResets;
309 
310     /** @brief Flag to indicate that traces should be throttled.
311                Used to limit traces when there are issues getting OCC status.
312      */
313     static bool throttleTraces;
314 
315     /** @brief Callback when PLDM response has not been received within the
316      * timeout period.
317      */
318     void pldmRspExpired();
319 
320     /** @brief Close the MCTP file */
321     void pldmClose();
322 
323     /** @brief When the OCC state changes host sends PlatformEventMessage
324      *         StateSensorEvent, this function processes the D-Bus signal
325      *         with the sensor event information and invokes the callback
326      *         to change the OCC state.
327      *
328      *  @param[in] msg - data associated with the subscribed signal
329      */
330     void sensorEvent(sdbusplus::message_t& msg);
331 
332     /** @brief When the host state changes and if the CurrentHostState is
333      *         xyz.openbmc_project.State.Host.HostState.Off then
334      *         the cache of OCC sensors and effecters mapping is cleared.
335      *
336      *  @param[in] msg - data associated with the subscribed signal
337      */
338     void hostStateEvent(sdbusplus::message_t& msg);
339 
340     /** @brief Called when it is determined that the Host is not running.
341      *         The cache of OCC sensors and effecters mapping is cleared.
342      */
343     void clearData();
344 
345     /** @brief Check if the PDR cache for PLDM OCC sensors is valid
346      *
347      *  @return true if cache is populated and false if the cache is not
348      *          populated.
349      */
isOCCSensorCacheValid()350     auto isOCCSensorCacheValid()
351     {
352         return (sensorToOCCInstance.empty() ? false : true);
353     }
354 
355     /** @brief Check if the PDR cache for PLDM OCC effecters is valid
356      *
357      *  @return true if cache is populated and false if the cache is not
358      *          populated.
359      */
isPDREffecterCacheValid()360     auto isPDREffecterCacheValid()
361     {
362         return (occInstanceToEffecter.empty() ? false : true);
363     }
364 
365     /** @brief Get a PLDM requester instance id
366      *
367      * @return true if the id was found and false if not
368      */
369     bool getPldmInstanceId();
370 
371     /** @brief Free PLDM requester instance id */
372     void freePldmInstanceId();
373 
374     /** @brief Encode a GetStateSensor command into a PLDM request
375      *  @param[in] instance - OCC instance number
376      *  @param[in] sensorId - OCC Active sensor ID number
377      *
378      *  @return request - The encoded PLDM messsage to be sent
379      */
380     std::vector<uint8_t> encodeGetStateSensorRequest(uint8_t instance,
381                                                      uint16_t sensorId);
382 
383     /** @brief setup PLDM transport for sending and receiving PLDM messages.
384      *
385      * @return true on success, otherwise return false
386      */
387     int pldmOpen(void);
388 
389     /** @brief Opens the MCTP socket for sending and receiving messages.
390      *
391      * @return 0 on success, otherwise returns a negative error code
392      */
393     int openMctpDemuxTransport();
394 
395     /** @brief Opens the MCTP AF_MCTP for sending and receiving messages.
396      *
397      * @return 0 on success, otherwise returns a negative error code
398      */
399     int openAfMctpTransport();
400 
401     /** @brief Send the PLDM request
402      *
403      * @param[in] request - the request data
404      * @param[in] rspExpected - false: no need to wait for the response
405      *                          true: will need to process response in callback
406      */
407     void sendPldm(const std::vector<uint8_t>& request, const uint8_t instance,
408                   const bool rspExpected = false);
409 
410     /** @brief Register a callback function to handle the PLDM response */
411     void registerPldmRspCallback();
412 
413     /** @brief callback for the PLDM response event
414      *
415      *  @param[in] es       - Populated event source
416      *  @param[in] fd       - Associated File descriptor
417      *  @param[in] revents  - Type of event
418      *  @param[in] userData - User data that was passed during registration
419      *
420      *  @return             - 0 or positive number on success and negative
421      *                        errno otherwise
422      */
423     static int pldmRspCallback(sd_event_source* es, int fd, uint32_t revents,
424                                void* userData);
425 
426     /** @brief callback for a OCC / HRESET response event
427      *
428      *  @param[in] es       - Populated event source
429      *  @param[in] fd       - Associated File descriptor
430      *  @param[in] revents  - Type of event
431      *  @param[in] userData - User data that was passed during registration
432      *
433      *  @return             - 0 or positive number on success and negative
434      *                        errno otherwise
435      */
436     static int pldmResetCallback(sd_event_source* /*es*/,
437                                  __attribute__((unused)) int fd,
438                                  uint32_t revents, void* userData);
439 };
440 
441 } // namespace pldm
442 
443 template <>
444 struct std::formatter<enum pldm_msg_type> : formatter<int>
445 {
formatstd::formatter446     auto format(enum pldm_msg_type m, format_context& ctx) const
447     {
448         return formatter<int>::format(std::to_underlying(m), ctx);
449     }
450 };
451