xref: /openbmc/phosphor-logging/extensions/openpower-pels/host_notifier.cpp (revision 075c79237505ea3b810a461f5f514e4d520a0c44)
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 
181b41886dSMatt Spinler #include <phosphor-logging/lg2.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 
HostNotifier(Repository & repo,DataInterfaceBase & dataIface,std::unique_ptr<HostInterface> hostIface)26f60ac27eSMatt Spinler HostNotifier::HostNotifier(Repository& repo, DataInterfaceBase& dataIface,
27f60ac27eSMatt Spinler                            std::unique_ptr<HostInterface> hostIface) :
28*075c7923SPatrick Williams     _repo(repo), _dataIface(dataIface), _hostIface(std::move(hostIface)),
29f869fcf8SMatt Spinler     _retryTimer(_hostIface->getEvent(),
3041293cb8SMatt Spinler                 std::bind(std::mem_fn(&HostNotifier::retryTimerExpired), this)),
3141293cb8SMatt Spinler     _hostFullTimer(
3241293cb8SMatt Spinler         _hostIface->getEvent(),
33e5f7508bSMatt Spinler         std::bind(std::mem_fn(&HostNotifier::hostFullTimerExpired), this)),
34*075c7923SPatrick Williams     _hostUpTimer(_hostIface->getEvent(),
35*075c7923SPatrick Williams                  std::bind(std::mem_fn(&HostNotifier::hostUpTimerExpired),
36*075c7923SPatrick Williams                            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(
554f1bed7eSMatt Spinler         subscriptionName, std::bind(std::mem_fn(&HostNotifier::hostStateChange),
564f1bed7eSMatt Spinler                                     this, std::placeholders::_1));
57f60ac27eSMatt Spinler 
58f60ac27eSMatt Spinler     // Set the function to call when the async reponse is received.
59f60ac27eSMatt Spinler     _hostIface->setResponseFunction(
60f60ac27eSMatt Spinler         std::bind(std::mem_fn(&HostNotifier::commandResponse), this,
61f60ac27eSMatt Spinler                   std::placeholders::_1));
62f60ac27eSMatt Spinler 
63f60ac27eSMatt Spinler     // Start sending logs if the host is running
64f60ac27eSMatt Spinler     if (!_pelQueue.empty() && _dataIface.isHostUp())
65f60ac27eSMatt Spinler     {
661b41886dSMatt Spinler         lg2::debug("Host is already up at startup");
67e5f7508bSMatt Spinler         _hostUpTimer.restartOnce(_hostIface->getHostUpDelay());
68f60ac27eSMatt Spinler     }
69f60ac27eSMatt Spinler }
70f60ac27eSMatt Spinler 
~HostNotifier()71f60ac27eSMatt Spinler HostNotifier::~HostNotifier()
72f60ac27eSMatt Spinler {
73f60ac27eSMatt Spinler     _repo.unsubscribeFromAdds(subscriptionName);
74f60ac27eSMatt Spinler     _dataIface.unsubscribeFromHostStateChange(subscriptionName);
75f60ac27eSMatt Spinler }
76f60ac27eSMatt Spinler 
hostUpTimerExpired()77e5f7508bSMatt Spinler void HostNotifier::hostUpTimerExpired()
78e5f7508bSMatt Spinler {
791b41886dSMatt Spinler     lg2::debug("Host up timer expired");
80e5f7508bSMatt Spinler     doNewLogNotify();
81e5f7508bSMatt Spinler }
82e5f7508bSMatt Spinler 
addPELToQueue(const PEL & pel)83f60ac27eSMatt Spinler bool HostNotifier::addPELToQueue(const PEL& pel)
84f60ac27eSMatt Spinler {
85f60ac27eSMatt Spinler     if (enqueueRequired(pel.id()))
86f60ac27eSMatt Spinler     {
87f60ac27eSMatt Spinler         _pelQueue.push_back(pel.id());
88f60ac27eSMatt Spinler     }
89f60ac27eSMatt Spinler 
90f60ac27eSMatt Spinler     // Return false so that Repo::for_each keeps going.
91f60ac27eSMatt Spinler     return false;
92f60ac27eSMatt Spinler }
93f60ac27eSMatt Spinler 
enqueueRequired(uint32_t id) const94f60ac27eSMatt Spinler bool HostNotifier::enqueueRequired(uint32_t id) const
95f60ac27eSMatt Spinler {
96f60ac27eSMatt Spinler     bool required = true;
97a943b15bSMatt Spinler     Repository::LogID i{Repository::LogID::Pel{id}};
98a943b15bSMatt Spinler 
9924a8558bSMatt Spinler     // Manufacturing testing may turn off sending up PELs
10024a8558bSMatt Spinler     if (!_dataIface.getHostPELEnablement())
10124a8558bSMatt Spinler     {
10224a8558bSMatt Spinler         return false;
10324a8558bSMatt Spinler     }
10424a8558bSMatt Spinler 
105a943b15bSMatt Spinler     if (auto attributes = _repo.getPELAttributes(i); attributes)
106a943b15bSMatt Spinler     {
107a943b15bSMatt Spinler         auto a = attributes.value().get();
108a943b15bSMatt Spinler 
109a943b15bSMatt Spinler         if ((a.hostState == TransmissionState::acked) ||
110a943b15bSMatt Spinler             (a.hostState == TransmissionState::badPEL))
111a943b15bSMatt Spinler         {
112a943b15bSMatt Spinler             required = false;
113a943b15bSMatt Spinler         }
114a943b15bSMatt Spinler         else if (a.actionFlags.test(hiddenFlagBit) &&
115a943b15bSMatt Spinler                  (a.hmcState == TransmissionState::acked))
116a943b15bSMatt Spinler         {
117a943b15bSMatt Spinler             required = false;
118a943b15bSMatt Spinler         }
119a943b15bSMatt Spinler         else if (a.actionFlags.test(dontReportToHostFlagBit))
120a943b15bSMatt Spinler         {
121a943b15bSMatt Spinler             required = false;
122a943b15bSMatt Spinler         }
123a943b15bSMatt Spinler     }
124a943b15bSMatt Spinler     else
125a943b15bSMatt Spinler     {
126a943b15bSMatt Spinler         using namespace phosphor::logging;
1271b41886dSMatt Spinler         lg2::error("Host Enqueue: Unable to find PEL ID {ID} in repository",
1281b41886dSMatt Spinler                    "ID", lg2::hex, id);
129a943b15bSMatt Spinler         required = false;
130a943b15bSMatt Spinler     }
131f60ac27eSMatt Spinler 
132f60ac27eSMatt Spinler     return required;
133f60ac27eSMatt Spinler }
134f60ac27eSMatt Spinler 
notifyRequired(uint32_t id) const135f77debb9SMatt Spinler bool HostNotifier::notifyRequired(uint32_t id) const
136f77debb9SMatt Spinler {
137f77debb9SMatt Spinler     bool notify = true;
138f77debb9SMatt Spinler     Repository::LogID i{Repository::LogID::Pel{id}};
139f77debb9SMatt Spinler 
140f77debb9SMatt Spinler     if (auto attributes = _repo.getPELAttributes(i); attributes)
141f77debb9SMatt Spinler     {
142f77debb9SMatt Spinler         // If already acked by the host, don't send again.
143f77debb9SMatt Spinler         // (A safety check as it shouldn't get to this point.)
144f77debb9SMatt Spinler         auto a = attributes.value().get();
145f77debb9SMatt Spinler         if (a.hostState == TransmissionState::acked)
146f77debb9SMatt Spinler         {
147f77debb9SMatt Spinler             notify = false;
148f77debb9SMatt Spinler         }
149f77debb9SMatt Spinler         else if (a.actionFlags.test(hiddenFlagBit))
150f77debb9SMatt Spinler         {
151f77debb9SMatt Spinler             // If hidden and acked (or will be) acked by the HMC,
152f77debb9SMatt Spinler             // also don't send it. (HMC management can come and
153f77debb9SMatt Spinler             // go at any time)
154f77debb9SMatt Spinler             if ((a.hmcState == TransmissionState::acked) ||
155f77debb9SMatt Spinler                 _dataIface.isHMCManaged())
156f77debb9SMatt Spinler             {
157f77debb9SMatt Spinler                 notify = false;
158f77debb9SMatt Spinler             }
159f77debb9SMatt Spinler         }
160f77debb9SMatt Spinler     }
161f77debb9SMatt Spinler     else
162f77debb9SMatt Spinler     {
163f77debb9SMatt Spinler         // Must have been deleted since put on the queue.
164f77debb9SMatt Spinler         notify = false;
165f77debb9SMatt Spinler     }
166f77debb9SMatt Spinler 
167f77debb9SMatt Spinler     return notify;
168f77debb9SMatt Spinler }
169f77debb9SMatt Spinler 
newLogCallback(const PEL & pel)170f60ac27eSMatt Spinler void HostNotifier::newLogCallback(const PEL& pel)
171f60ac27eSMatt Spinler {
172f60ac27eSMatt Spinler     if (!enqueueRequired(pel.id()))
173f60ac27eSMatt Spinler     {
174f60ac27eSMatt Spinler         return;
175f60ac27eSMatt Spinler     }
176f60ac27eSMatt Spinler 
1771b41886dSMatt Spinler     lg2::debug("New PEL added to queue, PEL ID = {ID}", "ID", lg2::hex,
1781b41886dSMatt Spinler                pel.id());
1795f5352e5SMatt Spinler 
180f60ac27eSMatt Spinler     _pelQueue.push_back(pel.id());
181f60ac27eSMatt Spinler 
182e5f7508bSMatt Spinler     // Notify shouldn't happen if host is down, not up long enough, or full
183e5f7508bSMatt Spinler     if (!_dataIface.isHostUp() || _hostFull || _hostUpTimer.isEnabled())
1847d800a4eSMatt Spinler     {
1857d800a4eSMatt Spinler         return;
1867d800a4eSMatt Spinler     }
1877d800a4eSMatt Spinler 
1887d800a4eSMatt Spinler     // Dispatch a command now if there isn't currently a command
1897d800a4eSMatt Spinler     // in progress and this is the first log in the queue or it
1907d800a4eSMatt Spinler     // previously gave up from a hard failure.
1917d800a4eSMatt Spinler     auto inProgress = (_inProgressPEL != 0) || _hostIface->cmdInProgress() ||
1927d800a4eSMatt Spinler                       _retryTimer.isEnabled();
1937d800a4eSMatt Spinler 
1947d800a4eSMatt Spinler     auto firstPEL = _pelQueue.size() == 1;
1957d800a4eSMatt Spinler     auto gaveUp = _retryCount >= maxRetryAttempts;
1967d800a4eSMatt Spinler 
1977d800a4eSMatt Spinler     if (!inProgress && (firstPEL || gaveUp))
1987d800a4eSMatt Spinler     {
1997d800a4eSMatt Spinler         _retryCount = 0;
2007d800a4eSMatt Spinler 
2017d800a4eSMatt Spinler         // Send a log, but from the event loop, not from here.
2027d800a4eSMatt Spinler         scheduleDispatch();
2037d800a4eSMatt Spinler     }
2047d800a4eSMatt Spinler }
2057d800a4eSMatt Spinler 
deleteLogCallback(uint32_t id)2067cb985ffSMatt Spinler void HostNotifier::deleteLogCallback(uint32_t id)
2077cb985ffSMatt Spinler {
2087cb985ffSMatt Spinler     auto queueIt = std::find(_pelQueue.begin(), _pelQueue.end(), id);
2097cb985ffSMatt Spinler     if (queueIt != _pelQueue.end())
2107cb985ffSMatt Spinler     {
2111b41886dSMatt Spinler         lg2::debug("Host notifier removing deleted log from queue");
2127cb985ffSMatt Spinler         _pelQueue.erase(queueIt);
2137cb985ffSMatt Spinler     }
2147cb985ffSMatt Spinler 
2157cb985ffSMatt Spinler     auto sentIt = std::find(_sentPELs.begin(), _sentPELs.end(), id);
2167cb985ffSMatt Spinler     if (sentIt != _sentPELs.end())
2177cb985ffSMatt Spinler     {
2181b41886dSMatt Spinler         lg2::debug("Host notifier removing deleted log from sent list");
2197cb985ffSMatt Spinler         _sentPELs.erase(sentIt);
2207cb985ffSMatt Spinler     }
2217cb985ffSMatt Spinler 
2227cb985ffSMatt Spinler     // Nothing we can do about this...
2237cb985ffSMatt Spinler     if (id == _inProgressPEL)
2247cb985ffSMatt Spinler     {
2251b41886dSMatt Spinler         lg2::warning(
2261b41886dSMatt Spinler             "A PEL was deleted while its host notification was in progress, PEL ID = {ID}",
2271b41886dSMatt Spinler             "ID", lg2::hex, id);
2287cb985ffSMatt Spinler     }
2297cb985ffSMatt Spinler }
2307cb985ffSMatt Spinler 
scheduleDispatch()2317d800a4eSMatt Spinler void HostNotifier::scheduleDispatch()
2327d800a4eSMatt Spinler {
2337d800a4eSMatt Spinler     _dispatcher = std::make_unique<sdeventplus::source::Defer>(
2347d800a4eSMatt Spinler         _hostIface->getEvent(), std::bind(std::mem_fn(&HostNotifier::dispatch),
2357d800a4eSMatt Spinler                                           this, std::placeholders::_1));
2367d800a4eSMatt Spinler }
2377d800a4eSMatt Spinler 
dispatch(sdeventplus::source::EventBase &)238d26fa3e7SPatrick Williams void HostNotifier::dispatch(sdeventplus::source::EventBase& /*source*/)
2397d800a4eSMatt Spinler {
2407d800a4eSMatt Spinler     _dispatcher.reset();
2417d800a4eSMatt Spinler 
2427d800a4eSMatt Spinler     doNewLogNotify();
243f60ac27eSMatt Spinler }
244f60ac27eSMatt Spinler 
doNewLogNotify()245f60ac27eSMatt Spinler void HostNotifier::doNewLogNotify()
246f60ac27eSMatt Spinler {
24741293cb8SMatt Spinler     if (!_dataIface.isHostUp() || _retryTimer.isEnabled() ||
24841293cb8SMatt Spinler         _hostFullTimer.isEnabled())
249f77debb9SMatt Spinler     {
250f77debb9SMatt Spinler         return;
251f77debb9SMatt Spinler     }
252f77debb9SMatt Spinler 
253f77debb9SMatt Spinler     if (_retryCount >= maxRetryAttempts)
254f77debb9SMatt Spinler     {
255f77debb9SMatt Spinler         // Give up until a new log comes in.
256f77debb9SMatt Spinler         if (_retryCount == maxRetryAttempts)
257f77debb9SMatt Spinler         {
258f77debb9SMatt Spinler             // If this were to really happen, the PLDM interface
259f77debb9SMatt Spinler             // would be down and isolating that shouldn't left to
260f77debb9SMatt Spinler             // a logging daemon, so just trace.  Also, this will start
261f77debb9SMatt Spinler             // trying again when the next new log comes in.
2621b41886dSMatt Spinler             lg2::error(
2631b41886dSMatt Spinler                 "PEL Host notifier hit max retry attempts. Giving up for now. PEL ID = {ID}",
2641b41886dSMatt Spinler                 "ID", lg2::hex, _pelQueue.front());
265829b052dSMatt Spinler 
266829b052dSMatt Spinler             // Tell the host interface object to clean itself up, especially to
267829b052dSMatt Spinler             // release the PLDM instance ID it's been using.
268829b052dSMatt Spinler             _hostIface->cancelCmd();
269f77debb9SMatt Spinler         }
270f77debb9SMatt Spinler         return;
271f77debb9SMatt Spinler     }
272f77debb9SMatt Spinler 
273f77debb9SMatt Spinler     bool doNotify = false;
274f77debb9SMatt Spinler     uint32_t id = 0;
275f77debb9SMatt Spinler 
276f77debb9SMatt Spinler     // Find the PEL to send
277f77debb9SMatt Spinler     while (!doNotify && !_pelQueue.empty())
278f77debb9SMatt Spinler     {
279f77debb9SMatt Spinler         id = _pelQueue.front();
280f77debb9SMatt Spinler         _pelQueue.pop_front();
281f77debb9SMatt Spinler 
282f77debb9SMatt Spinler         if (notifyRequired(id))
283f77debb9SMatt Spinler         {
284f77debb9SMatt Spinler             doNotify = true;
285f77debb9SMatt Spinler         }
286f77debb9SMatt Spinler     }
287f77debb9SMatt Spinler 
288f77debb9SMatt Spinler     if (doNotify)
289f77debb9SMatt Spinler     {
290f77debb9SMatt Spinler         // Get the size using the repo attributes
291f77debb9SMatt Spinler         Repository::LogID i{Repository::LogID::Pel{id}};
292f77debb9SMatt Spinler         if (auto attributes = _repo.getPELAttributes(i); attributes)
293f77debb9SMatt Spinler         {
294f77debb9SMatt Spinler             auto size = static_cast<size_t>(
295f77debb9SMatt Spinler                 std::filesystem::file_size((*attributes).get().path));
2965f5352e5SMatt Spinler 
2971b41886dSMatt Spinler             lg2::debug("sendNewLogCmd: ID {ID} size {SIZE}", "ID", lg2::hex, id,
2981b41886dSMatt Spinler                        "SIZE", size);
2995f5352e5SMatt Spinler 
300f77debb9SMatt Spinler             auto rc = _hostIface->sendNewLogCmd(id, size);
301f77debb9SMatt Spinler 
302f77debb9SMatt Spinler             if (rc == CmdStatus::success)
303f77debb9SMatt Spinler             {
304f77debb9SMatt Spinler                 _inProgressPEL = id;
305f77debb9SMatt Spinler             }
306f77debb9SMatt Spinler             else
307f77debb9SMatt Spinler             {
308f77debb9SMatt Spinler                 // It failed.  Retry
3091b41886dSMatt Spinler                 lg2::error("PLDM send failed, PEL ID = {ID}", "ID", lg2::hex,
3101b41886dSMatt Spinler                            id);
311f77debb9SMatt Spinler                 _pelQueue.push_front(id);
312f77debb9SMatt Spinler                 _inProgressPEL = 0;
313f77debb9SMatt Spinler                 _retryTimer.restartOnce(_hostIface->getSendRetryDelay());
314f77debb9SMatt Spinler             }
315f77debb9SMatt Spinler         }
316f77debb9SMatt Spinler         else
317f77debb9SMatt Spinler         {
3181b41886dSMatt Spinler             lg2::error(
3191b41886dSMatt Spinler                 "PEL ID is not in repository. Cannot notify host. PEL ID = {ID}",
3201b41886dSMatt Spinler                 "ID", lg2::hex, id);
321f77debb9SMatt Spinler         }
322f77debb9SMatt Spinler     }
323f60ac27eSMatt Spinler }
324f60ac27eSMatt Spinler 
hostStateChange(bool hostUp)325f60ac27eSMatt Spinler void HostNotifier::hostStateChange(bool hostUp)
326f60ac27eSMatt Spinler {
3273019c6fbSMatt Spinler     _retryCount = 0;
32841293cb8SMatt Spinler     _hostFull = false;
3293019c6fbSMatt Spinler 
3303019c6fbSMatt Spinler     if (hostUp && !_pelQueue.empty())
3313019c6fbSMatt Spinler     {
3321b41886dSMatt Spinler         lg2::debug("Host state change to on");
333e5f7508bSMatt Spinler         _hostUpTimer.restartOnce(_hostIface->getHostUpDelay());
3343019c6fbSMatt Spinler     }
3353019c6fbSMatt Spinler     else if (!hostUp)
3363019c6fbSMatt Spinler     {
3371b41886dSMatt Spinler         lg2::debug("Host state change to off");
3385f5352e5SMatt Spinler 
3393019c6fbSMatt Spinler         stopCommand();
3403019c6fbSMatt Spinler 
3413019c6fbSMatt Spinler         // Reset the state on any PELs that were sent but not acked back
3423019c6fbSMatt Spinler         // to new so they'll get sent again.
3433019c6fbSMatt Spinler         for (auto id : _sentPELs)
3443019c6fbSMatt Spinler         {
3453019c6fbSMatt Spinler             _pelQueue.push_back(id);
3463019c6fbSMatt Spinler             _repo.setPELHostTransState(id, TransmissionState::newPEL);
3473019c6fbSMatt Spinler         }
3483019c6fbSMatt Spinler 
3493019c6fbSMatt Spinler         _sentPELs.clear();
35041293cb8SMatt Spinler 
35141293cb8SMatt Spinler         if (_hostFullTimer.isEnabled())
35241293cb8SMatt Spinler         {
35341293cb8SMatt Spinler             _hostFullTimer.setEnabled(false);
35441293cb8SMatt Spinler         }
355e5f7508bSMatt Spinler 
356e5f7508bSMatt Spinler         if (_hostUpTimer.isEnabled())
357e5f7508bSMatt Spinler         {
358e5f7508bSMatt Spinler             _hostUpTimer.setEnabled(false);
359e5f7508bSMatt Spinler         }
3603019c6fbSMatt Spinler     }
361f60ac27eSMatt Spinler }
362f60ac27eSMatt Spinler 
commandResponse(ResponseStatus status)363f60ac27eSMatt Spinler void HostNotifier::commandResponse(ResponseStatus status)
364f60ac27eSMatt Spinler {
365f869fcf8SMatt Spinler     auto id = _inProgressPEL;
366f869fcf8SMatt Spinler     _inProgressPEL = 0;
367f869fcf8SMatt Spinler 
368f869fcf8SMatt Spinler     if (status == ResponseStatus::success)
369f869fcf8SMatt Spinler     {
3701b41886dSMatt Spinler         lg2::debug("HostNotifier command response success, PEL ID = {ID}", "ID",
3711b41886dSMatt Spinler                    lg2::hex, id);
372f869fcf8SMatt Spinler         _retryCount = 0;
373f869fcf8SMatt Spinler 
374f869fcf8SMatt Spinler         _sentPELs.push_back(id);
375f869fcf8SMatt Spinler 
376f869fcf8SMatt Spinler         _repo.setPELHostTransState(id, TransmissionState::sent);
377f869fcf8SMatt Spinler 
37841293cb8SMatt Spinler         // If the host is full, don't send off the next PEL
37941293cb8SMatt Spinler         if (!_hostFull && !_pelQueue.empty())
380f869fcf8SMatt Spinler         {
381f869fcf8SMatt Spinler             doNewLogNotify();
382f869fcf8SMatt Spinler         }
383f869fcf8SMatt Spinler     }
384f869fcf8SMatt Spinler     else
385f869fcf8SMatt Spinler     {
3861b41886dSMatt Spinler         lg2::error("PLDM command response failure, PEL ID = {ID}", "ID",
3871b41886dSMatt Spinler                    lg2::hex, id);
388f869fcf8SMatt Spinler         // Retry
389f869fcf8SMatt Spinler         _pelQueue.push_front(id);
390f869fcf8SMatt Spinler         _retryTimer.restartOnce(_hostIface->getReceiveRetryDelay());
391f869fcf8SMatt Spinler     }
392f869fcf8SMatt Spinler }
393f869fcf8SMatt Spinler 
retryTimerExpired()394f869fcf8SMatt Spinler void HostNotifier::retryTimerExpired()
395f869fcf8SMatt Spinler {
396f869fcf8SMatt Spinler     if (_dataIface.isHostUp())
397f869fcf8SMatt Spinler     {
3981b41886dSMatt Spinler         lg2::info("Attempting command retry, PEL ID = {ID}", "ID", lg2::hex,
3991b41886dSMatt Spinler                   _pelQueue.front());
400f869fcf8SMatt Spinler         _retryCount++;
401f869fcf8SMatt Spinler         doNewLogNotify();
402f869fcf8SMatt Spinler     }
403f60ac27eSMatt Spinler }
404f60ac27eSMatt Spinler 
hostFullTimerExpired()40541293cb8SMatt Spinler void HostNotifier::hostFullTimerExpired()
40641293cb8SMatt Spinler {
4071b41886dSMatt Spinler     lg2::debug("Host full timer expired, trying send again");
40841293cb8SMatt Spinler     doNewLogNotify();
40941293cb8SMatt Spinler }
41041293cb8SMatt Spinler 
stopCommand()4113019c6fbSMatt Spinler void HostNotifier::stopCommand()
4123019c6fbSMatt Spinler {
4133019c6fbSMatt Spinler     _retryCount = 0;
4143019c6fbSMatt Spinler 
4153019c6fbSMatt Spinler     if (_inProgressPEL != 0)
4163019c6fbSMatt Spinler     {
4173019c6fbSMatt Spinler         _pelQueue.push_front(_inProgressPEL);
4183019c6fbSMatt Spinler         _inProgressPEL = 0;
4193019c6fbSMatt Spinler     }
4203019c6fbSMatt Spinler 
4213019c6fbSMatt Spinler     if (_retryTimer.isEnabled())
4223019c6fbSMatt Spinler     {
4233019c6fbSMatt Spinler         _retryTimer.setEnabled(false);
4243019c6fbSMatt Spinler     }
4253019c6fbSMatt Spinler 
426829b052dSMatt Spinler     // Ensure the PLDM instance ID is released
4273019c6fbSMatt Spinler     _hostIface->cancelCmd();
4283019c6fbSMatt Spinler }
4293019c6fbSMatt Spinler 
ackPEL(uint32_t id)430cc3b64aeSMatt Spinler void HostNotifier::ackPEL(uint32_t id)
431cc3b64aeSMatt Spinler {
432cc3b64aeSMatt Spinler     _repo.setPELHostTransState(id, TransmissionState::acked);
433cc3b64aeSMatt Spinler 
434cc3b64aeSMatt Spinler     // No longer just 'sent', so remove it from the sent list.
435cc3b64aeSMatt Spinler     auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id);
436cc3b64aeSMatt Spinler     if (sent != _sentPELs.end())
437cc3b64aeSMatt Spinler     {
438cc3b64aeSMatt Spinler         _sentPELs.erase(sent);
439cc3b64aeSMatt Spinler     }
44041293cb8SMatt Spinler 
44141293cb8SMatt Spinler     // An ack means the host is no longer full
44241293cb8SMatt Spinler     if (_hostFullTimer.isEnabled())
44341293cb8SMatt Spinler     {
44441293cb8SMatt Spinler         _hostFullTimer.setEnabled(false);
44541293cb8SMatt Spinler     }
44641293cb8SMatt Spinler 
44741293cb8SMatt Spinler     if (_hostFull)
44841293cb8SMatt Spinler     {
44941293cb8SMatt Spinler         _hostFull = false;
45041293cb8SMatt Spinler 
4511b41886dSMatt Spinler         lg2::debug("Host previously full, not anymore after this ack");
4525f5352e5SMatt Spinler 
45341293cb8SMatt Spinler         // Start sending PELs again, from the event loop
45441293cb8SMatt Spinler         if (!_pelQueue.empty())
45541293cb8SMatt Spinler         {
45641293cb8SMatt Spinler             scheduleDispatch();
45741293cb8SMatt Spinler         }
45841293cb8SMatt Spinler     }
45941293cb8SMatt Spinler }
46041293cb8SMatt Spinler 
setHostFull(uint32_t id)46141293cb8SMatt Spinler void HostNotifier::setHostFull(uint32_t id)
46241293cb8SMatt Spinler {
463610e80f4SMatt Spinler     lg2::debug("Received Host full indication, PEL ID = {ID}", "ID", lg2::hex,
4641b41886dSMatt Spinler                id);
46541293cb8SMatt Spinler 
46641293cb8SMatt Spinler     _hostFull = true;
46741293cb8SMatt Spinler 
46841293cb8SMatt Spinler     // This PEL needs to get re-sent
46941293cb8SMatt Spinler     auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id);
47041293cb8SMatt Spinler     if (sent != _sentPELs.end())
47141293cb8SMatt Spinler     {
47241293cb8SMatt Spinler         _sentPELs.erase(sent);
47341293cb8SMatt Spinler         _repo.setPELHostTransState(id, TransmissionState::newPEL);
47441293cb8SMatt Spinler 
47541293cb8SMatt Spinler         if (std::find(_pelQueue.begin(), _pelQueue.end(), id) ==
47641293cb8SMatt Spinler             _pelQueue.end())
47741293cb8SMatt Spinler         {
47841293cb8SMatt Spinler             _pelQueue.push_front(id);
47941293cb8SMatt Spinler         }
48041293cb8SMatt Spinler     }
48141293cb8SMatt Spinler 
48241293cb8SMatt Spinler     // The only PELs that will be sent when the
48341293cb8SMatt Spinler     // host is full is from this timer callback.
48441293cb8SMatt Spinler     if (!_hostFullTimer.isEnabled())
48541293cb8SMatt Spinler     {
4861b41886dSMatt Spinler         lg2::debug("Starting host full timer");
48741293cb8SMatt Spinler         _hostFullTimer.restartOnce(_hostIface->getHostFullRetryDelay());
48841293cb8SMatt Spinler     }
489cc3b64aeSMatt Spinler }
490cc3b64aeSMatt Spinler 
setBadPEL(uint32_t id)491a19b6234SMatt Spinler void HostNotifier::setBadPEL(uint32_t id)
492a19b6234SMatt Spinler {
4931b41886dSMatt Spinler     lg2::error("PEL rejected by the host, PEL ID = {ID}", "ID", lg2::hex, id);
494a19b6234SMatt Spinler 
495a19b6234SMatt Spinler     auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id);
496a19b6234SMatt Spinler     if (sent != _sentPELs.end())
497a19b6234SMatt Spinler     {
498a19b6234SMatt Spinler         _sentPELs.erase(sent);
499a19b6234SMatt Spinler     }
500a19b6234SMatt Spinler 
501a19b6234SMatt Spinler     _repo.setPELHostTransState(id, TransmissionState::badPEL);
502a19b6234SMatt Spinler }
503a19b6234SMatt Spinler 
504f60ac27eSMatt Spinler } // namespace openpower::pels
505