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) :
28f60ac27eSMatt Spinler _repo(repo),
29f869fcf8SMatt Spinler _dataIface(dataIface), _hostIface(std::move(hostIface)),
30f869fcf8SMatt Spinler _retryTimer(_hostIface->getEvent(),
3141293cb8SMatt Spinler std::bind(std::mem_fn(&HostNotifier::retryTimerExpired), this)),
3241293cb8SMatt Spinler _hostFullTimer(
3341293cb8SMatt Spinler _hostIface->getEvent(),
34e5f7508bSMatt Spinler std::bind(std::mem_fn(&HostNotifier::hostFullTimerExpired), this)),
35e5f7508bSMatt Spinler _hostUpTimer(
36e5f7508bSMatt Spinler _hostIface->getEvent(),
37e5f7508bSMatt Spinler std::bind(std::mem_fn(&HostNotifier::hostUpTimerExpired), this))
38f60ac27eSMatt Spinler {
39f60ac27eSMatt Spinler // Subscribe to be told about new PELs.
40f60ac27eSMatt Spinler _repo.subscribeToAdds(subscriptionName,
41f60ac27eSMatt Spinler std::bind(std::mem_fn(&HostNotifier::newLogCallback),
42f60ac27eSMatt Spinler this, std::placeholders::_1));
43f60ac27eSMatt Spinler
447cb985ffSMatt Spinler // Subscribe to be told about deleted PELs.
457cb985ffSMatt Spinler _repo.subscribeToDeletes(
467cb985ffSMatt Spinler subscriptionName,
477cb985ffSMatt Spinler std::bind(std::mem_fn(&HostNotifier::deleteLogCallback), this,
487cb985ffSMatt Spinler std::placeholders::_1));
497cb985ffSMatt Spinler
50f60ac27eSMatt Spinler // Add any existing PELs to the queue to send them if necessary.
51f60ac27eSMatt Spinler _repo.for_each(std::bind(std::mem_fn(&HostNotifier::addPELToQueue), this,
52f60ac27eSMatt Spinler std::placeholders::_1));
53f60ac27eSMatt Spinler
54f60ac27eSMatt Spinler // Subscribe to be told about host state changes.
55f60ac27eSMatt Spinler _dataIface.subscribeToHostStateChange(
564f1bed7eSMatt Spinler subscriptionName, std::bind(std::mem_fn(&HostNotifier::hostStateChange),
574f1bed7eSMatt Spinler this, 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 {
671b41886dSMatt Spinler lg2::debug("Host is already up at startup");
68e5f7508bSMatt Spinler _hostUpTimer.restartOnce(_hostIface->getHostUpDelay());
69f60ac27eSMatt Spinler }
70f60ac27eSMatt Spinler }
71f60ac27eSMatt Spinler
~HostNotifier()72f60ac27eSMatt Spinler HostNotifier::~HostNotifier()
73f60ac27eSMatt Spinler {
74f60ac27eSMatt Spinler _repo.unsubscribeFromAdds(subscriptionName);
75f60ac27eSMatt Spinler _dataIface.unsubscribeFromHostStateChange(subscriptionName);
76f60ac27eSMatt Spinler }
77f60ac27eSMatt Spinler
hostUpTimerExpired()78e5f7508bSMatt Spinler void HostNotifier::hostUpTimerExpired()
79e5f7508bSMatt Spinler {
801b41886dSMatt Spinler lg2::debug("Host up timer expired");
81e5f7508bSMatt Spinler doNewLogNotify();
82e5f7508bSMatt Spinler }
83e5f7508bSMatt Spinler
addPELToQueue(const PEL & pel)84f60ac27eSMatt Spinler bool HostNotifier::addPELToQueue(const PEL& pel)
85f60ac27eSMatt Spinler {
86f60ac27eSMatt Spinler if (enqueueRequired(pel.id()))
87f60ac27eSMatt Spinler {
88f60ac27eSMatt Spinler _pelQueue.push_back(pel.id());
89f60ac27eSMatt Spinler }
90f60ac27eSMatt Spinler
91f60ac27eSMatt Spinler // Return false so that Repo::for_each keeps going.
92f60ac27eSMatt Spinler return false;
93f60ac27eSMatt Spinler }
94f60ac27eSMatt Spinler
enqueueRequired(uint32_t id) const95f60ac27eSMatt Spinler bool HostNotifier::enqueueRequired(uint32_t id) const
96f60ac27eSMatt Spinler {
97f60ac27eSMatt Spinler bool required = true;
98a943b15bSMatt Spinler Repository::LogID i{Repository::LogID::Pel{id}};
99a943b15bSMatt Spinler
10024a8558bSMatt Spinler // Manufacturing testing may turn off sending up PELs
10124a8558bSMatt Spinler if (!_dataIface.getHostPELEnablement())
10224a8558bSMatt Spinler {
10324a8558bSMatt Spinler return false;
10424a8558bSMatt Spinler }
10524a8558bSMatt Spinler
106a943b15bSMatt Spinler if (auto attributes = _repo.getPELAttributes(i); attributes)
107a943b15bSMatt Spinler {
108a943b15bSMatt Spinler auto a = attributes.value().get();
109a943b15bSMatt Spinler
110a943b15bSMatt Spinler if ((a.hostState == TransmissionState::acked) ||
111a943b15bSMatt Spinler (a.hostState == TransmissionState::badPEL))
112a943b15bSMatt Spinler {
113a943b15bSMatt Spinler required = false;
114a943b15bSMatt Spinler }
115a943b15bSMatt Spinler else if (a.actionFlags.test(hiddenFlagBit) &&
116a943b15bSMatt Spinler (a.hmcState == TransmissionState::acked))
117a943b15bSMatt Spinler {
118a943b15bSMatt Spinler required = false;
119a943b15bSMatt Spinler }
120a943b15bSMatt Spinler else if (a.actionFlags.test(dontReportToHostFlagBit))
121a943b15bSMatt Spinler {
122a943b15bSMatt Spinler required = false;
123a943b15bSMatt Spinler }
124a943b15bSMatt Spinler }
125a943b15bSMatt Spinler else
126a943b15bSMatt Spinler {
127a943b15bSMatt Spinler using namespace phosphor::logging;
1281b41886dSMatt Spinler lg2::error("Host Enqueue: Unable to find PEL ID {ID} in repository",
1291b41886dSMatt Spinler "ID", lg2::hex, id);
130a943b15bSMatt Spinler required = false;
131a943b15bSMatt Spinler }
132f60ac27eSMatt Spinler
133f60ac27eSMatt Spinler return required;
134f60ac27eSMatt Spinler }
135f60ac27eSMatt Spinler
notifyRequired(uint32_t id) const136f77debb9SMatt Spinler bool HostNotifier::notifyRequired(uint32_t id) const
137f77debb9SMatt Spinler {
138f77debb9SMatt Spinler bool notify = true;
139f77debb9SMatt Spinler Repository::LogID i{Repository::LogID::Pel{id}};
140f77debb9SMatt Spinler
141f77debb9SMatt Spinler if (auto attributes = _repo.getPELAttributes(i); attributes)
142f77debb9SMatt Spinler {
143f77debb9SMatt Spinler // If already acked by the host, don't send again.
144f77debb9SMatt Spinler // (A safety check as it shouldn't get to this point.)
145f77debb9SMatt Spinler auto a = attributes.value().get();
146f77debb9SMatt Spinler if (a.hostState == TransmissionState::acked)
147f77debb9SMatt Spinler {
148f77debb9SMatt Spinler notify = false;
149f77debb9SMatt Spinler }
150f77debb9SMatt Spinler else if (a.actionFlags.test(hiddenFlagBit))
151f77debb9SMatt Spinler {
152f77debb9SMatt Spinler // If hidden and acked (or will be) acked by the HMC,
153f77debb9SMatt Spinler // also don't send it. (HMC management can come and
154f77debb9SMatt Spinler // go at any time)
155f77debb9SMatt Spinler if ((a.hmcState == TransmissionState::acked) ||
156f77debb9SMatt Spinler _dataIface.isHMCManaged())
157f77debb9SMatt Spinler {
158f77debb9SMatt Spinler notify = false;
159f77debb9SMatt Spinler }
160f77debb9SMatt Spinler }
161f77debb9SMatt Spinler }
162f77debb9SMatt Spinler else
163f77debb9SMatt Spinler {
164f77debb9SMatt Spinler // Must have been deleted since put on the queue.
165f77debb9SMatt Spinler notify = false;
166f77debb9SMatt Spinler }
167f77debb9SMatt Spinler
168f77debb9SMatt Spinler return notify;
169f77debb9SMatt Spinler }
170f77debb9SMatt Spinler
newLogCallback(const PEL & pel)171f60ac27eSMatt Spinler void HostNotifier::newLogCallback(const PEL& pel)
172f60ac27eSMatt Spinler {
173f60ac27eSMatt Spinler if (!enqueueRequired(pel.id()))
174f60ac27eSMatt Spinler {
175f60ac27eSMatt Spinler return;
176f60ac27eSMatt Spinler }
177f60ac27eSMatt Spinler
1781b41886dSMatt Spinler lg2::debug("New PEL added to queue, PEL ID = {ID}", "ID", lg2::hex,
1791b41886dSMatt Spinler pel.id());
1805f5352e5SMatt Spinler
181f60ac27eSMatt Spinler _pelQueue.push_back(pel.id());
182f60ac27eSMatt Spinler
183e5f7508bSMatt Spinler // Notify shouldn't happen if host is down, not up long enough, or full
184e5f7508bSMatt Spinler if (!_dataIface.isHostUp() || _hostFull || _hostUpTimer.isEnabled())
1857d800a4eSMatt Spinler {
1867d800a4eSMatt Spinler return;
1877d800a4eSMatt Spinler }
1887d800a4eSMatt Spinler
1897d800a4eSMatt Spinler // Dispatch a command now if there isn't currently a command
1907d800a4eSMatt Spinler // in progress and this is the first log in the queue or it
1917d800a4eSMatt Spinler // previously gave up from a hard failure.
1927d800a4eSMatt Spinler auto inProgress = (_inProgressPEL != 0) || _hostIface->cmdInProgress() ||
1937d800a4eSMatt Spinler _retryTimer.isEnabled();
1947d800a4eSMatt Spinler
1957d800a4eSMatt Spinler auto firstPEL = _pelQueue.size() == 1;
1967d800a4eSMatt Spinler auto gaveUp = _retryCount >= maxRetryAttempts;
1977d800a4eSMatt Spinler
1987d800a4eSMatt Spinler if (!inProgress && (firstPEL || gaveUp))
1997d800a4eSMatt Spinler {
2007d800a4eSMatt Spinler _retryCount = 0;
2017d800a4eSMatt Spinler
2027d800a4eSMatt Spinler // Send a log, but from the event loop, not from here.
2037d800a4eSMatt Spinler scheduleDispatch();
2047d800a4eSMatt Spinler }
2057d800a4eSMatt Spinler }
2067d800a4eSMatt Spinler
deleteLogCallback(uint32_t id)2077cb985ffSMatt Spinler void HostNotifier::deleteLogCallback(uint32_t id)
2087cb985ffSMatt Spinler {
2097cb985ffSMatt Spinler auto queueIt = std::find(_pelQueue.begin(), _pelQueue.end(), id);
2107cb985ffSMatt Spinler if (queueIt != _pelQueue.end())
2117cb985ffSMatt Spinler {
2121b41886dSMatt Spinler lg2::debug("Host notifier removing deleted log from queue");
2137cb985ffSMatt Spinler _pelQueue.erase(queueIt);
2147cb985ffSMatt Spinler }
2157cb985ffSMatt Spinler
2167cb985ffSMatt Spinler auto sentIt = std::find(_sentPELs.begin(), _sentPELs.end(), id);
2177cb985ffSMatt Spinler if (sentIt != _sentPELs.end())
2187cb985ffSMatt Spinler {
2191b41886dSMatt Spinler lg2::debug("Host notifier removing deleted log from sent list");
2207cb985ffSMatt Spinler _sentPELs.erase(sentIt);
2217cb985ffSMatt Spinler }
2227cb985ffSMatt Spinler
2237cb985ffSMatt Spinler // Nothing we can do about this...
2247cb985ffSMatt Spinler if (id == _inProgressPEL)
2257cb985ffSMatt Spinler {
2261b41886dSMatt Spinler lg2::warning(
2271b41886dSMatt Spinler "A PEL was deleted while its host notification was in progress, PEL ID = {ID}",
2281b41886dSMatt Spinler "ID", lg2::hex, id);
2297cb985ffSMatt Spinler }
2307cb985ffSMatt Spinler }
2317cb985ffSMatt Spinler
scheduleDispatch()2327d800a4eSMatt Spinler void HostNotifier::scheduleDispatch()
2337d800a4eSMatt Spinler {
2347d800a4eSMatt Spinler _dispatcher = std::make_unique<sdeventplus::source::Defer>(
2357d800a4eSMatt Spinler _hostIface->getEvent(), std::bind(std::mem_fn(&HostNotifier::dispatch),
2367d800a4eSMatt Spinler this, std::placeholders::_1));
2377d800a4eSMatt Spinler }
2387d800a4eSMatt Spinler
dispatch(sdeventplus::source::EventBase &)239d26fa3e7SPatrick Williams void HostNotifier::dispatch(sdeventplus::source::EventBase& /*source*/)
2407d800a4eSMatt Spinler {
2417d800a4eSMatt Spinler _dispatcher.reset();
2427d800a4eSMatt Spinler
2437d800a4eSMatt Spinler doNewLogNotify();
244f60ac27eSMatt Spinler }
245f60ac27eSMatt Spinler
doNewLogNotify()246f60ac27eSMatt Spinler void HostNotifier::doNewLogNotify()
247f60ac27eSMatt Spinler {
24841293cb8SMatt Spinler if (!_dataIface.isHostUp() || _retryTimer.isEnabled() ||
24941293cb8SMatt Spinler _hostFullTimer.isEnabled())
250f77debb9SMatt Spinler {
251f77debb9SMatt Spinler return;
252f77debb9SMatt Spinler }
253f77debb9SMatt Spinler
254f77debb9SMatt Spinler if (_retryCount >= maxRetryAttempts)
255f77debb9SMatt Spinler {
256f77debb9SMatt Spinler // Give up until a new log comes in.
257f77debb9SMatt Spinler if (_retryCount == maxRetryAttempts)
258f77debb9SMatt Spinler {
259f77debb9SMatt Spinler // If this were to really happen, the PLDM interface
260f77debb9SMatt Spinler // would be down and isolating that shouldn't left to
261f77debb9SMatt Spinler // a logging daemon, so just trace. Also, this will start
262f77debb9SMatt Spinler // trying again when the next new log comes in.
2631b41886dSMatt Spinler lg2::error(
2641b41886dSMatt Spinler "PEL Host notifier hit max retry attempts. Giving up for now. PEL ID = {ID}",
2651b41886dSMatt Spinler "ID", lg2::hex, _pelQueue.front());
266829b052dSMatt Spinler
267829b052dSMatt Spinler // Tell the host interface object to clean itself up, especially to
268829b052dSMatt Spinler // release the PLDM instance ID it's been using.
269829b052dSMatt Spinler _hostIface->cancelCmd();
270f77debb9SMatt Spinler }
271f77debb9SMatt Spinler return;
272f77debb9SMatt Spinler }
273f77debb9SMatt Spinler
274f77debb9SMatt Spinler bool doNotify = false;
275f77debb9SMatt Spinler uint32_t id = 0;
276f77debb9SMatt Spinler
277f77debb9SMatt Spinler // Find the PEL to send
278f77debb9SMatt Spinler while (!doNotify && !_pelQueue.empty())
279f77debb9SMatt Spinler {
280f77debb9SMatt Spinler id = _pelQueue.front();
281f77debb9SMatt Spinler _pelQueue.pop_front();
282f77debb9SMatt Spinler
283f77debb9SMatt Spinler if (notifyRequired(id))
284f77debb9SMatt Spinler {
285f77debb9SMatt Spinler doNotify = true;
286f77debb9SMatt Spinler }
287f77debb9SMatt Spinler }
288f77debb9SMatt Spinler
289f77debb9SMatt Spinler if (doNotify)
290f77debb9SMatt Spinler {
291f77debb9SMatt Spinler // Get the size using the repo attributes
292f77debb9SMatt Spinler Repository::LogID i{Repository::LogID::Pel{id}};
293f77debb9SMatt Spinler if (auto attributes = _repo.getPELAttributes(i); attributes)
294f77debb9SMatt Spinler {
295f77debb9SMatt Spinler auto size = static_cast<size_t>(
296f77debb9SMatt Spinler std::filesystem::file_size((*attributes).get().path));
2975f5352e5SMatt Spinler
2981b41886dSMatt Spinler lg2::debug("sendNewLogCmd: ID {ID} size {SIZE}", "ID", lg2::hex, id,
2991b41886dSMatt Spinler "SIZE", size);
3005f5352e5SMatt Spinler
301f77debb9SMatt Spinler auto rc = _hostIface->sendNewLogCmd(id, size);
302f77debb9SMatt Spinler
303f77debb9SMatt Spinler if (rc == CmdStatus::success)
304f77debb9SMatt Spinler {
305f77debb9SMatt Spinler _inProgressPEL = id;
306f77debb9SMatt Spinler }
307f77debb9SMatt Spinler else
308f77debb9SMatt Spinler {
309f77debb9SMatt Spinler // It failed. Retry
3101b41886dSMatt Spinler lg2::error("PLDM send failed, PEL ID = {ID}", "ID", lg2::hex,
3111b41886dSMatt Spinler id);
312f77debb9SMatt Spinler _pelQueue.push_front(id);
313f77debb9SMatt Spinler _inProgressPEL = 0;
314f77debb9SMatt Spinler _retryTimer.restartOnce(_hostIface->getSendRetryDelay());
315f77debb9SMatt Spinler }
316f77debb9SMatt Spinler }
317f77debb9SMatt Spinler else
318f77debb9SMatt Spinler {
3191b41886dSMatt Spinler lg2::error(
3201b41886dSMatt Spinler "PEL ID is not in repository. Cannot notify host. PEL ID = {ID}",
3211b41886dSMatt Spinler "ID", lg2::hex, id);
322f77debb9SMatt Spinler }
323f77debb9SMatt Spinler }
324f60ac27eSMatt Spinler }
325f60ac27eSMatt Spinler
hostStateChange(bool hostUp)326f60ac27eSMatt Spinler void HostNotifier::hostStateChange(bool hostUp)
327f60ac27eSMatt Spinler {
3283019c6fbSMatt Spinler _retryCount = 0;
32941293cb8SMatt Spinler _hostFull = false;
3303019c6fbSMatt Spinler
3313019c6fbSMatt Spinler if (hostUp && !_pelQueue.empty())
3323019c6fbSMatt Spinler {
3331b41886dSMatt Spinler lg2::debug("Host state change to on");
334e5f7508bSMatt Spinler _hostUpTimer.restartOnce(_hostIface->getHostUpDelay());
3353019c6fbSMatt Spinler }
3363019c6fbSMatt Spinler else if (!hostUp)
3373019c6fbSMatt Spinler {
3381b41886dSMatt Spinler lg2::debug("Host state change to off");
3395f5352e5SMatt Spinler
3403019c6fbSMatt Spinler stopCommand();
3413019c6fbSMatt Spinler
3423019c6fbSMatt Spinler // Reset the state on any PELs that were sent but not acked back
3433019c6fbSMatt Spinler // to new so they'll get sent again.
3443019c6fbSMatt Spinler for (auto id : _sentPELs)
3453019c6fbSMatt Spinler {
3463019c6fbSMatt Spinler _pelQueue.push_back(id);
3473019c6fbSMatt Spinler _repo.setPELHostTransState(id, TransmissionState::newPEL);
3483019c6fbSMatt Spinler }
3493019c6fbSMatt Spinler
3503019c6fbSMatt Spinler _sentPELs.clear();
35141293cb8SMatt Spinler
35241293cb8SMatt Spinler if (_hostFullTimer.isEnabled())
35341293cb8SMatt Spinler {
35441293cb8SMatt Spinler _hostFullTimer.setEnabled(false);
35541293cb8SMatt Spinler }
356e5f7508bSMatt Spinler
357e5f7508bSMatt Spinler if (_hostUpTimer.isEnabled())
358e5f7508bSMatt Spinler {
359e5f7508bSMatt Spinler _hostUpTimer.setEnabled(false);
360e5f7508bSMatt Spinler }
3613019c6fbSMatt Spinler }
362f60ac27eSMatt Spinler }
363f60ac27eSMatt Spinler
commandResponse(ResponseStatus status)364f60ac27eSMatt Spinler void HostNotifier::commandResponse(ResponseStatus status)
365f60ac27eSMatt Spinler {
366f869fcf8SMatt Spinler auto id = _inProgressPEL;
367f869fcf8SMatt Spinler _inProgressPEL = 0;
368f869fcf8SMatt Spinler
369f869fcf8SMatt Spinler if (status == ResponseStatus::success)
370f869fcf8SMatt Spinler {
3711b41886dSMatt Spinler lg2::debug("HostNotifier command response success, PEL ID = {ID}", "ID",
3721b41886dSMatt Spinler lg2::hex, id);
373f869fcf8SMatt Spinler _retryCount = 0;
374f869fcf8SMatt Spinler
375f869fcf8SMatt Spinler _sentPELs.push_back(id);
376f869fcf8SMatt Spinler
377f869fcf8SMatt Spinler _repo.setPELHostTransState(id, TransmissionState::sent);
378f869fcf8SMatt Spinler
37941293cb8SMatt Spinler // If the host is full, don't send off the next PEL
38041293cb8SMatt Spinler if (!_hostFull && !_pelQueue.empty())
381f869fcf8SMatt Spinler {
382f869fcf8SMatt Spinler doNewLogNotify();
383f869fcf8SMatt Spinler }
384f869fcf8SMatt Spinler }
385f869fcf8SMatt Spinler else
386f869fcf8SMatt Spinler {
3871b41886dSMatt Spinler lg2::error("PLDM command response failure, PEL ID = {ID}", "ID",
3881b41886dSMatt Spinler lg2::hex, id);
389f869fcf8SMatt Spinler // Retry
390f869fcf8SMatt Spinler _pelQueue.push_front(id);
391f869fcf8SMatt Spinler _retryTimer.restartOnce(_hostIface->getReceiveRetryDelay());
392f869fcf8SMatt Spinler }
393f869fcf8SMatt Spinler }
394f869fcf8SMatt Spinler
retryTimerExpired()395f869fcf8SMatt Spinler void HostNotifier::retryTimerExpired()
396f869fcf8SMatt Spinler {
397f869fcf8SMatt Spinler if (_dataIface.isHostUp())
398f869fcf8SMatt Spinler {
3991b41886dSMatt Spinler lg2::info("Attempting command retry, PEL ID = {ID}", "ID", lg2::hex,
4001b41886dSMatt Spinler _pelQueue.front());
401f869fcf8SMatt Spinler _retryCount++;
402f869fcf8SMatt Spinler doNewLogNotify();
403f869fcf8SMatt Spinler }
404f60ac27eSMatt Spinler }
405f60ac27eSMatt Spinler
hostFullTimerExpired()40641293cb8SMatt Spinler void HostNotifier::hostFullTimerExpired()
40741293cb8SMatt Spinler {
4081b41886dSMatt Spinler lg2::debug("Host full timer expired, trying send again");
40941293cb8SMatt Spinler doNewLogNotify();
41041293cb8SMatt Spinler }
41141293cb8SMatt Spinler
stopCommand()4123019c6fbSMatt Spinler void HostNotifier::stopCommand()
4133019c6fbSMatt Spinler {
4143019c6fbSMatt Spinler _retryCount = 0;
4153019c6fbSMatt Spinler
4163019c6fbSMatt Spinler if (_inProgressPEL != 0)
4173019c6fbSMatt Spinler {
4183019c6fbSMatt Spinler _pelQueue.push_front(_inProgressPEL);
4193019c6fbSMatt Spinler _inProgressPEL = 0;
4203019c6fbSMatt Spinler }
4213019c6fbSMatt Spinler
4223019c6fbSMatt Spinler if (_retryTimer.isEnabled())
4233019c6fbSMatt Spinler {
4243019c6fbSMatt Spinler _retryTimer.setEnabled(false);
4253019c6fbSMatt Spinler }
4263019c6fbSMatt Spinler
427829b052dSMatt Spinler // Ensure the PLDM instance ID is released
4283019c6fbSMatt Spinler _hostIface->cancelCmd();
4293019c6fbSMatt Spinler }
4303019c6fbSMatt Spinler
ackPEL(uint32_t id)431cc3b64aeSMatt Spinler void HostNotifier::ackPEL(uint32_t id)
432cc3b64aeSMatt Spinler {
433cc3b64aeSMatt Spinler _repo.setPELHostTransState(id, TransmissionState::acked);
434cc3b64aeSMatt Spinler
435cc3b64aeSMatt Spinler // No longer just 'sent', so remove it from the sent list.
436cc3b64aeSMatt Spinler auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id);
437cc3b64aeSMatt Spinler if (sent != _sentPELs.end())
438cc3b64aeSMatt Spinler {
439cc3b64aeSMatt Spinler _sentPELs.erase(sent);
440cc3b64aeSMatt Spinler }
44141293cb8SMatt Spinler
44241293cb8SMatt Spinler // An ack means the host is no longer full
44341293cb8SMatt Spinler if (_hostFullTimer.isEnabled())
44441293cb8SMatt Spinler {
44541293cb8SMatt Spinler _hostFullTimer.setEnabled(false);
44641293cb8SMatt Spinler }
44741293cb8SMatt Spinler
44841293cb8SMatt Spinler if (_hostFull)
44941293cb8SMatt Spinler {
45041293cb8SMatt Spinler _hostFull = false;
45141293cb8SMatt Spinler
4521b41886dSMatt Spinler lg2::debug("Host previously full, not anymore after this ack");
4535f5352e5SMatt Spinler
45441293cb8SMatt Spinler // Start sending PELs again, from the event loop
45541293cb8SMatt Spinler if (!_pelQueue.empty())
45641293cb8SMatt Spinler {
45741293cb8SMatt Spinler scheduleDispatch();
45841293cb8SMatt Spinler }
45941293cb8SMatt Spinler }
46041293cb8SMatt Spinler }
46141293cb8SMatt Spinler
setHostFull(uint32_t id)46241293cb8SMatt Spinler void HostNotifier::setHostFull(uint32_t id)
46341293cb8SMatt Spinler {
464*610e80f4SMatt Spinler lg2::debug("Received Host full indication, PEL ID = {ID}", "ID", lg2::hex,
4651b41886dSMatt Spinler id);
46641293cb8SMatt Spinler
46741293cb8SMatt Spinler _hostFull = true;
46841293cb8SMatt Spinler
46941293cb8SMatt Spinler // This PEL needs to get re-sent
47041293cb8SMatt Spinler auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id);
47141293cb8SMatt Spinler if (sent != _sentPELs.end())
47241293cb8SMatt Spinler {
47341293cb8SMatt Spinler _sentPELs.erase(sent);
47441293cb8SMatt Spinler _repo.setPELHostTransState(id, TransmissionState::newPEL);
47541293cb8SMatt Spinler
47641293cb8SMatt Spinler if (std::find(_pelQueue.begin(), _pelQueue.end(), id) ==
47741293cb8SMatt Spinler _pelQueue.end())
47841293cb8SMatt Spinler {
47941293cb8SMatt Spinler _pelQueue.push_front(id);
48041293cb8SMatt Spinler }
48141293cb8SMatt Spinler }
48241293cb8SMatt Spinler
48341293cb8SMatt Spinler // The only PELs that will be sent when the
48441293cb8SMatt Spinler // host is full is from this timer callback.
48541293cb8SMatt Spinler if (!_hostFullTimer.isEnabled())
48641293cb8SMatt Spinler {
4871b41886dSMatt Spinler lg2::debug("Starting host full timer");
48841293cb8SMatt Spinler _hostFullTimer.restartOnce(_hostIface->getHostFullRetryDelay());
48941293cb8SMatt Spinler }
490cc3b64aeSMatt Spinler }
491cc3b64aeSMatt Spinler
setBadPEL(uint32_t id)492a19b6234SMatt Spinler void HostNotifier::setBadPEL(uint32_t id)
493a19b6234SMatt Spinler {
4941b41886dSMatt Spinler lg2::error("PEL rejected by the host, PEL ID = {ID}", "ID", lg2::hex, id);
495a19b6234SMatt Spinler
496a19b6234SMatt Spinler auto sent = std::find(_sentPELs.begin(), _sentPELs.end(), id);
497a19b6234SMatt Spinler if (sent != _sentPELs.end())
498a19b6234SMatt Spinler {
499a19b6234SMatt Spinler _sentPELs.erase(sent);
500a19b6234SMatt Spinler }
501a19b6234SMatt Spinler
502a19b6234SMatt Spinler _repo.setPELHostTransState(id, TransmissionState::badPEL);
503a19b6234SMatt Spinler }
504a19b6234SMatt Spinler
505f60ac27eSMatt Spinler } // namespace openpower::pels
506