blob: b935f7e58cfcea8c11ea5017d3e601f161435f85 [file] [log] [blame]
Matt Spinlerf60ac272019-12-11 13:47:50 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "host_notifier.hpp"
17
18#include <phosphor-logging/log.hpp>
19
20namespace openpower::pels
21{
22
23const auto subscriptionName = "PELHostNotifier";
24
25using namespace phosphor::logging;
26
27HostNotifier::HostNotifier(Repository& repo, DataInterfaceBase& dataIface,
28 std::unique_ptr<HostInterface> hostIface) :
29 _repo(repo),
Matt Spinlerf869fcf2019-12-11 15:02:20 -060030 _dataIface(dataIface), _hostIface(std::move(hostIface)),
31 _retryTimer(_hostIface->getEvent(),
32 std::bind(std::mem_fn(&HostNotifier::retryTimerExpired), this))
Matt Spinlerf60ac272019-12-11 13:47:50 -060033{
34 // Subscribe to be told about new PELs.
35 _repo.subscribeToAdds(subscriptionName,
36 std::bind(std::mem_fn(&HostNotifier::newLogCallback),
37 this, std::placeholders::_1));
38
39 // Add any existing PELs to the queue to send them if necessary.
40 _repo.for_each(std::bind(std::mem_fn(&HostNotifier::addPELToQueue), this,
41 std::placeholders::_1));
42
43 // Subscribe to be told about host state changes.
44 _dataIface.subscribeToHostStateChange(
45 subscriptionName,
46 std::bind(std::mem_fun(&HostNotifier::hostStateChange), this,
47 std::placeholders::_1));
48
49 // Set the function to call when the async reponse is received.
50 _hostIface->setResponseFunction(
51 std::bind(std::mem_fn(&HostNotifier::commandResponse), this,
52 std::placeholders::_1));
53
54 // Start sending logs if the host is running
55 if (!_pelQueue.empty() && _dataIface.isHostUp())
56 {
57 doNewLogNotify();
58 }
59}
60
61HostNotifier::~HostNotifier()
62{
63 _repo.unsubscribeFromAdds(subscriptionName);
64 _dataIface.unsubscribeFromHostStateChange(subscriptionName);
65}
66
67bool HostNotifier::addPELToQueue(const PEL& pel)
68{
69 if (enqueueRequired(pel.id()))
70 {
71 _pelQueue.push_back(pel.id());
72 }
73
74 // Return false so that Repo::for_each keeps going.
75 return false;
76}
77
78bool HostNotifier::enqueueRequired(uint32_t id) const
79{
80 bool required = true;
Matt Spinlera943b152019-12-11 14:44:50 -060081 Repository::LogID i{Repository::LogID::Pel{id}};
82
83 if (auto attributes = _repo.getPELAttributes(i); attributes)
84 {
85 auto a = attributes.value().get();
86
87 if ((a.hostState == TransmissionState::acked) ||
88 (a.hostState == TransmissionState::badPEL))
89 {
90 required = false;
91 }
92 else if (a.actionFlags.test(hiddenFlagBit) &&
93 (a.hmcState == TransmissionState::acked))
94 {
95 required = false;
96 }
97 else if (a.actionFlags.test(dontReportToHostFlagBit))
98 {
99 required = false;
100 }
101 }
102 else
103 {
104 using namespace phosphor::logging;
105 log<level::ERR>("Host Enqueue: Unable to find PEL ID in repository",
106 entry("PEL_ID=0x%X", id));
107 required = false;
108 }
Matt Spinlerf60ac272019-12-11 13:47:50 -0600109
110 return required;
111}
112
113void HostNotifier::newLogCallback(const PEL& pel)
114{
115 if (!enqueueRequired(pel.id()))
116 {
117 return;
118 }
119
120 _pelQueue.push_back(pel.id());
121
122 // TODO: Check if a send is needed now
123}
124
125void HostNotifier::doNewLogNotify()
126{
127}
128
129void HostNotifier::hostStateChange(bool hostUp)
130{
131}
132
133void HostNotifier::commandResponse(ResponseStatus status)
134{
Matt Spinlerf869fcf2019-12-11 15:02:20 -0600135 auto id = _inProgressPEL;
136 _inProgressPEL = 0;
137
138 if (status == ResponseStatus::success)
139 {
140 _retryCount = 0;
141
142 _sentPELs.push_back(id);
143
144 _repo.setPELHostTransState(id, TransmissionState::sent);
145
146 if (!_pelQueue.empty())
147 {
148 doNewLogNotify();
149 }
150 }
151 else
152 {
153 log<level::ERR>("PLDM command response failure",
154 entry("PEL_ID=0x%X", id));
155 // Retry
156 _pelQueue.push_front(id);
157 _retryTimer.restartOnce(_hostIface->getReceiveRetryDelay());
158 }
159}
160
161void HostNotifier::retryTimerExpired()
162{
163 if (_dataIface.isHostUp())
164 {
165 log<level::INFO>("Attempting command retry",
166 entry("PEL_ID=0x%X", _pelQueue.front()));
167 _retryCount++;
168 doNewLogNotify();
169 }
Matt Spinlerf60ac272019-12-11 13:47:50 -0600170}
171
172} // namespace openpower::pels