1f60ac27eSMatt Spinler /**
2f60ac27eSMatt Spinler  * Copyright © 2019 IBM Corporation
3f60ac27eSMatt Spinler  *
4f60ac27eSMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
5f60ac27eSMatt Spinler  * you may not use this file except in compliance with the License.
6f60ac27eSMatt Spinler  * You may obtain a copy of the License at
7f60ac27eSMatt Spinler  *
8f60ac27eSMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
9f60ac27eSMatt Spinler  *
10f60ac27eSMatt Spinler  * Unless required by applicable law or agreed to in writing, software
11f60ac27eSMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
12f60ac27eSMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f60ac27eSMatt Spinler  * See the License for the specific language governing permissions and
14f60ac27eSMatt Spinler  * limitations under the License.
15f60ac27eSMatt Spinler  */
16f60ac27eSMatt Spinler #include "host_notifier.hpp"
17f60ac27eSMatt Spinler 
18f60ac27eSMatt Spinler #include <phosphor-logging/log.hpp>
19f60ac27eSMatt Spinler 
20f60ac27eSMatt Spinler namespace openpower::pels
21f60ac27eSMatt Spinler {
22f60ac27eSMatt Spinler 
23f60ac27eSMatt Spinler const auto subscriptionName = "PELHostNotifier";
24f77debb9SMatt Spinler const size_t maxRetryAttempts = 15;
25f60ac27eSMatt Spinler 
26f60ac27eSMatt Spinler using namespace phosphor::logging;
27f60ac27eSMatt Spinler 
28f60ac27eSMatt Spinler HostNotifier::HostNotifier(Repository& repo, DataInterfaceBase& dataIface,
29f60ac27eSMatt Spinler                            std::unique_ptr<HostInterface> hostIface) :
30f60ac27eSMatt Spinler     _repo(repo),
31f869fcf8SMatt Spinler     _dataIface(dataIface), _hostIface(std::move(hostIface)),
32f869fcf8SMatt Spinler     _retryTimer(_hostIface->getEvent(),
3341293cb8SMatt Spinler                 std::bind(std::mem_fn(&HostNotifier::retryTimerExpired), this)),
3441293cb8SMatt Spinler     _hostFullTimer(
3541293cb8SMatt Spinler         _hostIface->getEvent(),
3641293cb8SMatt Spinler         std::bind(std::mem_fn(&HostNotifier::hostFullTimerExpired), this))
37f60ac27eSMatt Spinler {
38f60ac27eSMatt Spinler     // Subscribe to be told about new PELs.
39f60ac27eSMatt Spinler     _repo.subscribeToAdds(subscriptionName,
40f60ac27eSMatt Spinler                           std::bind(std::mem_fn(&HostNotifier::newLogCallback),
41f60ac27eSMatt Spinler                                     this, std::placeholders::_1));
42f60ac27eSMatt Spinler 
43f60ac27eSMatt Spinler     // Add any existing PELs to the queue to send them if necessary.
44f60ac27eSMatt Spinler     _repo.for_each(std::bind(std::mem_fn(&HostNotifier::addPELToQueue), this,
45f60ac27eSMatt Spinler                              std::placeholders::_1));
46f60ac27eSMatt Spinler 
47f60ac27eSMatt Spinler     // Subscribe to be told about host state changes.
48f60ac27eSMatt Spinler     _dataIface.subscribeToHostStateChange(
49f60ac27eSMatt Spinler         subscriptionName,
50f60ac27eSMatt Spinler         std::bind(std::mem_fun(&HostNotifier::hostStateChange), this,
51f60ac27eSMatt Spinler                   std::placeholders::_1));
52f60ac27eSMatt Spinler 
53f60ac27eSMatt Spinler     // Set the function to call when the async reponse is received.
54f60ac27eSMatt Spinler     _hostIface->setResponseFunction(
55f60ac27eSMatt Spinler         std::bind(std::mem_fn(&HostNotifier::commandResponse), this,
56f60ac27eSMatt Spinler                   std::placeholders::_1));
57f60ac27eSMatt Spinler 
58f60ac27eSMatt Spinler     // Start sending logs if the host is running
59f60ac27eSMatt Spinler     if (!_pelQueue.empty() && _dataIface.isHostUp())
60f60ac27eSMatt Spinler     {
61f60ac27eSMatt Spinler         doNewLogNotify();
62f60ac27eSMatt Spinler     }
63f60ac27eSMatt Spinler }
64f60ac27eSMatt Spinler 
65f60ac27eSMatt Spinler HostNotifier::~HostNotifier()
66f60ac27eSMatt Spinler {
67f60ac27eSMatt Spinler     _repo.unsubscribeFromAdds(subscriptionName);
68f60ac27eSMatt Spinler     _dataIface.unsubscribeFromHostStateChange(subscriptionName);
69f60ac27eSMatt Spinler }
70f60ac27eSMatt Spinler 
71f60ac27eSMatt Spinler bool HostNotifier::addPELToQueue(const PEL& pel)
72f60ac27eSMatt Spinler {
73f60ac27eSMatt Spinler     if (enqueueRequired(pel.id()))
74f60ac27eSMatt Spinler     {
75f60ac27eSMatt Spinler         _pelQueue.push_back(pel.id());
76f60ac27eSMatt Spinler     }
77f60ac27eSMatt Spinler 
78f60ac27eSMatt Spinler     // Return false so that Repo::for_each keeps going.
79f60ac27eSMatt Spinler     return false;
80f60ac27eSMatt Spinler }
81f60ac27eSMatt Spinler 
82f60ac27eSMatt Spinler bool HostNotifier::enqueueRequired(uint32_t id) const
83f60ac27eSMatt Spinler {
84f60ac27eSMatt Spinler     bool required = true;
85a943b15bSMatt Spinler     Repository::LogID i{Repository::LogID::Pel{id}};
86a943b15bSMatt Spinler 
8724a8558bSMatt Spinler     // Manufacturing testing may turn off sending up PELs
8824a8558bSMatt Spinler     if (!_dataIface.getHostPELEnablement())
8924a8558bSMatt Spinler     {
9024a8558bSMatt Spinler         return false;
9124a8558bSMatt Spinler     }
9224a8558bSMatt Spinler 
93a943b15bSMatt Spinler     if (auto attributes = _repo.getPELAttributes(i); attributes)
94a943b15bSMatt Spinler     {
95a943b15bSMatt Spinler         auto a = attributes.value().get();
96a943b15bSMatt Spinler 
97a943b15bSMatt Spinler         if ((a.hostState == TransmissionState::acked) ||
98a943b15bSMatt Spinler             (a.hostState == TransmissionState::badPEL))
99a943b15bSMatt Spinler         {
100a943b15bSMatt Spinler             required = false;
101a943b15bSMatt Spinler         }
102a943b15bSMatt Spinler         else if (a.actionFlags.test(hiddenFlagBit) &&
103a943b15bSMatt Spinler                  (a.hmcState == TransmissionState::acked))
104a943b15bSMatt Spinler         {
105a943b15bSMatt Spinler             required = false;
106a943b15bSMatt Spinler         }
107a943b15bSMatt Spinler         else if (a.actionFlags.test(dontReportToHostFlagBit))
108a943b15bSMatt Spinler         {
109a943b15bSMatt Spinler             required = false;
110a943b15bSMatt Spinler         }
111a943b15bSMatt Spinler     }
112a943b15bSMatt Spinler     else
113a943b15bSMatt Spinler     {
114a943b15bSMatt Spinler         using namespace phosphor::logging;
115a943b15bSMatt Spinler         log<level::ERR>("Host Enqueue: Unable to find PEL ID in repository",
116a943b15bSMatt Spinler                         entry("PEL_ID=0x%X", id));
117a943b15bSMatt Spinler         required = false;
118a943b15bSMatt Spinler     }
119f60ac27eSMatt Spinler 
120f60ac27eSMatt Spinler     return required;
121f60ac27eSMatt Spinler }
122f60ac27eSMatt Spinler 
123f77debb9SMatt Spinler bool HostNotifier::notifyRequired(uint32_t id) const
124f77debb9SMatt Spinler {
125f77debb9SMatt Spinler     bool notify = true;
126f77debb9SMatt Spinler     Repository::LogID i{Repository::LogID::Pel{id}};
127f77debb9SMatt Spinler 
128f77debb9SMatt Spinler     if (auto attributes = _repo.getPELAttributes(i); attributes)
129f77debb9SMatt Spinler     {
130f77debb9SMatt Spinler         // If already acked by the host, don't send again.
131f77debb9SMatt Spinler         // (A safety check as it shouldn't get to this point.)
132f77debb9SMatt Spinler         auto a = attributes.value().get();
133f77debb9SMatt Spinler         if (a.hostState == TransmissionState::acked)
134f77debb9SMatt Spinler         {
135f77debb9SMatt Spinler             notify = false;
136f77debb9SMatt Spinler         }
137f77debb9SMatt Spinler         else if (a.actionFlags.test(hiddenFlagBit))
138f77debb9SMatt Spinler         {
139f77debb9SMatt Spinler             // If hidden and acked (or will be) acked by the HMC,
140f77debb9SMatt Spinler             // also don't send it. (HMC management can come and
141f77debb9SMatt Spinler             // go at any time)
142f77debb9SMatt Spinler             if ((a.hmcState == TransmissionState::acked) ||
143f77debb9SMatt Spinler                 _dataIface.isHMCManaged())
144f77debb9SMatt Spinler             {
145f77debb9SMatt Spinler                 notify = false;
146f77debb9SMatt Spinler             }
147f77debb9SMatt Spinler         }
148f77debb9SMatt Spinler     }
149f77debb9SMatt Spinler     else
150f77debb9SMatt Spinler     {
151f77debb9SMatt Spinler         // Must have been deleted since put on the queue.
152f77debb9SMatt Spinler         notify = false;
153f77debb9SMatt Spinler     }
154f77debb9SMatt Spinler 
155f77debb9SMatt Spinler     return notify;
156f77debb9SMatt Spinler }
157f77debb9SMatt Spinler 
158f60ac27eSMatt Spinler void HostNotifier::newLogCallback(const PEL& pel)
159f60ac27eSMatt Spinler {
160f60ac27eSMatt Spinler     if (!enqueueRequired(pel.id()))
161f60ac27eSMatt Spinler     {
162f60ac27eSMatt Spinler         return;
163f60ac27eSMatt Spinler     }
164f60ac27eSMatt Spinler 
165f60ac27eSMatt Spinler     _pelQueue.push_back(pel.id());
166f60ac27eSMatt Spinler 
16741293cb8SMatt Spinler     // Notify shouldn't happen if host is down or full
16841293cb8SMatt Spinler     if (!_dataIface.isHostUp() || _hostFull)
1697d800a4eSMatt Spinler     {
1707d800a4eSMatt Spinler         return;
1717d800a4eSMatt Spinler     }
1727d800a4eSMatt Spinler 
1737d800a4eSMatt Spinler     // Dispatch a command now if there isn't currently a command
1747d800a4eSMatt Spinler     // in progress and this is the first log in the queue or it
1757d800a4eSMatt Spinler     // previously gave up from a hard failure.
1767d800a4eSMatt Spinler     auto inProgress = (_inProgressPEL != 0) || _hostIface->cmdInProgress() ||
1777d800a4eSMatt Spinler                       _retryTimer.isEnabled();
1787d800a4eSMatt Spinler 
1797d800a4eSMatt Spinler     auto firstPEL = _pelQueue.size() == 1;
1807d800a4eSMatt Spinler     auto gaveUp = _retryCount >= maxRetryAttempts;
1817d800a4eSMatt Spinler 
1827d800a4eSMatt Spinler     if (!inProgress && (firstPEL || gaveUp))
1837d800a4eSMatt Spinler     {
1847d800a4eSMatt Spinler         _retryCount = 0;
1857d800a4eSMatt Spinler 
1867d800a4eSMatt Spinler         // Send a log, but from the event loop, not from here.
1877d800a4eSMatt Spinler         scheduleDispatch();
1887d800a4eSMatt Spinler     }
1897d800a4eSMatt Spinler }
1907d800a4eSMatt Spinler 
1917d800a4eSMatt Spinler void HostNotifier::scheduleDispatch()
1927d800a4eSMatt Spinler {
1937d800a4eSMatt Spinler     _dispatcher = std::make_unique<sdeventplus::source::Defer>(
1947d800a4eSMatt Spinler         _hostIface->getEvent(), std::bind(std::mem_fn(&HostNotifier::dispatch),
1957d800a4eSMatt Spinler                                           this, std::placeholders::_1));
1967d800a4eSMatt Spinler }
1977d800a4eSMatt Spinler 
1987d800a4eSMatt Spinler void HostNotifier::dispatch(sdeventplus::source::EventBase& source)
1997d800a4eSMatt Spinler {
2007d800a4eSMatt Spinler     _dispatcher.reset();
2017d800a4eSMatt Spinler 
2027d800a4eSMatt Spinler     doNewLogNotify();
203f60ac27eSMatt Spinler }
204f60ac27eSMatt Spinler 
205f60ac27eSMatt Spinler void HostNotifier::doNewLogNotify()
206f60ac27eSMatt Spinler {
20741293cb8SMatt Spinler     if (!_dataIface.isHostUp() || _retryTimer.isEnabled() ||
20841293cb8SMatt Spinler         _hostFullTimer.isEnabled())
209f77debb9SMatt Spinler     {
210f77debb9SMatt Spinler         return;
211f77debb9SMatt Spinler     }
212f77debb9SMatt Spinler 
213f77debb9SMatt Spinler     if (_retryCount >= maxRetryAttempts)
214f77debb9SMatt Spinler     {
215f77debb9SMatt Spinler         // Give up until a new log comes in.
216f77debb9SMatt Spinler         if (_retryCount == maxRetryAttempts)
217f77debb9SMatt Spinler         {
218f77debb9SMatt Spinler             // If this were to really happen, the PLDM interface
219f77debb9SMatt Spinler             // would be down and isolating that shouldn't left to
220f77debb9SMatt Spinler             // a logging daemon, so just trace.  Also, this will start
221f77debb9SMatt Spinler             // trying again when the next new log comes in.
222f77debb9SMatt Spinler             log<level::ERR>(
223f77debb9SMatt Spinler                 "PEL Host notifier hit max retry attempts. Giving up for now.",
224f77debb9SMatt Spinler                 entry("PEL_ID=0x%X", _pelQueue.front()));
225*829b052dSMatt Spinler 
226*829b052dSMatt Spinler             // Tell the host interface object to clean itself up, especially to
227*829b052dSMatt Spinler             // release the PLDM instance ID it's been using.
228*829b052dSMatt Spinler             _hostIface->cancelCmd();
229f77debb9SMatt Spinler         }
230f77debb9SMatt Spinler         return;
231f77debb9SMatt Spinler     }
232f77debb9SMatt Spinler 
233f77debb9SMatt Spinler     bool doNotify = false;
234f77debb9SMatt Spinler     uint32_t id = 0;
235f77debb9SMatt Spinler 
236f77debb9SMatt Spinler     // Find the PEL to send
237f77debb9SMatt Spinler     while (!doNotify && !_pelQueue.empty())
238f77debb9SMatt Spinler     {
239f77debb9SMatt Spinler         id = _pelQueue.front();
240f77debb9SMatt Spinler         _pelQueue.pop_front();
241f77debb9SMatt Spinler 
242f77debb9SMatt Spinler         if (notifyRequired(id))
243f77debb9SMatt Spinler         {
244f77debb9SMatt Spinler             doNotify = true;
245f77debb9SMatt Spinler         }
246f77debb9SMatt Spinler     }
247f77debb9SMatt Spinler 
248f77debb9SMatt Spinler     if (doNotify)
249f77debb9SMatt Spinler     {
250f77debb9SMatt Spinler         // Get the size using the repo attributes
251f77debb9SMatt Spinler         Repository::LogID i{Repository::LogID::Pel{id}};
252f77debb9SMatt Spinler         if (auto attributes = _repo.getPELAttributes(i); attributes)
253f77debb9SMatt Spinler         {
254f77debb9SMatt Spinler             auto size = static_cast<size_t>(
255f77debb9SMatt Spinler                 std::filesystem::file_size((*attributes).get().path));
256f77debb9SMatt Spinler             auto rc = _hostIface->sendNewLogCmd(id, size);
257f77debb9SMatt Spinler 
258f77debb9SMatt Spinler             if (rc == CmdStatus::success)
259f77debb9SMatt Spinler             {
260f77debb9SMatt Spinler                 _inProgressPEL = id;
261f77debb9SMatt Spinler             }
262f77debb9SMatt Spinler             else
263f77debb9SMatt Spinler             {
264f77debb9SMatt Spinler                 // It failed.  Retry
265f77debb9SMatt Spinler                 log<level::ERR>("PLDM send failed", entry("PEL_ID=0x%X", id));
266f77debb9SMatt Spinler                 _pelQueue.push_front(id);
267f77debb9SMatt Spinler                 _inProgressPEL = 0;
268f77debb9SMatt Spinler                 _retryTimer.restartOnce(_hostIface->getSendRetryDelay());
269f77debb9SMatt Spinler             }
270f77debb9SMatt Spinler         }
271f77debb9SMatt Spinler         else
272f77debb9SMatt Spinler         {
273f77debb9SMatt Spinler             log<level::ERR>("PEL ID not in repository.  Cannot notify host",
274f77debb9SMatt Spinler                             entry("PEL_ID=0x%X", id));
275f77debb9SMatt Spinler         }
276f77debb9SMatt Spinler     }
277f60ac27eSMatt Spinler }
278f60ac27eSMatt Spinler 
279f60ac27eSMatt Spinler void HostNotifier::hostStateChange(bool hostUp)
280f60ac27eSMatt Spinler {
2813019c6fbSMatt Spinler     _retryCount = 0;
28241293cb8SMatt Spinler     _hostFull = false;
2833019c6fbSMatt Spinler 
2843019c6fbSMatt Spinler     if (hostUp && !_pelQueue.empty())
2853019c6fbSMatt Spinler     {
2863019c6fbSMatt Spinler         doNewLogNotify();
2873019c6fbSMatt Spinler     }
2883019c6fbSMatt Spinler     else if (!hostUp)
2893019c6fbSMatt Spinler     {
2903019c6fbSMatt Spinler         stopCommand();
2913019c6fbSMatt Spinler 
2923019c6fbSMatt Spinler         // Reset the state on any PELs that were sent but not acked back
2933019c6fbSMatt Spinler         // to new so they'll get sent again.
2943019c6fbSMatt Spinler         for (auto id : _sentPELs)
2953019c6fbSMatt Spinler         {
2963019c6fbSMatt Spinler             _pelQueue.push_back(id);
2973019c6fbSMatt Spinler             _repo.setPELHostTransState(id, TransmissionState::newPEL);
2983019c6fbSMatt Spinler         }
2993019c6fbSMatt Spinler 
3003019c6fbSMatt Spinler         _sentPELs.clear();
30141293cb8SMatt Spinler 
30241293cb8SMatt Spinler         if (_hostFullTimer.isEnabled())
30341293cb8SMatt Spinler         {
30441293cb8SMatt Spinler             _hostFullTimer.setEnabled(false);
30541293cb8SMatt Spinler         }
3063019c6fbSMatt Spinler     }
307f60ac27eSMatt Spinler }
308f60ac27eSMatt Spinler 
309f60ac27eSMatt Spinler void HostNotifier::commandResponse(ResponseStatus status)
310f60ac27eSMatt Spinler {
311f869fcf8SMatt Spinler     auto id = _inProgressPEL;
312f869fcf8SMatt Spinler     _inProgressPEL = 0;
313f869fcf8SMatt Spinler 
314f869fcf8SMatt Spinler     if (status == ResponseStatus::success)
315f869fcf8SMatt Spinler     {
316f869fcf8SMatt Spinler         _retryCount = 0;
317f869fcf8SMatt Spinler 
318f869fcf8SMatt Spinler         _sentPELs.push_back(id);
319f869fcf8SMatt Spinler 
320f869fcf8SMatt Spinler         _repo.setPELHostTransState(id, TransmissionState::sent);
321f869fcf8SMatt Spinler 
32241293cb8SMatt Spinler         // If the host is full, don't send off the next PEL
32341293cb8SMatt Spinler         if (!_hostFull && !_pelQueue.empty())
324f869fcf8SMatt Spinler         {
325f869fcf8SMatt Spinler             doNewLogNotify();
326f869fcf8SMatt Spinler         }
327f869fcf8SMatt Spinler     }
328f869fcf8SMatt Spinler     else
329f869fcf8SMatt Spinler     {
330f869fcf8SMatt Spinler         log<level::ERR>("PLDM command response failure",
331f869fcf8SMatt Spinler                         entry("PEL_ID=0x%X", id));
332f869fcf8SMatt Spinler         // Retry
333f869fcf8SMatt Spinler         _pelQueue.push_front(id);
334f869fcf8SMatt Spinler         _retryTimer.restartOnce(_hostIface->getReceiveRetryDelay());
335f869fcf8SMatt Spinler     }
336f869fcf8SMatt Spinler }
337f869fcf8SMatt Spinler 
338f869fcf8SMatt Spinler void HostNotifier::retryTimerExpired()
339f869fcf8SMatt Spinler {
340f869fcf8SMatt Spinler     if (_dataIface.isHostUp())
341f869fcf8SMatt Spinler     {
342f869fcf8SMatt Spinler         log<level::INFO>("Attempting command retry",
343f869fcf8SMatt Spinler                          entry("PEL_ID=0x%X", _pelQueue.front()));
344f869fcf8SMatt Spinler         _retryCount++;
345f869fcf8SMatt Spinler         doNewLogNotify();
346f869fcf8SMatt Spinler     }
347f60ac27eSMatt Spinler }
348f60ac27eSMatt Spinler 
34941293cb8SMatt Spinler void HostNotifier::hostFullTimerExpired()
35041293cb8SMatt Spinler {
35141293cb8SMatt Spinler     doNewLogNotify();
35241293cb8SMatt Spinler }
35341293cb8SMatt Spinler 
3543019c6fbSMatt Spinler void HostNotifier::stopCommand()
3553019c6fbSMatt Spinler {
3563019c6fbSMatt Spinler     _retryCount = 0;
3573019c6fbSMatt Spinler 
3583019c6fbSMatt Spinler     if (_inProgressPEL != 0)
3593019c6fbSMatt Spinler     {
3603019c6fbSMatt Spinler         _pelQueue.push_front(_inProgressPEL);
3613019c6fbSMatt Spinler         _inProgressPEL = 0;
3623019c6fbSMatt Spinler     }
3633019c6fbSMatt Spinler 
3643019c6fbSMatt Spinler     if (_retryTimer.isEnabled())
3653019c6fbSMatt Spinler     {
3663019c6fbSMatt Spinler         _retryTimer.setEnabled(false);
3673019c6fbSMatt Spinler     }
3683019c6fbSMatt Spinler 
369*829b052dSMatt Spinler     // Ensure the PLDM instance ID is released
3703019c6fbSMatt Spinler     _hostIface->cancelCmd();
3713019c6fbSMatt Spinler }
3723019c6fbSMatt Spinler 
373cc3b64aeSMatt Spinler void HostNotifier::ackPEL(uint32_t id)
374cc3b64aeSMatt Spinler {
375cc3b64aeSMatt Spinler     _repo.setPELHostTransState(id, TransmissionState::acked);
376cc3b64aeSMatt Spinler 
377cc3b64aeSMatt Spinler     // No longer just 'sent', so remove it from the sent list.
378cc3b64aeSMatt Spinler     auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id);
379cc3b64aeSMatt Spinler     if (sent != _sentPELs.end())
380cc3b64aeSMatt Spinler     {
381cc3b64aeSMatt Spinler         _sentPELs.erase(sent);
382cc3b64aeSMatt Spinler     }
38341293cb8SMatt Spinler 
38441293cb8SMatt Spinler     // An ack means the host is no longer full
38541293cb8SMatt Spinler     if (_hostFullTimer.isEnabled())
38641293cb8SMatt Spinler     {
38741293cb8SMatt Spinler         _hostFullTimer.setEnabled(false);
38841293cb8SMatt Spinler     }
38941293cb8SMatt Spinler 
39041293cb8SMatt Spinler     if (_hostFull)
39141293cb8SMatt Spinler     {
39241293cb8SMatt Spinler         _hostFull = false;
39341293cb8SMatt Spinler 
39441293cb8SMatt Spinler         // Start sending PELs again, from the event loop
39541293cb8SMatt Spinler         if (!_pelQueue.empty())
39641293cb8SMatt Spinler         {
39741293cb8SMatt Spinler             scheduleDispatch();
39841293cb8SMatt Spinler         }
39941293cb8SMatt Spinler     }
40041293cb8SMatt Spinler }
40141293cb8SMatt Spinler 
40241293cb8SMatt Spinler void HostNotifier::setHostFull(uint32_t id)
40341293cb8SMatt Spinler {
40441293cb8SMatt Spinler     log<level::INFO>("Received Host full indication", entry("PEL_ID=0x%X", id));
40541293cb8SMatt Spinler 
40641293cb8SMatt Spinler     _hostFull = true;
40741293cb8SMatt Spinler 
40841293cb8SMatt Spinler     // This PEL needs to get re-sent
40941293cb8SMatt Spinler     auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id);
41041293cb8SMatt Spinler     if (sent != _sentPELs.end())
41141293cb8SMatt Spinler     {
41241293cb8SMatt Spinler         _sentPELs.erase(sent);
41341293cb8SMatt Spinler         _repo.setPELHostTransState(id, TransmissionState::newPEL);
41441293cb8SMatt Spinler 
41541293cb8SMatt Spinler         if (std::find(_pelQueue.begin(), _pelQueue.end(), id) ==
41641293cb8SMatt Spinler             _pelQueue.end())
41741293cb8SMatt Spinler         {
41841293cb8SMatt Spinler             _pelQueue.push_front(id);
41941293cb8SMatt Spinler         }
42041293cb8SMatt Spinler     }
42141293cb8SMatt Spinler 
42241293cb8SMatt Spinler     // The only PELs that will be sent when the
42341293cb8SMatt Spinler     // host is full is from this timer callback.
42441293cb8SMatt Spinler     if (!_hostFullTimer.isEnabled())
42541293cb8SMatt Spinler     {
42641293cb8SMatt Spinler         _hostFullTimer.restartOnce(_hostIface->getHostFullRetryDelay());
42741293cb8SMatt Spinler     }
428cc3b64aeSMatt Spinler }
429cc3b64aeSMatt Spinler 
430a19b6234SMatt Spinler void HostNotifier::setBadPEL(uint32_t id)
431a19b6234SMatt Spinler {
432a19b6234SMatt Spinler     log<level::ERR>("PEL rejected by the host", entry("PEL_ID=0x%X", id));
433a19b6234SMatt Spinler 
434a19b6234SMatt Spinler     auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id);
435a19b6234SMatt Spinler     if (sent != _sentPELs.end())
436a19b6234SMatt Spinler     {
437a19b6234SMatt Spinler         _sentPELs.erase(sent);
438a19b6234SMatt Spinler     }
439a19b6234SMatt Spinler 
440a19b6234SMatt Spinler     _repo.setPELHostTransState(id, TransmissionState::badPEL);
441a19b6234SMatt Spinler }
442a19b6234SMatt Spinler 
443f60ac27eSMatt Spinler } // namespace openpower::pels
444