xref: /openbmc/phosphor-logging/extensions/openpower-pels/pldm_interface.hpp (revision b0ff05abe3946dd7a5cb2e9cd3e53aec299d9034)
1 #pragma once
2 
3 #include "host_interface.hpp"
4 
5 #include <libpldm/instance-id.h>
6 #include <libpldm/pldm.h>
7 #include <libpldm/transport.h>
8 #include <libpldm/transport/mctp-demux.h>
9 
10 #include <sdeventplus/clock.hpp>
11 #include <sdeventplus/source/io.hpp>
12 #include <sdeventplus/utility/timer.hpp>
13 
14 #include <chrono>
15 #include <memory>
16 
17 namespace openpower::pels
18 {
19 
20 /**
21  * @class PLDMInterface
22  *
23  * This class handles sending the 'new file available' PLDM
24  * command to the host to notify it of a new PEL's ID and size.
25  *
26  * The command response is asynchronous.
27  */
28 class PLDMInterface : public HostInterface
29 {
30   public:
31     PLDMInterface() = delete;
32     PLDMInterface(const PLDMInterface&) = default;
33     PLDMInterface& operator=(const PLDMInterface&) = default;
34     PLDMInterface(PLDMInterface&&) = default;
35     PLDMInterface& operator=(PLDMInterface&&) = default;
36 
37     /**
38      * @brief Constructor
39      *
40      * @param[in] event - The sd_event object pointer
41      * @param[in] dataIface - The DataInterface object
42      */
PLDMInterface(sd_event * event,DataInterfaceBase & dataIface)43     PLDMInterface(sd_event* event, DataInterfaceBase& dataIface) :
44         HostInterface(event, dataIface),
45         _receiveTimer(
46             event,
47             std::bind(std::mem_fn(&PLDMInterface::receiveTimerExpired), this))
48     {
49         pldm_instance_db_init_default(&_pldm_idb);
50 
51         readEID();
52     }
53 
54     /**
55      * @brief Destructor
56      */
57     ~PLDMInterface();
58 
59     /**
60      * @brief Kicks off the send of the 'new file available' command
61      *        to send up the ID and size of the new PEL.
62      *
63      * It starts by issuing the async D-Bus method call to read the
64      * instance ID.
65      *
66      * @param[in] id - The PEL ID
67      * @param[in] size - The PEL size in bytes
68      *
69      * @return CmdStatus - the success/fail status of the send
70      */
71     CmdStatus sendNewLogCmd(uint32_t id, uint32_t size) override;
72 
73     /**
74      * @brief Cancels waiting for a command response
75      *
76      * This will clear the instance ID so the next command
77      * will request a new one.
78      */
79     void cancelCmd() override;
80 
81     /**
82      * @brief Cleans up so that a new command is ready to be sent.
83      *
84      * Does not clear the instance ID.
85      */
86     void cleanupCmd();
87 
88   private:
89     /**
90      * @brief The asynchronous callback for getting the response
91      *        of the 'new file available' command.
92      *
93      * Calls the response callback that is registered.
94      *
95      * @param[in] io - The event source object
96      * @param[in] fd - The FD used
97      * @param[in] revents - The event bits
98      * @param[in] transport - The transport data pointer
99      */
100     void receive(sdeventplus::source::IO& io, int fd, uint32_t revents,
101                  pldm_transport* transport) override;
102 
103     /**
104      * @brief Function called when the receive timer expires.
105      *
106      * This is considered a failure and so will invoke the
107      * registered response callback function with a failure
108      * indication.
109      */
110     void receiveTimerExpired();
111 
112     /**
113      * @brief Configures the sdeventplus::source::IO object to
114      *        call receive() on EPOLLIN activity on the PLDM FD
115      *        which is used for command responses.
116      */
117     void registerReceiveCallback();
118 
119     /**
120      * @brief Reads the MCTP endpoint ID out of a file
121      */
122     void readEID();
123 
124     /**
125      * @brief Opens the PLDM file descriptor
126      */
127     void open();
128 
129     /** @brief Opens the MCTP socket for sending and receiving messages.
130      *
131      */
132     int openMctpDemuxTransport();
133 
134     /**
135      * @brief Encodes and sends the PLDM 'new file available' cmd
136      */
137     void doSend();
138 
139     /**
140      * @brief Closes the PLDM file descriptor
141      */
142     void closeFD();
143 
144     /**
145      * @brief Kicks off the send of the 'new file available' command
146      *        to send the ID and size of a PEL after the instance ID
147      *        has been retrieved.
148      */
149     void startCommand();
150 
151     /**
152      * @brief Allocates the instance id.
153      */
154     void allocIID();
155 
156     /**
157      * @brief Frees the instance id.
158      */
159     void freeIID();
160 
161     /**
162      * @brief The MCTP endpoint ID
163      */
164     mctp_eid_t _eid;
165 
166     /**
167      * @brief The PLDM instance ID of the current command
168      *
169      * A new ID will be used for every command.
170      *
171      * If there are command failures, the same instance ID can be
172      * used on retries only if the host didn't respond.
173      */
174     std::optional<pldm_instance_id_t> _instanceID;
175 
176     /**
177      * @brief The PLDM command file descriptor for the current command
178      */
179     int _fd = -1;
180 
181     /**
182      * @brief The event object for handling callbacks on the PLDM FD
183      */
184     std::unique_ptr<sdeventplus::source::IO> _source;
185 
186     /**
187      * @brief A timer to only allow a certain amount of time for the
188      *        async PLDM receive before it is considered a failure.
189      */
190     sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _receiveTimer;
191 
192     /**
193      * @brief The command timeout value
194      */
195     const std::chrono::milliseconds _receiveTimeout{45000};
196 
197     /**
198      * @brief The libpldm instance ID database.
199      */
200     pldm_instance_db* _pldm_idb = nullptr;
201 
202     /**
203      * @brief The ID of the PEL to notify the host of.
204      */
205     uint32_t _pelID = 0;
206 
207     /**
208      * @brief The size of the PEL to notify the host of.
209      */
210     uint32_t _pelSize = 0;
211 
212     /**
213      * @brief pldm transport instance.
214      */
215     pldm_transport* pldmTransport = nullptr;
216 
217     pldm_transport_mctp_demux* mctpDemux = nullptr;
218 };
219 
220 } // namespace openpower::pels
221