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