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