blob: 01eac48c952bec7b426674932b88e646e4841eb9 [file] [log] [blame]
Matt Spinlerf60ac272019-12-11 13:47:50 -06001#pragma once
2
3#include "host_interface.hpp"
4#include "pel.hpp"
5#include "repository.hpp"
6
7#include <deque>
Matt Spinlerf869fcf2019-12-11 15:02:20 -06008#include <sdeventplus/clock.hpp>
Matt Spinler7d800a42019-12-12 10:35:01 -06009#include <sdeventplus/source/event.hpp>
Matt Spinlerf869fcf2019-12-11 15:02:20 -060010#include <sdeventplus/utility/timer.hpp>
Matt Spinlerf60ac272019-12-11 13:47:50 -060011
12namespace openpower::pels
13{
14
15/**
16 * @class HostNotifier
17 *
18 * This class handles notifying the host firmware of new PELs.
19 */
20class HostNotifier
21{
22 public:
23 HostNotifier() = delete;
24 HostNotifier(const HostNotifier&) = delete;
25 HostNotifier& operator=(const HostNotifier&) = delete;
26 HostNotifier(HostNotifier&&) = delete;
27 HostNotifier& operator=(HostNotifier&&) = delete;
28
29 /**
30 * @brief Constructor
31 *
32 * @param[in] repo - The PEL repository object
33 * @param[in] dataIface - The data interface object
34 * @param[in] hostIface - The host interface object
35 */
36 HostNotifier(Repository& repo, DataInterfaceBase& dataIface,
37 std::unique_ptr<HostInterface> hostIface);
38
39 /**
40 * @brief Destructor
41 */
42 ~HostNotifier();
43
44 /**
45 * @brief Returns the PEL queue size.
46 *
47 * For testing.
48 *
49 * @return size_t - The queue size
50 */
51 size_t queueSize() const
52 {
53 return _pelQueue.size();
54 }
55
56 /**
57 * @brief Specifies if the PEL needs to go onto the queue to be
58 * set to the host.
59 *
Matt Spinlera943b152019-12-11 14:44:50 -060060 * Only returns false if:
61 * - Already acked by the host (or they didn't like it)
62 * - Hidden and the HMC already got it
63 * - The 'do not report to host' bit is set
64 *
Matt Spinlerf60ac272019-12-11 13:47:50 -060065 * @param[in] id - The PEL ID
66 *
67 * @return bool - If enqueue is required
68 */
69 bool enqueueRequired(uint32_t id) const;
70
Matt Spinlerf77debb2019-12-12 10:04:33 -060071 /**
72 * @brief If the host still needs to be notified of the PEL
73 * at the time of the notification.
74 *
75 * Only returns false if:
76 * - Already acked by the host
77 * - It's hidden, and the HMC already got or will get it.
78 *
79 * @param[in] id - The PEL ID
80 *
81 * @return bool - If the notify is required
82 */
83 bool notifyRequired(uint32_t id) const;
84
Matt Spinlercc3b64a2019-12-12 11:27:10 -060085 /**
86 * @brief Called when the host sends the 'ack' PLDM command.
87 *
88 * This means the PEL never needs to be sent up again.
89 *
Matt Spinler41293cb2019-12-12 13:11:09 -060090 * If the host was previously full, it is also an indication
91 * it no longer is.
92 *
Matt Spinlercc3b64a2019-12-12 11:27:10 -060093 * @param[in] id - The PEL ID
94 */
95 void ackPEL(uint32_t id);
96
Matt Spinler41293cb2019-12-12 13:11:09 -060097 /**
98 * @brief Called when the host does not have room for more
99 * PELs at this time.
100 *
101 * This can happen when an OS isn't running yet, and the
102 * staging area to hold the PELs before sending them up
103 * to the OS is full. This will stop future PEls from being
104 * sent up, as explained below.
105 *
106 * The PEL with this ID will need to be sent again, so its
107 * state is set back to 'new', and it is removed from the list
108 * of already sent PELs.
109 *
110 * A timer will be started, if it isn't already running, to
111 * issue another send in the hopes that space has been freed
112 * up by then (Receiving an ackPEL response is also an
113 * indication of this if there happened to have been other
114 * PELs in flight).
115 *
116 * @param[in] id - The PEL ID
117 */
118 void setHostFull(uint32_t id);
119
Matt Spinlera19b6232019-12-12 13:30:14 -0600120 /**
121 * @brief Called when the host receives a malformed PEL.
122 *
123 * Ideally this will never happen, as the Repository
124 * class already purges malformed PELs.
125 *
126 * The PEL should never be sent up again.
127 *
128 * @param[in] id - The PEL ID
129 */
130 void setBadPEL(uint32_t id);
131
Matt Spinlerf60ac272019-12-11 13:47:50 -0600132 private:
133 /**
134 * @brief This function gets called by the Repository class
135 * when a new PEL is added to it.
136 *
Matt Spinler7d800a42019-12-12 10:35:01 -0600137 * This function puts the PEL on the queue to be sent up if it
138 * needs it, and possibly dispatch the send if the conditions call
139 * for it.
140 *
Matt Spinlerf60ac272019-12-11 13:47:50 -0600141 * @param[in] pel - The new PEL
142 */
143 void newLogCallback(const PEL& pel);
144
145 /**
146 * @brief This function runs on every existing PEL at startup
147 * and puts the PEL on the queue to send if necessary.
148 *
149 * @param[in] pel - The PEL
150 *
151 * @return bool - This is an indicator to the Repository::for_each
152 * function to traverse every PEL. Always false.
153 */
154 bool addPELToQueue(const PEL& pel);
155
156 /**
Matt Spinlerf77debb2019-12-12 10:04:33 -0600157 * @brief Takes the first PEL from the queue that needs to be
158 * sent, and issues the send if conditions are right.
Matt Spinlerf60ac272019-12-11 13:47:50 -0600159 */
160 void doNewLogNotify();
161
162 /**
Matt Spinler7d800a42019-12-12 10:35:01 -0600163 * @brief Creates the event object to handle sending the PLDM
164 * command from the event loop.
165 */
166 void scheduleDispatch();
167
168 /**
169 * @brief Kicks off the PLDM send, but called from the event
170 * loop.
171 *
172 * @param[in] source - The event source object
173 */
174 void dispatch(sdeventplus::source::EventBase& source);
175
176 /**
Matt Spinlerf60ac272019-12-11 13:47:50 -0600177 * @brief Called when the host changes state.
178 *
Matt Spinler3019c6f2019-12-11 15:24:45 -0600179 * If the new state is host up and there are PELs to send, it
180 * will trigger the first command. If the new state is off, then
181 * it will transfer any PELs that were sent but not acked yet back
182 * to the queue to be sent again.
183 *
Matt Spinlerf60ac272019-12-11 13:47:50 -0600184 * @param[in] hostUp - The new host state
185 */
186 void hostStateChange(bool hostUp);
187
188 /**
189 * @brief The callback function invoked after the asynchronous
190 * PLDM receive function is complete.
191 *
Matt Spinlerf869fcf2019-12-11 15:02:20 -0600192 * If the command was successful, the state of that PEL will
193 * be set to 'sent', and the next send will be triggered.
194 *
195 * If the command failed, a retry timer will be started so it
196 * can be sent again.
197 *
Matt Spinlerf60ac272019-12-11 13:47:50 -0600198 * @param[in] status - The response status
199 */
200 void commandResponse(ResponseStatus status);
201
202 /**
Matt Spinlerf869fcf2019-12-11 15:02:20 -0600203 * @brief The function called when the command failure retry
204 * time is up.
205 *
206 * It will issue a send of the previous PEL and increment the
207 * retry count.
208 */
209 void retryTimerExpired();
210
211 /**
Matt Spinler41293cb2019-12-12 13:11:09 -0600212 * @brief The function called when the 'host full' retry timer
213 * expires.
214 *
215 * This will re-issue a command to try again with the PEL at
216 * the front of the queue.
217 */
218 void hostFullTimerExpired();
219
220 /**
Matt Spinler3019c6f2019-12-11 15:24:45 -0600221 * @brief Stops an in progress command
222 *
223 * In progress meaning after the send but before the response.
224 */
225 void stopCommand();
226
227 /**
Matt Spinlerf60ac272019-12-11 13:47:50 -0600228 * @brief The PEL repository object
229 */
230 Repository& _repo;
231
232 /**
233 * @brief The data interface object
234 */
235 DataInterfaceBase& _dataIface;
236
237 /**
238 * @brief Base class pointer for the host command interface
239 */
240 std::unique_ptr<HostInterface> _hostIface;
241
242 /**
243 * @brief The list of PEL IDs that need to be sent.
244 */
245 std::deque<uint32_t> _pelQueue;
Matt Spinlerf869fcf2019-12-11 15:02:20 -0600246
247 /**
248 * @brief The list of IDs that were sent, but not acked yet.
249 *
250 * These move back to _pelQueue on a power off.
251 */
252 std::vector<uint32_t> _sentPELs;
253
254 /**
255 * @brief The ID the PEL where the notification has
256 * been kicked off but the asynchronous response
257 * hasn't been received yet.
258 */
259 uint32_t _inProgressPEL = 0;
260
261 /**
262 * @brief The command retry count
263 */
264 size_t _retryCount = 0;
265
266 /**
Matt Spinler41293cb2019-12-12 13:11:09 -0600267 * @brief Indicates if the host has said it is full and does not
268 * currently have the space for more PELs.
269 */
270 bool _hostFull = false;
271
272 /**
Matt Spinlerf869fcf2019-12-11 15:02:20 -0600273 * @brief The command retry timer.
274 */
275 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _retryTimer;
Matt Spinler7d800a42019-12-12 10:35:01 -0600276
277 /**
Matt Spinler41293cb2019-12-12 13:11:09 -0600278 * @brief The host full timer, used to retry sending a PEL if the host
279 * said it is full.
280 */
281 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _hostFullTimer;
282
283 /**
Matt Spinler7d800a42019-12-12 10:35:01 -0600284 * @brief The object used to dispatch a new PEL send from the
285 * event loop, so the calling function can be returned from
286 * first.
287 */
288 std::unique_ptr<sdeventplus::source::Defer> _dispatcher;
Matt Spinlerf60ac272019-12-11 13:47:50 -0600289};
290
291} // namespace openpower::pels