blob: cc7374c6e45b902fb253a0eb4749ce8eac4bf3ff [file] [log] [blame]
Cheng C Yang58b2b532019-05-31 00:19:45 +08001/*
2// Copyright (c) 2019 Intel 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
Cheng C Yang5665db22019-07-12 00:57:30 +080017#include <systemd/sd-journal.h>
18
Cheng C Yang58b2b532019-05-31 00:19:45 +080019#include <PSUEvent.hpp>
20#include <iostream>
21#include <sdbusplus/asio/connection.hpp>
22#include <sdbusplus/asio/object_server.hpp>
23
24PSUCombineEvent::PSUCombineEvent(
25 sdbusplus::asio::object_server& objectServer, boost::asio::io_service& io,
26 const std::string& psuName,
27 boost::container::flat_map<std::string, std::vector<std::string>>&
28 eventPathList,
29 const std::string& combineEventName) :
30 objServer(objectServer)
31{
32 eventInterface = objServer.add_interface(
33 "/xyz/openbmc_project/State/Decorator/" + psuName + "_" +
34 combineEventName,
35 "xyz.openbmc_project.State.Decorator.OperationalStatus");
James Feistb6c0b912019-07-09 12:21:44 -070036 eventInterface->register_property("functional", true);
Cheng C Yang58b2b532019-05-31 00:19:45 +080037
38 if (!eventInterface->initialize())
39 {
40 std::cerr << "error initializing event interface\n";
41 }
42
43 std::shared_ptr<std::set<std::string>> combineEvent =
44 std::make_shared<std::set<std::string>>();
45 for (const auto& pathList : eventPathList)
46 {
47 const std::string& eventName = pathList.first;
48 std::string eventPSUName = eventName + psuName;
49 for (const auto& path : pathList.second)
50 {
51 std::shared_ptr<std::set<std::string>> assert =
52 std::make_shared<std::set<std::string>>();
53 std::shared_ptr<bool> state = std::make_shared<bool>(false);
54 events[eventPSUName].emplace_back(std::make_unique<PSUSubEvent>(
55 eventInterface, path, io, eventName, assert, combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +080056 state, psuName));
Cheng C Yang58b2b532019-05-31 00:19:45 +080057 asserts.emplace_back(assert);
58 states.emplace_back(state);
59 }
60 }
61}
62
63PSUCombineEvent::~PSUCombineEvent()
64{
65 events.clear();
66 objServer.remove_interface(eventInterface);
67}
68
Cheng C Yang9b53a622019-08-27 22:13:58 +080069static boost::container::flat_map<std::string,
70 std::pair<std::string, std::string>>
71 logID = {
72 {"PredictiveFailure",
73 {"OpenBMC.0.1.PowerSupplyFailurePredicted",
74 "OpenBMC.0.1.PowerSupplyPredictedFailureRecovered"}},
75 {"Failure",
76 {"OpenBMC.0.1.PowerSupplyFailed", "OpenBMC.0.1.PowerSupplyRecovered"}},
77 {"ACLost",
Cheng C Yangbb732ef2019-09-18 16:25:58 +080078 {"OpenBMC.0.1.PowerSupplyPowerLost",
79 "OpenBMC.0.1.PowerSupplyPowerRestored"}},
Cheng C Yang9b53a622019-08-27 22:13:58 +080080 {"FanFault",
81 {"OpenBMC.0.1.PowerSupplyFanFailed",
82 "OpenBMC.0.1.PowerSupplyFanRecovered"}},
83 {"ConfigureError", {"OpenBMC.0.1.PowerSupplyConfigurationError", ""}}};
Cheng C Yang5665db22019-07-12 00:57:30 +080084
Cheng C Yang58b2b532019-05-31 00:19:45 +080085PSUSubEvent::PSUSubEvent(
86 std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
87 const std::string& path, boost::asio::io_service& io,
88 const std::string& eventName,
89 std::shared_ptr<std::set<std::string>> asserts,
90 std::shared_ptr<std::set<std::string>> combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +080091 std::shared_ptr<bool> state, const std::string& psuName) :
Cheng C Yang58b2b532019-05-31 00:19:45 +080092 eventInterface(eventInterface),
93 inputDev(io, open(path.c_str(), O_RDONLY)), waitTimer(io), errCount(0),
94 path(path), eventName(eventName), assertState(state), asserts(asserts),
Cheng C Yang5665db22019-07-12 00:57:30 +080095 combineEvent(combineEvent), psuName(psuName)
Cheng C Yang58b2b532019-05-31 00:19:45 +080096{
Cheng C Yang5665db22019-07-12 00:57:30 +080097 auto found = logID.find(eventName);
98 if (found == logID.end())
99 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800100 assertMessage.clear();
101 deassertMessage.clear();
Cheng C Yang5665db22019-07-12 00:57:30 +0800102 }
103 else
104 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800105 assertMessage = found->second.first;
106 deassertMessage = found->second.second;
Cheng C Yang5665db22019-07-12 00:57:30 +0800107 }
108
109 auto fanPos = path.find("fan");
110 if (fanPos != std::string::npos)
111 {
112 fanName = path.substr(fanPos);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800113 auto fanNamePos = fanName.find("_");
114 if (fanNamePos != std::string::npos)
115 {
116 fanName = fanName.substr(0, fanNamePos);
117 }
Cheng C Yang5665db22019-07-12 00:57:30 +0800118 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800119 setupRead();
120}
121
122void PSUSubEvent::setupRead(void)
123{
124 boost::asio::async_read_until(
125 inputDev, readBuf, '\n',
126 [&](const boost::system::error_code& ec,
127 std::size_t /*bytes_transfered*/) { handleResponse(ec); });
128}
129
130PSUSubEvent::~PSUSubEvent()
131{
132 inputDev.close();
133 waitTimer.cancel();
134}
135
136void PSUSubEvent::handleResponse(const boost::system::error_code& err)
137{
138 if (err == boost::system::errc::bad_file_descriptor)
139 {
140 return;
141 }
142 std::istream responseStream(&readBuf);
143 if (!err)
144 {
145 std::string response;
146 try
147 {
148 std::getline(responseStream, response);
149 int nvalue = std::stof(response);
150 responseStream.clear();
151 if (nvalue != value)
152 {
153 updateValue(nvalue);
154 }
155 errCount = 0;
156 }
157 catch (const std::invalid_argument&)
158 {
159 errCount++;
160 }
161 }
162 else
163 {
164 errCount++;
165 }
166 if (errCount >= warnAfterErrorCount)
167 {
168 if (errCount == warnAfterErrorCount)
169 {
170 std::cerr << "Failure to read event at " << path << "\n";
171 }
172 updateValue(0);
173 errCount++;
174 }
175 responseStream.clear();
176 inputDev.close();
177 int fd = open(path.c_str(), O_RDONLY);
Jae Hyun Yooef9665a2019-10-10 10:26:39 -0700178 if (fd < 0)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800179 {
180 return;
181 }
182 inputDev.assign(fd);
183 waitTimer.expires_from_now(boost::posix_time::milliseconds(eventPollMs));
184 waitTimer.async_wait([&](const boost::system::error_code& ec) {
185 if (ec == boost::asio::error::operation_aborted)
186 {
187 return;
188 }
189 setupRead();
190 });
191}
192
193// Any of the sub events of one event is asserted, then the event will be
194// asserted. Only if none of the sub events are asserted, the event will be
195// deasserted.
196void PSUSubEvent::updateValue(const int& newValue)
197{
198 if (newValue == 0)
199 {
200 auto found = (*asserts).find(path);
201 if (found == (*asserts).end())
202 {
203 return;
204 }
Cheng C Yang9b53a622019-08-27 22:13:58 +0800205 (*asserts).erase(path);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800206
207 if (!(*asserts).empty())
208 {
209 return;
210 }
211 if (*assertState == true)
212 {
213 *assertState = false;
214 auto foundCombine = (*combineEvent).find(eventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800215 if (foundCombine == (*combineEvent).end())
Cheng C Yang58b2b532019-05-31 00:19:45 +0800216 {
217 return;
218 }
219 (*combineEvent).erase(eventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800220 if (!deassertMessage.empty())
221 {
222 // Fan Failed has two args
223 std::string sendMessage = eventName + " deassert";
224 if (deassertMessage == "OpenBMC.0.1.PowerSupplyFanRecovered")
225 {
226 sd_journal_send(
227 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
228 LOG_ERR, "REDFISH_MESSAGE_ID=%s",
229 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s,%s",
230 psuName.c_str(), fanName.c_str(), NULL);
231 }
232 else
233 {
234 sd_journal_send(
235 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
236 LOG_ERR, "REDFISH_MESSAGE_ID=%s",
237 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s",
238 psuName.c_str(), NULL);
239 }
240 }
241
Cheng C Yang58b2b532019-05-31 00:19:45 +0800242 if ((*combineEvent).empty())
243 {
244 eventInterface->set_property("functional", true);
245 }
246 }
247 }
248 else
249 {
250 (*asserts).emplace(path);
251 if (*assertState == false)
252 {
253 *assertState = true;
Cheng C Yang9b53a622019-08-27 22:13:58 +0800254 if (!assertMessage.empty())
Cheng C Yang5665db22019-07-12 00:57:30 +0800255 {
256 // Fan Failed has two args
257 std::string sendMessage = eventName + " assert";
Cheng C Yang9b53a622019-08-27 22:13:58 +0800258 if (assertMessage == "OpenBMC.0.1.PowerSupplyFanFailed")
Cheng C Yang5665db22019-07-12 00:57:30 +0800259 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800260 sd_journal_send(
261 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
262 LOG_ERR, "REDFISH_MESSAGE_ID=%s", assertMessage.c_str(),
263 "REDFISH_MESSAGE_ARGS=%s,%s", psuName.c_str(),
264 fanName.c_str(), NULL);
Cheng C Yang5665db22019-07-12 00:57:30 +0800265 }
266 else
267 {
268 sd_journal_send(
269 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Cheng C Yang9b53a622019-08-27 22:13:58 +0800270 LOG_ERR, "REDFISH_MESSAGE_ID=%s", assertMessage.c_str(),
Cheng C Yang5665db22019-07-12 00:57:30 +0800271 "REDFISH_MESSAGE_ARGS=%s", psuName.c_str(), NULL);
272 }
273 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800274 if ((*combineEvent).empty())
275 {
276 eventInterface->set_property("functional", false);
277 }
278 (*combineEvent).emplace(eventName);
279 }
280 }
281 value = newValue;
282}