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 
437cb985ffSMatt Spinler     // Subscribe to be told about deleted PELs.
447cb985ffSMatt Spinler     _repo.subscribeToDeletes(
457cb985ffSMatt Spinler         subscriptionName,
467cb985ffSMatt Spinler         std::bind(std::mem_fn(&HostNotifier::deleteLogCallback), this,
477cb985ffSMatt Spinler                   std::placeholders::_1));
487cb985ffSMatt Spinler 
49f60ac27eSMatt Spinler     // Add any existing PELs to the queue to send them if necessary.
50f60ac27eSMatt Spinler     _repo.for_each(std::bind(std::mem_fn(&HostNotifier::addPELToQueue), this,
51f60ac27eSMatt Spinler                              std::placeholders::_1));
52f60ac27eSMatt Spinler 
53f60ac27eSMatt Spinler     // Subscribe to be told about host state changes.
54f60ac27eSMatt Spinler     _dataIface.subscribeToHostStateChange(
55f60ac27eSMatt Spinler         subscriptionName,
56f60ac27eSMatt Spinler         std::bind(std::mem_fun(&HostNotifier::hostStateChange), this,
57f60ac27eSMatt Spinler                   std::placeholders::_1));
58f60ac27eSMatt Spinler 
59f60ac27eSMatt Spinler     // Set the function to call when the async reponse is received.
60f60ac27eSMatt Spinler     _hostIface->setResponseFunction(
61f60ac27eSMatt Spinler         std::bind(std::mem_fn(&HostNotifier::commandResponse), this,
62f60ac27eSMatt Spinler                   std::placeholders::_1));
63f60ac27eSMatt Spinler 
64f60ac27eSMatt Spinler     // Start sending logs if the host is running
65f60ac27eSMatt Spinler     if (!_pelQueue.empty() && _dataIface.isHostUp())
66f60ac27eSMatt Spinler     {
67f60ac27eSMatt Spinler         doNewLogNotify();
68f60ac27eSMatt Spinler     }
69f60ac27eSMatt Spinler }
70f60ac27eSMatt Spinler 
71f60ac27eSMatt Spinler HostNotifier::~HostNotifier()
72f60ac27eSMatt Spinler {
73f60ac27eSMatt Spinler     _repo.unsubscribeFromAdds(subscriptionName);
74f60ac27eSMatt Spinler     _dataIface.unsubscribeFromHostStateChange(subscriptionName);
75f60ac27eSMatt Spinler }
76f60ac27eSMatt Spinler 
77f60ac27eSMatt Spinler bool HostNotifier::addPELToQueue(const PEL& pel)
78f60ac27eSMatt Spinler {
79f60ac27eSMatt Spinler     if (enqueueRequired(pel.id()))
80f60ac27eSMatt Spinler     {
81f60ac27eSMatt Spinler         _pelQueue.push_back(pel.id());
82f60ac27eSMatt Spinler     }
83f60ac27eSMatt Spinler 
84f60ac27eSMatt Spinler     // Return false so that Repo::for_each keeps going.
85f60ac27eSMatt Spinler     return false;
86f60ac27eSMatt Spinler }
87f60ac27eSMatt Spinler 
88f60ac27eSMatt Spinler bool HostNotifier::enqueueRequired(uint32_t id) const
89f60ac27eSMatt Spinler {
90f60ac27eSMatt Spinler     bool required = true;
91a943b15bSMatt Spinler     Repository::LogID i{Repository::LogID::Pel{id}};
92a943b15bSMatt Spinler 
9324a8558bSMatt Spinler     // Manufacturing testing may turn off sending up PELs
9424a8558bSMatt Spinler     if (!_dataIface.getHostPELEnablement())
9524a8558bSMatt Spinler     {
9624a8558bSMatt Spinler         return false;
9724a8558bSMatt Spinler     }
9824a8558bSMatt Spinler 
99a943b15bSMatt Spinler     if (auto attributes = _repo.getPELAttributes(i); attributes)
100a943b15bSMatt Spinler     {
101a943b15bSMatt Spinler         auto a = attributes.value().get();
102a943b15bSMatt Spinler 
103a943b15bSMatt Spinler         if ((a.hostState == TransmissionState::acked) ||
104a943b15bSMatt Spinler             (a.hostState == TransmissionState::badPEL))
105a943b15bSMatt Spinler         {
106a943b15bSMatt Spinler             required = false;
107a943b15bSMatt Spinler         }
108a943b15bSMatt Spinler         else if (a.actionFlags.test(hiddenFlagBit) &&
109a943b15bSMatt Spinler                  (a.hmcState == TransmissionState::acked))
110a943b15bSMatt Spinler         {
111a943b15bSMatt Spinler             required = false;
112a943b15bSMatt Spinler         }
113a943b15bSMatt Spinler         else if (a.actionFlags.test(dontReportToHostFlagBit))
114a943b15bSMatt Spinler         {
115a943b15bSMatt Spinler             required = false;
116a943b15bSMatt Spinler         }
117a943b15bSMatt Spinler     }
118a943b15bSMatt Spinler     else
119a943b15bSMatt Spinler     {
120a943b15bSMatt Spinler         using namespace phosphor::logging;
121a943b15bSMatt Spinler         log<level::ERR>("Host Enqueue: Unable to find PEL ID in repository",
122a943b15bSMatt Spinler                         entry("PEL_ID=0x%X", id));
123a943b15bSMatt Spinler         required = false;
124a943b15bSMatt Spinler     }
125f60ac27eSMatt Spinler 
126f60ac27eSMatt Spinler     return required;
127f60ac27eSMatt Spinler }
128f60ac27eSMatt Spinler 
129f77debb9SMatt Spinler bool HostNotifier::notifyRequired(uint32_t id) const
130f77debb9SMatt Spinler {
131f77debb9SMatt Spinler     bool notify = true;
132f77debb9SMatt Spinler     Repository::LogID i{Repository::LogID::Pel{id}};
133f77debb9SMatt Spinler 
134f77debb9SMatt Spinler     if (auto attributes = _repo.getPELAttributes(i); attributes)
135f77debb9SMatt Spinler     {
136f77debb9SMatt Spinler         // If already acked by the host, don't send again.
137f77debb9SMatt Spinler         // (A safety check as it shouldn't get to this point.)
138f77debb9SMatt Spinler         auto a = attributes.value().get();
139f77debb9SMatt Spinler         if (a.hostState == TransmissionState::acked)
140f77debb9SMatt Spinler         {
141f77debb9SMatt Spinler             notify = false;
142f77debb9SMatt Spinler         }
143f77debb9SMatt Spinler         else if (a.actionFlags.test(hiddenFlagBit))
144f77debb9SMatt Spinler         {
145f77debb9SMatt Spinler             // If hidden and acked (or will be) acked by the HMC,
146f77debb9SMatt Spinler             // also don't send it. (HMC management can come and
147f77debb9SMatt Spinler             // go at any time)
148f77debb9SMatt Spinler             if ((a.hmcState == TransmissionState::acked) ||
149f77debb9SMatt Spinler                 _dataIface.isHMCManaged())
150f77debb9SMatt Spinler             {
151f77debb9SMatt Spinler                 notify = false;
152f77debb9SMatt Spinler             }
153f77debb9SMatt Spinler         }
154f77debb9SMatt Spinler     }
155f77debb9SMatt Spinler     else
156f77debb9SMatt Spinler     {
157f77debb9SMatt Spinler         // Must have been deleted since put on the queue.
158f77debb9SMatt Spinler         notify = false;
159f77debb9SMatt Spinler     }
160f77debb9SMatt Spinler 
161f77debb9SMatt Spinler     return notify;
162f77debb9SMatt Spinler }
163f77debb9SMatt Spinler 
164f60ac27eSMatt Spinler void HostNotifier::newLogCallback(const PEL& pel)
165f60ac27eSMatt Spinler {
166f60ac27eSMatt Spinler     if (!enqueueRequired(pel.id()))
167f60ac27eSMatt Spinler     {
168f60ac27eSMatt Spinler         return;
169f60ac27eSMatt Spinler     }
170f60ac27eSMatt Spinler 
1715f5352e5SMatt Spinler     log<level::DEBUG>("new PEL added to queue", entry("PEL_ID=0x%X", pel.id()));
1725f5352e5SMatt Spinler 
173f60ac27eSMatt Spinler     _pelQueue.push_back(pel.id());
174f60ac27eSMatt Spinler 
17541293cb8SMatt Spinler     // Notify shouldn't happen if host is down or full
17641293cb8SMatt Spinler     if (!_dataIface.isHostUp() || _hostFull)
1777d800a4eSMatt Spinler     {
1787d800a4eSMatt Spinler         return;
1797d800a4eSMatt Spinler     }
1807d800a4eSMatt Spinler 
1817d800a4eSMatt Spinler     // Dispatch a command now if there isn't currently a command
1827d800a4eSMatt Spinler     // in progress and this is the first log in the queue or it
1837d800a4eSMatt Spinler     // previously gave up from a hard failure.
1847d800a4eSMatt Spinler     auto inProgress = (_inProgressPEL != 0) || _hostIface->cmdInProgress() ||
1857d800a4eSMatt Spinler                       _retryTimer.isEnabled();
1867d800a4eSMatt Spinler 
1877d800a4eSMatt Spinler     auto firstPEL = _pelQueue.size() == 1;
1887d800a4eSMatt Spinler     auto gaveUp = _retryCount >= maxRetryAttempts;
1897d800a4eSMatt Spinler 
1907d800a4eSMatt Spinler     if (!inProgress && (firstPEL || gaveUp))
1917d800a4eSMatt Spinler     {
1927d800a4eSMatt Spinler         _retryCount = 0;
1937d800a4eSMatt Spinler 
1947d800a4eSMatt Spinler         // Send a log, but from the event loop, not from here.
1957d800a4eSMatt Spinler         scheduleDispatch();
1967d800a4eSMatt Spinler     }
1977d800a4eSMatt Spinler }
1987d800a4eSMatt Spinler 
1997cb985ffSMatt Spinler void HostNotifier::deleteLogCallback(uint32_t id)
2007cb985ffSMatt Spinler {
2017cb985ffSMatt Spinler     auto queueIt = std::find(_pelQueue.begin(), _pelQueue.end(), id);
2027cb985ffSMatt Spinler     if (queueIt != _pelQueue.end())
2037cb985ffSMatt Spinler     {
2047cb985ffSMatt Spinler         log<level::DEBUG>("Host notifier removing deleted log from queue");
2057cb985ffSMatt Spinler         _pelQueue.erase(queueIt);
2067cb985ffSMatt Spinler     }
2077cb985ffSMatt Spinler 
2087cb985ffSMatt Spinler     auto sentIt = std::find(_sentPELs.begin(), _sentPELs.end(), id);
2097cb985ffSMatt Spinler     if (sentIt != _sentPELs.end())
2107cb985ffSMatt Spinler     {
2117cb985ffSMatt Spinler         log<level::DEBUG>("Host notifier removing deleted log from sent list");
2127cb985ffSMatt Spinler         _sentPELs.erase(sentIt);
2137cb985ffSMatt Spinler     }
2147cb985ffSMatt Spinler 
2157cb985ffSMatt Spinler     // Nothing we can do about this...
2167cb985ffSMatt Spinler     if (id == _inProgressPEL)
2177cb985ffSMatt Spinler     {
2187cb985ffSMatt Spinler         log<level::WARNING>(
2197cb985ffSMatt Spinler             "A PEL was deleted while its host notification was in progress",
2207cb985ffSMatt Spinler             entry("PEL_ID=0x%X", id));
2217cb985ffSMatt Spinler     }
2227cb985ffSMatt Spinler }
2237cb985ffSMatt Spinler 
2247d800a4eSMatt Spinler void HostNotifier::scheduleDispatch()
2257d800a4eSMatt Spinler {
2267d800a4eSMatt Spinler     _dispatcher = std::make_unique<sdeventplus::source::Defer>(
2277d800a4eSMatt Spinler         _hostIface->getEvent(), std::bind(std::mem_fn(&HostNotifier::dispatch),
2287d800a4eSMatt Spinler                                           this, std::placeholders::_1));
2297d800a4eSMatt Spinler }
2307d800a4eSMatt Spinler 
231*d26fa3e7SPatrick Williams void HostNotifier::dispatch(sdeventplus::source::EventBase& /*source*/)
2327d800a4eSMatt Spinler {
2337d800a4eSMatt Spinler     _dispatcher.reset();
2347d800a4eSMatt Spinler 
2357d800a4eSMatt Spinler     doNewLogNotify();
236f60ac27eSMatt Spinler }
237f60ac27eSMatt Spinler 
238f60ac27eSMatt Spinler void HostNotifier::doNewLogNotify()
239f60ac27eSMatt Spinler {
24041293cb8SMatt Spinler     if (!_dataIface.isHostUp() || _retryTimer.isEnabled() ||
24141293cb8SMatt Spinler         _hostFullTimer.isEnabled())
242f77debb9SMatt Spinler     {
243f77debb9SMatt Spinler         return;
244f77debb9SMatt Spinler     }
245f77debb9SMatt Spinler 
246f77debb9SMatt Spinler     if (_retryCount >= maxRetryAttempts)
247f77debb9SMatt Spinler     {
248f77debb9SMatt Spinler         // Give up until a new log comes in.
249f77debb9SMatt Spinler         if (_retryCount == maxRetryAttempts)
250f77debb9SMatt Spinler         {
251f77debb9SMatt Spinler             // If this were to really happen, the PLDM interface
252f77debb9SMatt Spinler             // would be down and isolating that shouldn't left to
253f77debb9SMatt Spinler             // a logging daemon, so just trace.  Also, this will start
254f77debb9SMatt Spinler             // trying again when the next new log comes in.
255f77debb9SMatt Spinler             log<level::ERR>(
256f77debb9SMatt Spinler                 "PEL Host notifier hit max retry attempts. Giving up for now.",
257f77debb9SMatt Spinler                 entry("PEL_ID=0x%X", _pelQueue.front()));
258829b052dSMatt Spinler 
259829b052dSMatt Spinler             // Tell the host interface object to clean itself up, especially to
260829b052dSMatt Spinler             // release the PLDM instance ID it's been using.
261829b052dSMatt Spinler             _hostIface->cancelCmd();
262f77debb9SMatt Spinler         }
263f77debb9SMatt Spinler         return;
264f77debb9SMatt Spinler     }
265f77debb9SMatt Spinler 
266f77debb9SMatt Spinler     bool doNotify = false;
267f77debb9SMatt Spinler     uint32_t id = 0;
268f77debb9SMatt Spinler 
269f77debb9SMatt Spinler     // Find the PEL to send
270f77debb9SMatt Spinler     while (!doNotify && !_pelQueue.empty())
271f77debb9SMatt Spinler     {
272f77debb9SMatt Spinler         id = _pelQueue.front();
273f77debb9SMatt Spinler         _pelQueue.pop_front();
274f77debb9SMatt Spinler 
275f77debb9SMatt Spinler         if (notifyRequired(id))
276f77debb9SMatt Spinler         {
277f77debb9SMatt Spinler             doNotify = true;
278f77debb9SMatt Spinler         }
279f77debb9SMatt Spinler     }
280f77debb9SMatt Spinler 
281f77debb9SMatt Spinler     if (doNotify)
282f77debb9SMatt Spinler     {
283f77debb9SMatt Spinler         // Get the size using the repo attributes
284f77debb9SMatt Spinler         Repository::LogID i{Repository::LogID::Pel{id}};
285f77debb9SMatt Spinler         if (auto attributes = _repo.getPELAttributes(i); attributes)
286f77debb9SMatt Spinler         {
287f77debb9SMatt Spinler             auto size = static_cast<size_t>(
288f77debb9SMatt Spinler                 std::filesystem::file_size((*attributes).get().path));
2895f5352e5SMatt Spinler 
2905f5352e5SMatt Spinler             log<level::DEBUG>("sendNewLogCmd", entry("PEL_ID=0x%X", id),
2915f5352e5SMatt Spinler                               entry("PEL_SIZE=%d", size));
2925f5352e5SMatt Spinler 
293f77debb9SMatt Spinler             auto rc = _hostIface->sendNewLogCmd(id, size);
294f77debb9SMatt Spinler 
295f77debb9SMatt Spinler             if (rc == CmdStatus::success)
296f77debb9SMatt Spinler             {
297f77debb9SMatt Spinler                 _inProgressPEL = id;
298f77debb9SMatt Spinler             }
299f77debb9SMatt Spinler             else
300f77debb9SMatt Spinler             {
301f77debb9SMatt Spinler                 // It failed.  Retry
302f77debb9SMatt Spinler                 log<level::ERR>("PLDM send failed", entry("PEL_ID=0x%X", id));
303f77debb9SMatt Spinler                 _pelQueue.push_front(id);
304f77debb9SMatt Spinler                 _inProgressPEL = 0;
305f77debb9SMatt Spinler                 _retryTimer.restartOnce(_hostIface->getSendRetryDelay());
306f77debb9SMatt Spinler             }
307f77debb9SMatt Spinler         }
308f77debb9SMatt Spinler         else
309f77debb9SMatt Spinler         {
310f77debb9SMatt Spinler             log<level::ERR>("PEL ID not in repository.  Cannot notify host",
311f77debb9SMatt Spinler                             entry("PEL_ID=0x%X", id));
312f77debb9SMatt Spinler         }
313f77debb9SMatt Spinler     }
314f60ac27eSMatt Spinler }
315f60ac27eSMatt Spinler 
316f60ac27eSMatt Spinler void HostNotifier::hostStateChange(bool hostUp)
317f60ac27eSMatt Spinler {
3183019c6fbSMatt Spinler     _retryCount = 0;
31941293cb8SMatt Spinler     _hostFull = false;
3203019c6fbSMatt Spinler 
3213019c6fbSMatt Spinler     if (hostUp && !_pelQueue.empty())
3223019c6fbSMatt Spinler     {
3235f5352e5SMatt Spinler         log<level::DEBUG>("Host state change to on");
3245f5352e5SMatt Spinler 
3253019c6fbSMatt Spinler         doNewLogNotify();
3263019c6fbSMatt Spinler     }
3273019c6fbSMatt Spinler     else if (!hostUp)
3283019c6fbSMatt Spinler     {
3295f5352e5SMatt Spinler         log<level::DEBUG>("Host state change to off");
3305f5352e5SMatt Spinler 
3313019c6fbSMatt Spinler         stopCommand();
3323019c6fbSMatt Spinler 
3333019c6fbSMatt Spinler         // Reset the state on any PELs that were sent but not acked back
3343019c6fbSMatt Spinler         // to new so they'll get sent again.
3353019c6fbSMatt Spinler         for (auto id : _sentPELs)
3363019c6fbSMatt Spinler         {
3373019c6fbSMatt Spinler             _pelQueue.push_back(id);
3383019c6fbSMatt Spinler             _repo.setPELHostTransState(id, TransmissionState::newPEL);
3393019c6fbSMatt Spinler         }
3403019c6fbSMatt Spinler 
3413019c6fbSMatt Spinler         _sentPELs.clear();
34241293cb8SMatt Spinler 
34341293cb8SMatt Spinler         if (_hostFullTimer.isEnabled())
34441293cb8SMatt Spinler         {
34541293cb8SMatt Spinler             _hostFullTimer.setEnabled(false);
34641293cb8SMatt Spinler         }
3473019c6fbSMatt Spinler     }
348f60ac27eSMatt Spinler }
349f60ac27eSMatt Spinler 
350f60ac27eSMatt Spinler void HostNotifier::commandResponse(ResponseStatus status)
351f60ac27eSMatt Spinler {
352f869fcf8SMatt Spinler     auto id = _inProgressPEL;
353f869fcf8SMatt Spinler     _inProgressPEL = 0;
354f869fcf8SMatt Spinler 
355f869fcf8SMatt Spinler     if (status == ResponseStatus::success)
356f869fcf8SMatt Spinler     {
3575f5352e5SMatt Spinler         log<level::DEBUG>("HostNotifier command response success",
3585f5352e5SMatt Spinler                           entry("PEL_ID=0x%X", id));
359f869fcf8SMatt Spinler         _retryCount = 0;
360f869fcf8SMatt Spinler 
361f869fcf8SMatt Spinler         _sentPELs.push_back(id);
362f869fcf8SMatt Spinler 
363f869fcf8SMatt Spinler         _repo.setPELHostTransState(id, TransmissionState::sent);
364f869fcf8SMatt Spinler 
36541293cb8SMatt Spinler         // If the host is full, don't send off the next PEL
36641293cb8SMatt Spinler         if (!_hostFull && !_pelQueue.empty())
367f869fcf8SMatt Spinler         {
368f869fcf8SMatt Spinler             doNewLogNotify();
369f869fcf8SMatt Spinler         }
370f869fcf8SMatt Spinler     }
371f869fcf8SMatt Spinler     else
372f869fcf8SMatt Spinler     {
373f869fcf8SMatt Spinler         log<level::ERR>("PLDM command response failure",
374f869fcf8SMatt Spinler                         entry("PEL_ID=0x%X", id));
375f869fcf8SMatt Spinler         // Retry
376f869fcf8SMatt Spinler         _pelQueue.push_front(id);
377f869fcf8SMatt Spinler         _retryTimer.restartOnce(_hostIface->getReceiveRetryDelay());
378f869fcf8SMatt Spinler     }
379f869fcf8SMatt Spinler }
380f869fcf8SMatt Spinler 
381f869fcf8SMatt Spinler void HostNotifier::retryTimerExpired()
382f869fcf8SMatt Spinler {
383f869fcf8SMatt Spinler     if (_dataIface.isHostUp())
384f869fcf8SMatt Spinler     {
385f869fcf8SMatt Spinler         log<level::INFO>("Attempting command retry",
386f869fcf8SMatt Spinler                          entry("PEL_ID=0x%X", _pelQueue.front()));
387f869fcf8SMatt Spinler         _retryCount++;
388f869fcf8SMatt Spinler         doNewLogNotify();
389f869fcf8SMatt Spinler     }
390f60ac27eSMatt Spinler }
391f60ac27eSMatt Spinler 
39241293cb8SMatt Spinler void HostNotifier::hostFullTimerExpired()
39341293cb8SMatt Spinler {
3945f5352e5SMatt Spinler     log<level::DEBUG>("Host full timer expired, trying send again");
39541293cb8SMatt Spinler     doNewLogNotify();
39641293cb8SMatt Spinler }
39741293cb8SMatt Spinler 
3983019c6fbSMatt Spinler void HostNotifier::stopCommand()
3993019c6fbSMatt Spinler {
4003019c6fbSMatt Spinler     _retryCount = 0;
4013019c6fbSMatt Spinler 
4023019c6fbSMatt Spinler     if (_inProgressPEL != 0)
4033019c6fbSMatt Spinler     {
4043019c6fbSMatt Spinler         _pelQueue.push_front(_inProgressPEL);
4053019c6fbSMatt Spinler         _inProgressPEL = 0;
4063019c6fbSMatt Spinler     }
4073019c6fbSMatt Spinler 
4083019c6fbSMatt Spinler     if (_retryTimer.isEnabled())
4093019c6fbSMatt Spinler     {
4103019c6fbSMatt Spinler         _retryTimer.setEnabled(false);
4113019c6fbSMatt Spinler     }
4123019c6fbSMatt Spinler 
413829b052dSMatt Spinler     // Ensure the PLDM instance ID is released
4143019c6fbSMatt Spinler     _hostIface->cancelCmd();
4153019c6fbSMatt Spinler }
4163019c6fbSMatt Spinler 
417cc3b64aeSMatt Spinler void HostNotifier::ackPEL(uint32_t id)
418cc3b64aeSMatt Spinler {
419cc3b64aeSMatt Spinler     _repo.setPELHostTransState(id, TransmissionState::acked);
420cc3b64aeSMatt Spinler 
421cc3b64aeSMatt Spinler     // No longer just 'sent', so remove it from the sent list.
422cc3b64aeSMatt Spinler     auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id);
423cc3b64aeSMatt Spinler     if (sent != _sentPELs.end())
424cc3b64aeSMatt Spinler     {
425cc3b64aeSMatt Spinler         _sentPELs.erase(sent);
426cc3b64aeSMatt Spinler     }
42741293cb8SMatt Spinler 
42841293cb8SMatt Spinler     // An ack means the host is no longer full
42941293cb8SMatt Spinler     if (_hostFullTimer.isEnabled())
43041293cb8SMatt Spinler     {
43141293cb8SMatt Spinler         _hostFullTimer.setEnabled(false);
43241293cb8SMatt Spinler     }
43341293cb8SMatt Spinler 
43441293cb8SMatt Spinler     if (_hostFull)
43541293cb8SMatt Spinler     {
43641293cb8SMatt Spinler         _hostFull = false;
43741293cb8SMatt Spinler 
4385f5352e5SMatt Spinler         log<level::DEBUG>("Host previously full, not anymore after this ack");
4395f5352e5SMatt Spinler 
44041293cb8SMatt Spinler         // Start sending PELs again, from the event loop
44141293cb8SMatt Spinler         if (!_pelQueue.empty())
44241293cb8SMatt Spinler         {
44341293cb8SMatt Spinler             scheduleDispatch();
44441293cb8SMatt Spinler         }
44541293cb8SMatt Spinler     }
44641293cb8SMatt Spinler }
44741293cb8SMatt Spinler 
44841293cb8SMatt Spinler void HostNotifier::setHostFull(uint32_t id)
44941293cb8SMatt Spinler {
45041293cb8SMatt Spinler     log<level::INFO>("Received Host full indication", entry("PEL_ID=0x%X", id));
45141293cb8SMatt Spinler 
45241293cb8SMatt Spinler     _hostFull = true;
45341293cb8SMatt Spinler 
45441293cb8SMatt Spinler     // This PEL needs to get re-sent
45541293cb8SMatt Spinler     auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id);
45641293cb8SMatt Spinler     if (sent != _sentPELs.end())
45741293cb8SMatt Spinler     {
45841293cb8SMatt Spinler         _sentPELs.erase(sent);
45941293cb8SMatt Spinler         _repo.setPELHostTransState(id, TransmissionState::newPEL);
46041293cb8SMatt Spinler 
46141293cb8SMatt Spinler         if (std::find(_pelQueue.begin(), _pelQueue.end(), id) ==
46241293cb8SMatt Spinler             _pelQueue.end())
46341293cb8SMatt Spinler         {
46441293cb8SMatt Spinler             _pelQueue.push_front(id);
46541293cb8SMatt Spinler         }
46641293cb8SMatt Spinler     }
46741293cb8SMatt Spinler 
46841293cb8SMatt Spinler     // The only PELs that will be sent when the
46941293cb8SMatt Spinler     // host is full is from this timer callback.
47041293cb8SMatt Spinler     if (!_hostFullTimer.isEnabled())
47141293cb8SMatt Spinler     {
4725f5352e5SMatt Spinler         log<level::DEBUG>("Starting host full timer");
47341293cb8SMatt Spinler         _hostFullTimer.restartOnce(_hostIface->getHostFullRetryDelay());
47441293cb8SMatt Spinler     }
475cc3b64aeSMatt Spinler }
476cc3b64aeSMatt Spinler 
477a19b6234SMatt Spinler void HostNotifier::setBadPEL(uint32_t id)
478a19b6234SMatt Spinler {
479a19b6234SMatt Spinler     log<level::ERR>("PEL rejected by the host", entry("PEL_ID=0x%X", id));
480a19b6234SMatt Spinler 
481a19b6234SMatt Spinler     auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id);
482a19b6234SMatt Spinler     if (sent != _sentPELs.end())
483a19b6234SMatt Spinler     {
484a19b6234SMatt Spinler         _sentPELs.erase(sent);
485a19b6234SMatt Spinler     }
486a19b6234SMatt Spinler 
487a19b6234SMatt Spinler     _repo.setPELHostTransState(id, TransmissionState::badPEL);
488a19b6234SMatt Spinler }
489a19b6234SMatt Spinler 
490f60ac27eSMatt Spinler } // namespace openpower::pels
491