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