blob: bfe077673a3c3fce64fcc513b680e1b71d2339a7 [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
Patrick Ventureca44b2f2019-10-31 11:02:26 -070017#include "PSUEvent.hpp"
18
Cheng C Yang5665db22019-07-12 00:57:30 +080019#include <systemd/sd-journal.h>
20
Patrick Venture96e97db2019-10-31 13:44:38 -070021#include <boost/container/flat_map.hpp>
Cheng C Yang58b2b532019-05-31 00:19:45 +080022#include <iostream>
Patrick Venture96e97db2019-10-31 13:44:38 -070023#include <memory>
Cheng C Yang58b2b532019-05-31 00:19:45 +080024#include <sdbusplus/asio/connection.hpp>
25#include <sdbusplus/asio/object_server.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070026#include <stdexcept>
27#include <string>
28#include <utility>
29#include <variant>
30#include <vector>
Cheng C Yang58b2b532019-05-31 00:19:45 +080031
32PSUCombineEvent::PSUCombineEvent(
33 sdbusplus::asio::object_server& objectServer, boost::asio::io_service& io,
34 const std::string& psuName,
35 boost::container::flat_map<std::string, std::vector<std::string>>&
36 eventPathList,
Cheng C Yang202a1ff2020-01-09 09:34:22 +080037 boost::container::flat_map<
38 std::string,
39 boost::container::flat_map<std::string, std::vector<std::string>>>&
40 groupEventPathList,
Cheng C Yang58b2b532019-05-31 00:19:45 +080041 const std::string& combineEventName) :
42 objServer(objectServer)
43{
44 eventInterface = objServer.add_interface(
45 "/xyz/openbmc_project/State/Decorator/" + psuName + "_" +
46 combineEventName,
47 "xyz.openbmc_project.State.Decorator.OperationalStatus");
James Feistb6c0b912019-07-09 12:21:44 -070048 eventInterface->register_property("functional", true);
Cheng C Yang58b2b532019-05-31 00:19:45 +080049
50 if (!eventInterface->initialize())
51 {
52 std::cerr << "error initializing event interface\n";
53 }
54
55 std::shared_ptr<std::set<std::string>> combineEvent =
56 std::make_shared<std::set<std::string>>();
57 for (const auto& pathList : eventPathList)
58 {
Yong Li591b1e42019-12-19 17:46:31 +080059 std::shared_ptr<std::set<std::string>> assert =
60 std::make_shared<std::set<std::string>>();
Cheng C Yang202a1ff2020-01-09 09:34:22 +080061 std::shared_ptr<bool> state = std::make_shared<bool>(false);
Yong Li591b1e42019-12-19 17:46:31 +080062
Cheng C Yang58b2b532019-05-31 00:19:45 +080063 const std::string& eventName = pathList.first;
64 std::string eventPSUName = eventName + psuName;
65 for (const auto& path : pathList.second)
66 {
Cheng C Yang58b2b532019-05-31 00:19:45 +080067 events[eventPSUName].emplace_back(std::make_unique<PSUSubEvent>(
Cheng C Yang202a1ff2020-01-09 09:34:22 +080068 eventInterface, path, io, eventName, eventName, assert,
69 combineEvent, state, psuName));
Cheng C Yang58b2b532019-05-31 00:19:45 +080070 asserts.emplace_back(assert);
71 states.emplace_back(state);
72 }
73 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +080074
75 for (const auto& groupPathList : groupEventPathList)
76 {
77 for (const auto& pathList : groupPathList.second)
78 {
79 std::shared_ptr<std::set<std::string>> assert =
80 std::make_shared<std::set<std::string>>();
81 std::shared_ptr<bool> state = std::make_shared<bool>(false);
82
83 const std::string& groupEventName = pathList.first;
84 std::string eventPSUName = groupEventName + psuName;
85 for (const auto& path : pathList.second)
86 {
87 events[eventPSUName].emplace_back(std::make_unique<PSUSubEvent>(
88 eventInterface, path, io, groupEventName,
89 groupPathList.first, assert, combineEvent, state, psuName));
90 asserts.emplace_back(assert);
91 states.emplace_back(state);
92 }
93 }
94 }
Cheng C Yang58b2b532019-05-31 00:19:45 +080095}
96
97PSUCombineEvent::~PSUCombineEvent()
98{
Cheng C Yang202a1ff2020-01-09 09:34:22 +080099 // Clear unique_ptr first
100 for (auto& event : events)
101 {
102 for (auto& subEventPtr : event.second)
103 {
104 subEventPtr.reset();
105 }
106 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800107 events.clear();
108 objServer.remove_interface(eventInterface);
109}
110
Cheng C Yang9b53a622019-08-27 22:13:58 +0800111static boost::container::flat_map<std::string,
112 std::pair<std::string, std::string>>
113 logID = {
114 {"PredictiveFailure",
115 {"OpenBMC.0.1.PowerSupplyFailurePredicted",
116 "OpenBMC.0.1.PowerSupplyPredictedFailureRecovered"}},
117 {"Failure",
118 {"OpenBMC.0.1.PowerSupplyFailed", "OpenBMC.0.1.PowerSupplyRecovered"}},
119 {"ACLost",
Cheng C Yangbb732ef2019-09-18 16:25:58 +0800120 {"OpenBMC.0.1.PowerSupplyPowerLost",
121 "OpenBMC.0.1.PowerSupplyPowerRestored"}},
Cheng C Yang9b53a622019-08-27 22:13:58 +0800122 {"FanFault",
123 {"OpenBMC.0.1.PowerSupplyFanFailed",
124 "OpenBMC.0.1.PowerSupplyFanRecovered"}},
jayaprakash Mutyalad12f23e2019-12-03 23:03:52 +0000125 {"ConfigureError",
126 {"OpenBMC.0.1.PowerSupplyConfigurationError",
127 "OpenBMC.0.1.PowerSupplyConfigurationErrorRecovered"}}};
Cheng C Yang5665db22019-07-12 00:57:30 +0800128
Cheng C Yang58b2b532019-05-31 00:19:45 +0800129PSUSubEvent::PSUSubEvent(
130 std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
131 const std::string& path, boost::asio::io_service& io,
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800132 const std::string& groupEventName, const std::string& eventName,
Cheng C Yang58b2b532019-05-31 00:19:45 +0800133 std::shared_ptr<std::set<std::string>> asserts,
134 std::shared_ptr<std::set<std::string>> combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +0800135 std::shared_ptr<bool> state, const std::string& psuName) :
Cheng C Yang58b2b532019-05-31 00:19:45 +0800136 eventInterface(eventInterface),
Brad Bishopfbb44ad2019-11-08 09:42:37 -0500137 asserts(asserts), combineEvent(combineEvent), assertState(state),
138 errCount(0), path(path), eventName(eventName), waitTimer(io),
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800139 inputDev(io, open(path.c_str(), O_RDONLY)), psuName(psuName),
140 groupEventName(groupEventName)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800141{
Cheng C Yang5665db22019-07-12 00:57:30 +0800142 auto found = logID.find(eventName);
143 if (found == logID.end())
144 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800145 assertMessage.clear();
146 deassertMessage.clear();
Cheng C Yang5665db22019-07-12 00:57:30 +0800147 }
148 else
149 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800150 assertMessage = found->second.first;
151 deassertMessage = found->second.second;
Cheng C Yang5665db22019-07-12 00:57:30 +0800152 }
153
154 auto fanPos = path.find("fan");
155 if (fanPos != std::string::npos)
156 {
157 fanName = path.substr(fanPos);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800158 auto fanNamePos = fanName.find("_");
159 if (fanNamePos != std::string::npos)
160 {
161 fanName = fanName.substr(0, fanNamePos);
162 }
Cheng C Yang5665db22019-07-12 00:57:30 +0800163 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800164 setupRead();
165}
166
167void PSUSubEvent::setupRead(void)
168{
169 boost::asio::async_read_until(
170 inputDev, readBuf, '\n',
171 [&](const boost::system::error_code& ec,
172 std::size_t /*bytes_transfered*/) { handleResponse(ec); });
173}
174
175PSUSubEvent::~PSUSubEvent()
176{
177 inputDev.close();
178 waitTimer.cancel();
179}
180
181void PSUSubEvent::handleResponse(const boost::system::error_code& err)
182{
183 if (err == boost::system::errc::bad_file_descriptor)
184 {
185 return;
186 }
187 std::istream responseStream(&readBuf);
188 if (!err)
189 {
190 std::string response;
191 try
192 {
193 std::getline(responseStream, response);
194 int nvalue = std::stof(response);
195 responseStream.clear();
196 if (nvalue != value)
197 {
198 updateValue(nvalue);
199 }
200 errCount = 0;
201 }
202 catch (const std::invalid_argument&)
203 {
204 errCount++;
205 }
206 }
207 else
208 {
209 errCount++;
210 }
211 if (errCount >= warnAfterErrorCount)
212 {
213 if (errCount == warnAfterErrorCount)
214 {
215 std::cerr << "Failure to read event at " << path << "\n";
216 }
217 updateValue(0);
218 errCount++;
219 }
220 responseStream.clear();
221 inputDev.close();
222 int fd = open(path.c_str(), O_RDONLY);
Jae Hyun Yooef9665a2019-10-10 10:26:39 -0700223 if (fd < 0)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800224 {
225 return;
226 }
227 inputDev.assign(fd);
228 waitTimer.expires_from_now(boost::posix_time::milliseconds(eventPollMs));
229 waitTimer.async_wait([&](const boost::system::error_code& ec) {
230 if (ec == boost::asio::error::operation_aborted)
231 {
232 return;
233 }
234 setupRead();
235 });
236}
237
238// Any of the sub events of one event is asserted, then the event will be
239// asserted. Only if none of the sub events are asserted, the event will be
240// deasserted.
241void PSUSubEvent::updateValue(const int& newValue)
242{
243 if (newValue == 0)
244 {
Yong Li591b1e42019-12-19 17:46:31 +0800245 // log deassert only after all asserts are gone
Cheng C Yang58b2b532019-05-31 00:19:45 +0800246 if (!(*asserts).empty())
247 {
Yong Li591b1e42019-12-19 17:46:31 +0800248 auto found = (*asserts).find(path);
249 if (found == (*asserts).end())
250 {
251 return;
252 }
253 (*asserts).erase(path);
254
Cheng C Yang58b2b532019-05-31 00:19:45 +0800255 return;
256 }
257 if (*assertState == true)
258 {
259 *assertState = false;
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800260 auto foundCombine = (*combineEvent).find(groupEventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800261 if (foundCombine == (*combineEvent).end())
Cheng C Yang58b2b532019-05-31 00:19:45 +0800262 {
263 return;
264 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800265 (*combineEvent).erase(groupEventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800266 if (!deassertMessage.empty())
267 {
268 // Fan Failed has two args
269 std::string sendMessage = eventName + " deassert";
270 if (deassertMessage == "OpenBMC.0.1.PowerSupplyFanRecovered")
271 {
272 sd_journal_send(
273 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800274 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
Cheng C Yang9b53a622019-08-27 22:13:58 +0800275 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s,%s",
276 psuName.c_str(), fanName.c_str(), NULL);
277 }
278 else
279 {
280 sd_journal_send(
281 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800282 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
Cheng C Yang9b53a622019-08-27 22:13:58 +0800283 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s",
284 psuName.c_str(), NULL);
285 }
286 }
287
Cheng C Yang58b2b532019-05-31 00:19:45 +0800288 if ((*combineEvent).empty())
289 {
290 eventInterface->set_property("functional", true);
291 }
292 }
293 }
294 else
295 {
Yong Li591b1e42019-12-19 17:46:31 +0800296 if ((*assertState == false) && ((*asserts).empty()))
Cheng C Yang58b2b532019-05-31 00:19:45 +0800297 {
298 *assertState = true;
Cheng C Yang9b53a622019-08-27 22:13:58 +0800299 if (!assertMessage.empty())
Cheng C Yang5665db22019-07-12 00:57:30 +0800300 {
301 // Fan Failed has two args
302 std::string sendMessage = eventName + " assert";
Cheng C Yang9b53a622019-08-27 22:13:58 +0800303 if (assertMessage == "OpenBMC.0.1.PowerSupplyFanFailed")
Cheng C Yang5665db22019-07-12 00:57:30 +0800304 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800305 sd_journal_send(
306 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800307 LOG_WARNING, "REDFISH_MESSAGE_ID=%s",
308 assertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s,%s",
309 psuName.c_str(), fanName.c_str(), NULL);
Cheng C Yang5665db22019-07-12 00:57:30 +0800310 }
311 else
312 {
313 sd_journal_send(
314 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800315 LOG_WARNING, "REDFISH_MESSAGE_ID=%s",
316 assertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s",
317 psuName.c_str(), NULL);
Cheng C Yang5665db22019-07-12 00:57:30 +0800318 }
319 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800320 if ((*combineEvent).empty())
321 {
322 eventInterface->set_property("functional", false);
323 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800324 (*combineEvent).emplace(groupEventName);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800325 }
Yong Li591b1e42019-12-19 17:46:31 +0800326 (*asserts).emplace(path);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800327 }
328 value = newValue;
329}