blob: 8980d53fac82a7d8ed1e47fcaeed523a7b2a20bf [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,
37 const std::string& combineEventName) :
38 objServer(objectServer)
39{
40 eventInterface = objServer.add_interface(
41 "/xyz/openbmc_project/State/Decorator/" + psuName + "_" +
42 combineEventName,
43 "xyz.openbmc_project.State.Decorator.OperationalStatus");
James Feistb6c0b912019-07-09 12:21:44 -070044 eventInterface->register_property("functional", true);
Cheng C Yang58b2b532019-05-31 00:19:45 +080045
46 if (!eventInterface->initialize())
47 {
48 std::cerr << "error initializing event interface\n";
49 }
50
51 std::shared_ptr<std::set<std::string>> combineEvent =
52 std::make_shared<std::set<std::string>>();
53 for (const auto& pathList : eventPathList)
54 {
Yong Li591b1e42019-12-19 17:46:31 +080055 std::shared_ptr<std::set<std::string>> assert =
56 std::make_shared<std::set<std::string>>();
57
Cheng C Yang58b2b532019-05-31 00:19:45 +080058 const std::string& eventName = pathList.first;
59 std::string eventPSUName = eventName + psuName;
60 for (const auto& path : pathList.second)
61 {
Cheng C Yang58b2b532019-05-31 00:19:45 +080062 std::shared_ptr<bool> state = std::make_shared<bool>(false);
63 events[eventPSUName].emplace_back(std::make_unique<PSUSubEvent>(
64 eventInterface, path, io, eventName, assert, combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +080065 state, psuName));
Cheng C Yang58b2b532019-05-31 00:19:45 +080066 asserts.emplace_back(assert);
67 states.emplace_back(state);
68 }
69 }
70}
71
72PSUCombineEvent::~PSUCombineEvent()
73{
74 events.clear();
75 objServer.remove_interface(eventInterface);
76}
77
Cheng C Yang9b53a622019-08-27 22:13:58 +080078static boost::container::flat_map<std::string,
79 std::pair<std::string, std::string>>
80 logID = {
81 {"PredictiveFailure",
82 {"OpenBMC.0.1.PowerSupplyFailurePredicted",
83 "OpenBMC.0.1.PowerSupplyPredictedFailureRecovered"}},
84 {"Failure",
85 {"OpenBMC.0.1.PowerSupplyFailed", "OpenBMC.0.1.PowerSupplyRecovered"}},
86 {"ACLost",
Cheng C Yangbb732ef2019-09-18 16:25:58 +080087 {"OpenBMC.0.1.PowerSupplyPowerLost",
88 "OpenBMC.0.1.PowerSupplyPowerRestored"}},
Cheng C Yang9b53a622019-08-27 22:13:58 +080089 {"FanFault",
90 {"OpenBMC.0.1.PowerSupplyFanFailed",
91 "OpenBMC.0.1.PowerSupplyFanRecovered"}},
jayaprakash Mutyalad12f23e2019-12-03 23:03:52 +000092 {"ConfigureError",
93 {"OpenBMC.0.1.PowerSupplyConfigurationError",
94 "OpenBMC.0.1.PowerSupplyConfigurationErrorRecovered"}}};
Cheng C Yang5665db22019-07-12 00:57:30 +080095
Cheng C Yang58b2b532019-05-31 00:19:45 +080096PSUSubEvent::PSUSubEvent(
97 std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
98 const std::string& path, boost::asio::io_service& io,
99 const std::string& eventName,
100 std::shared_ptr<std::set<std::string>> asserts,
101 std::shared_ptr<std::set<std::string>> combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +0800102 std::shared_ptr<bool> state, const std::string& psuName) :
Cheng C Yang58b2b532019-05-31 00:19:45 +0800103 eventInterface(eventInterface),
Brad Bishopfbb44ad2019-11-08 09:42:37 -0500104 asserts(asserts), combineEvent(combineEvent), assertState(state),
105 errCount(0), path(path), eventName(eventName), waitTimer(io),
106 inputDev(io, open(path.c_str(), O_RDONLY)), psuName(psuName)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800107{
Cheng C Yang5665db22019-07-12 00:57:30 +0800108 auto found = logID.find(eventName);
109 if (found == logID.end())
110 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800111 assertMessage.clear();
112 deassertMessage.clear();
Cheng C Yang5665db22019-07-12 00:57:30 +0800113 }
114 else
115 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800116 assertMessage = found->second.first;
117 deassertMessage = found->second.second;
Cheng C Yang5665db22019-07-12 00:57:30 +0800118 }
119
120 auto fanPos = path.find("fan");
121 if (fanPos != std::string::npos)
122 {
123 fanName = path.substr(fanPos);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800124 auto fanNamePos = fanName.find("_");
125 if (fanNamePos != std::string::npos)
126 {
127 fanName = fanName.substr(0, fanNamePos);
128 }
Cheng C Yang5665db22019-07-12 00:57:30 +0800129 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800130 setupRead();
131}
132
133void PSUSubEvent::setupRead(void)
134{
135 boost::asio::async_read_until(
136 inputDev, readBuf, '\n',
137 [&](const boost::system::error_code& ec,
138 std::size_t /*bytes_transfered*/) { handleResponse(ec); });
139}
140
141PSUSubEvent::~PSUSubEvent()
142{
143 inputDev.close();
144 waitTimer.cancel();
145}
146
147void PSUSubEvent::handleResponse(const boost::system::error_code& err)
148{
149 if (err == boost::system::errc::bad_file_descriptor)
150 {
151 return;
152 }
153 std::istream responseStream(&readBuf);
154 if (!err)
155 {
156 std::string response;
157 try
158 {
159 std::getline(responseStream, response);
160 int nvalue = std::stof(response);
161 responseStream.clear();
162 if (nvalue != value)
163 {
164 updateValue(nvalue);
165 }
166 errCount = 0;
167 }
168 catch (const std::invalid_argument&)
169 {
170 errCount++;
171 }
172 }
173 else
174 {
175 errCount++;
176 }
177 if (errCount >= warnAfterErrorCount)
178 {
179 if (errCount == warnAfterErrorCount)
180 {
181 std::cerr << "Failure to read event at " << path << "\n";
182 }
183 updateValue(0);
184 errCount++;
185 }
186 responseStream.clear();
187 inputDev.close();
188 int fd = open(path.c_str(), O_RDONLY);
Jae Hyun Yooef9665a2019-10-10 10:26:39 -0700189 if (fd < 0)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800190 {
191 return;
192 }
193 inputDev.assign(fd);
194 waitTimer.expires_from_now(boost::posix_time::milliseconds(eventPollMs));
195 waitTimer.async_wait([&](const boost::system::error_code& ec) {
196 if (ec == boost::asio::error::operation_aborted)
197 {
198 return;
199 }
200 setupRead();
201 });
202}
203
204// Any of the sub events of one event is asserted, then the event will be
205// asserted. Only if none of the sub events are asserted, the event will be
206// deasserted.
207void PSUSubEvent::updateValue(const int& newValue)
208{
209 if (newValue == 0)
210 {
Yong Li591b1e42019-12-19 17:46:31 +0800211 // log deassert only after all asserts are gone
Cheng C Yang58b2b532019-05-31 00:19:45 +0800212 if (!(*asserts).empty())
213 {
Yong Li591b1e42019-12-19 17:46:31 +0800214 auto found = (*asserts).find(path);
215 if (found == (*asserts).end())
216 {
217 return;
218 }
219 (*asserts).erase(path);
220
Cheng C Yang58b2b532019-05-31 00:19:45 +0800221 return;
222 }
223 if (*assertState == true)
224 {
225 *assertState = false;
226 auto foundCombine = (*combineEvent).find(eventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800227 if (foundCombine == (*combineEvent).end())
Cheng C Yang58b2b532019-05-31 00:19:45 +0800228 {
229 return;
230 }
231 (*combineEvent).erase(eventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800232 if (!deassertMessage.empty())
233 {
234 // Fan Failed has two args
235 std::string sendMessage = eventName + " deassert";
236 if (deassertMessage == "OpenBMC.0.1.PowerSupplyFanRecovered")
237 {
238 sd_journal_send(
239 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800240 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
Cheng C Yang9b53a622019-08-27 22:13:58 +0800241 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s,%s",
242 psuName.c_str(), fanName.c_str(), NULL);
243 }
244 else
245 {
246 sd_journal_send(
247 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800248 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
Cheng C Yang9b53a622019-08-27 22:13:58 +0800249 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s",
250 psuName.c_str(), NULL);
251 }
252 }
253
Cheng C Yang58b2b532019-05-31 00:19:45 +0800254 if ((*combineEvent).empty())
255 {
256 eventInterface->set_property("functional", true);
257 }
258 }
259 }
260 else
261 {
Yong Li591b1e42019-12-19 17:46:31 +0800262 if ((*assertState == false) && ((*asserts).empty()))
Cheng C Yang58b2b532019-05-31 00:19:45 +0800263 {
264 *assertState = true;
Cheng C Yang9b53a622019-08-27 22:13:58 +0800265 if (!assertMessage.empty())
Cheng C Yang5665db22019-07-12 00:57:30 +0800266 {
267 // Fan Failed has two args
268 std::string sendMessage = eventName + " assert";
Cheng C Yang9b53a622019-08-27 22:13:58 +0800269 if (assertMessage == "OpenBMC.0.1.PowerSupplyFanFailed")
Cheng C Yang5665db22019-07-12 00:57:30 +0800270 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800271 sd_journal_send(
272 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800273 LOG_WARNING, "REDFISH_MESSAGE_ID=%s",
274 assertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s,%s",
275 psuName.c_str(), fanName.c_str(), NULL);
Cheng C Yang5665db22019-07-12 00:57:30 +0800276 }
277 else
278 {
279 sd_journal_send(
280 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800281 LOG_WARNING, "REDFISH_MESSAGE_ID=%s",
282 assertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s",
283 psuName.c_str(), NULL);
Cheng C Yang5665db22019-07-12 00:57:30 +0800284 }
285 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800286 if ((*combineEvent).empty())
287 {
288 eventInterface->set_property("functional", false);
289 }
290 (*combineEvent).emplace(eventName);
291 }
Yong Li591b1e42019-12-19 17:46:31 +0800292 (*asserts).emplace(path);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800293 }
294 value = newValue;
295}