1 #pragma once
2 
3 #include "data_interface.hpp"
4 
5 #include <libpldm/transport.h>
6 #include <stdint.h>
7 
8 #include <phosphor-logging/lg2.hpp>
9 #include <sdeventplus/event.hpp>
10 #include <sdeventplus/source/io.hpp>
11 
12 #include <chrono>
13 #include <functional>
14 
15 namespace openpower
16 {
17 namespace pels
18 {
19 
20 /**
21  * @brief Return codes from sending a command
22  */
23 enum class CmdStatus
24 {
25     success,
26     failure
27 };
28 
29 /**
30  * @brief Return codes from the command response
31  */
32 enum class ResponseStatus
33 {
34     success,
35     failure
36 };
37 
38 /**
39  * @class HostInterface
40  *
41  * An abstract base class for sending the 'New PEL available' command
42  * to the host.  Used so that the PLDM interfaces can be mocked for
43  * testing the HostNotifier code.  The response to this command is
44  * asynchronous, with the intent that other code registers a callback
45  * function to run when the response is received.
46  */
47 class HostInterface
48 {
49   public:
50     HostInterface() = delete;
51     virtual ~HostInterface() = default;
52     HostInterface(const HostInterface&) = default;
53     HostInterface& operator=(const HostInterface&) = default;
54     HostInterface(HostInterface&&) = default;
55     HostInterface& operator=(HostInterface&&) = default;
56 
57     /**
58      * @brief Constructor
59      *
60      * @param[in] event - The sd_event object pointer
61      * @param[in] dataIface - The DataInterface object
62      */
HostInterface(sd_event * event,DataInterfaceBase & dataIface)63     HostInterface(sd_event* event, DataInterfaceBase& dataIface) :
64         _event(event), _dataIface(dataIface)
65     {}
66 
67     /**
68      * @brief Pure virtual function for sending the 'new PEL available'
69      *        asynchronous command to the host.
70      *
71      * @param[in] id - The ID of the new PEL
72      * @param[in] size - The size of the new PEL
73      *
74      * @return CmdStatus - If the send was successful or not
75      */
76     virtual CmdStatus sendNewLogCmd(uint32_t id, uint32_t size) = 0;
77 
78     /**
79      * @brief Returns the amount of time to wait before retrying after
80      *        a failed send command.
81      *
82      * @return milliseconds - The amount of time to wait
83      */
getSendRetryDelay() const84     virtual std::chrono::milliseconds getSendRetryDelay() const
85     {
86         return _defaultSendRetryDelay;
87     }
88 
89     /**
90      * @brief Returns the amount of time to wait before retrying after
91      *        a command receive.
92      *
93      * @return milliseconds - The amount of time to wait
94      */
getReceiveRetryDelay() const95     virtual std::chrono::milliseconds getReceiveRetryDelay() const
96     {
97         return _defaultReceiveRetryDelay;
98     }
99 
100     /**
101      * @brief Returns the amount of time to wait before retrying if the
102      *        host firmware's PEL storage was full and it can't store
103      *        any more logs until it is freed up somehow.
104      *
105      * In this class to help with mocking.
106      *
107      * @return milliseconds - The amount of time to wait
108      */
getHostFullRetryDelay() const109     virtual std::chrono::milliseconds getHostFullRetryDelay() const
110     {
111         return _defaultHostFullRetryDelay;
112     }
113 
114     /**
115      * @brief Returns the amount of time to wait after the host is up
116      *        before sending commands.
117      *
118      * In this class to help with mocking.
119      *
120      * @return milliseconds - The amount of time to wait
121      */
getHostUpDelay() const122     virtual std::chrono::milliseconds getHostUpDelay() const
123     {
124         return _defaultHostUpDelay;
125     }
126 
127     using ResponseFunction = std::function<void(ResponseStatus)>;
128 
129     /**
130      * @brief Sets the function to call on the command receive.
131      *
132      * The success/failure status is passed to the function.
133      *
134      * @param[in] func - The callback function
135      */
setResponseFunction(ResponseFunction func)136     void setResponseFunction(ResponseFunction func)
137     {
138         _responseFunc = std::move(func);
139     }
140 
141     /**
142      * @brief Call the response function
143      *
144      * @param[in] status - The status given to the function
145      */
callResponseFunc(ResponseStatus status)146     void callResponseFunc(ResponseStatus status)
147     {
148         if (_responseFunc)
149         {
150             try
151             {
152                 (*_responseFunc)(status);
153             }
154             catch (const std::exception& e)
155             {
156                 lg2::error(
157                     "Host iface response callback threw an exception: {EX}",
158                     "EX", e);
159             }
160         }
161     }
162 
163     /**
164      * @brief Returns the event object in use
165      *
166      * @return sdeventplus::Event& - The event object
167      */
getEvent()168     sdeventplus::Event& getEvent()
169     {
170         return _event;
171     }
172 
173     /**
174      * @brief Pure virtual function to cancel an in-progress command
175      *
176      * 'In progress' means after the send but before the receive
177      */
178     virtual void cancelCmd() = 0;
179 
180     /**
181      * @brief Says if the command is in progress (after send/before receive)
182      *
183      * @return bool - If command is in progress
184      */
cmdInProgress() const185     bool cmdInProgress() const
186     {
187         return _inProgress;
188     }
189 
190   protected:
191     /**
192      * @brief Pure virtual function for implementing the asynchronous
193      *        command response callback.
194      *
195      * @param[in] io - The sdeventplus IO object that the callback is
196      *                 invoked from.
197      * @param[in] fd - The file descriptor being used
198      * @param[in] revents - The event status bits
199      * @param[in] transport - The transport data pointer
200      */
201     virtual void receive(sdeventplus::source::IO& io, int fd, uint32_t revents,
202                          pldm_transport* transport) = 0;
203 
204     /**
205      * @brief An optional function to call on a successful command response.
206      */
207     std::optional<ResponseFunction> _responseFunc;
208 
209     /**
210      * @brief The sd_event wrapper object needed for response callbacks
211      */
212     sdeventplus::Event _event;
213 
214     /**
215      * @brief The DataInterface object
216      */
217     DataInterfaceBase& _dataIface;
218 
219     /**
220      * @brief Tracks status of after a command is sent and before the
221      *        response is received.
222      */
223     bool _inProgress = false;
224 
225   private:
226     /**
227      * @brief The default amount of time to wait before retrying
228      *        a failed send.
229      */
230     const std::chrono::milliseconds _defaultSendRetryDelay{1000};
231 
232     /**
233      * @brief The default amount of time to wait
234      *        before retrying after a failed receive.
235      */
236     const std::chrono::milliseconds _defaultReceiveRetryDelay{1000};
237 
238     /**
239      * @brief The default amount of time to wait when the host said it
240      *        was full before sending the PEL again.
241      */
242     const std::chrono::milliseconds _defaultHostFullRetryDelay{60000};
243 
244     /**
245      * @brief The default amount of time to wait after the host is up
246      *        before sending up the PELs.
247      */
248     const std::chrono::milliseconds _defaultHostUpDelay{60000};
249 };
250 
251 } // namespace pels
252 } // namespace openpower
253