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