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