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