blob: b75a4947c5e0b479dbdec2202566dafc3b9d7c3c [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 {
55 const std::string& eventName = pathList.first;
56 std::string eventPSUName = eventName + psuName;
57 for (const auto& path : pathList.second)
58 {
59 std::shared_ptr<std::set<std::string>> assert =
60 std::make_shared<std::set<std::string>>();
61 std::shared_ptr<bool> state = std::make_shared<bool>(false);
62 events[eventPSUName].emplace_back(std::make_unique<PSUSubEvent>(
63 eventInterface, path, io, eventName, assert, combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +080064 state, psuName));
Cheng C Yang58b2b532019-05-31 00:19:45 +080065 asserts.emplace_back(assert);
66 states.emplace_back(state);
67 }
68 }
69}
70
71PSUCombineEvent::~PSUCombineEvent()
72{
73 events.clear();
74 objServer.remove_interface(eventInterface);
75}
76
Cheng C Yang9b53a622019-08-27 22:13:58 +080077static boost::container::flat_map<std::string,
78 std::pair<std::string, std::string>>
79 logID = {
80 {"PredictiveFailure",
81 {"OpenBMC.0.1.PowerSupplyFailurePredicted",
82 "OpenBMC.0.1.PowerSupplyPredictedFailureRecovered"}},
83 {"Failure",
84 {"OpenBMC.0.1.PowerSupplyFailed", "OpenBMC.0.1.PowerSupplyRecovered"}},
85 {"ACLost",
Cheng C Yangbb732ef2019-09-18 16:25:58 +080086 {"OpenBMC.0.1.PowerSupplyPowerLost",
87 "OpenBMC.0.1.PowerSupplyPowerRestored"}},
Cheng C Yang9b53a622019-08-27 22:13:58 +080088 {"FanFault",
89 {"OpenBMC.0.1.PowerSupplyFanFailed",
90 "OpenBMC.0.1.PowerSupplyFanRecovered"}},
jayaprakash Mutyalad12f23e2019-12-03 23:03:52 +000091 {"ConfigureError",
92 {"OpenBMC.0.1.PowerSupplyConfigurationError",
93 "OpenBMC.0.1.PowerSupplyConfigurationErrorRecovered"}}};
Cheng C Yang5665db22019-07-12 00:57:30 +080094
Cheng C Yang58b2b532019-05-31 00:19:45 +080095PSUSubEvent::PSUSubEvent(
96 std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
97 const std::string& path, boost::asio::io_service& io,
98 const std::string& eventName,
99 std::shared_ptr<std::set<std::string>> asserts,
100 std::shared_ptr<std::set<std::string>> combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +0800101 std::shared_ptr<bool> state, const std::string& psuName) :
Cheng C Yang58b2b532019-05-31 00:19:45 +0800102 eventInterface(eventInterface),
Brad Bishopfbb44ad2019-11-08 09:42:37 -0500103 asserts(asserts), combineEvent(combineEvent), assertState(state),
104 errCount(0), path(path), eventName(eventName), waitTimer(io),
105 inputDev(io, open(path.c_str(), O_RDONLY)), psuName(psuName)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800106{
Cheng C Yang5665db22019-07-12 00:57:30 +0800107 auto found = logID.find(eventName);
108 if (found == logID.end())
109 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800110 assertMessage.clear();
111 deassertMessage.clear();
Cheng C Yang5665db22019-07-12 00:57:30 +0800112 }
113 else
114 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800115 assertMessage = found->second.first;
116 deassertMessage = found->second.second;
Cheng C Yang5665db22019-07-12 00:57:30 +0800117 }
118
119 auto fanPos = path.find("fan");
120 if (fanPos != std::string::npos)
121 {
122 fanName = path.substr(fanPos);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800123 auto fanNamePos = fanName.find("_");
124 if (fanNamePos != std::string::npos)
125 {
126 fanName = fanName.substr(0, fanNamePos);
127 }
Cheng C Yang5665db22019-07-12 00:57:30 +0800128 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800129 setupRead();
130}
131
132void PSUSubEvent::setupRead(void)
133{
134 boost::asio::async_read_until(
135 inputDev, readBuf, '\n',
136 [&](const boost::system::error_code& ec,
137 std::size_t /*bytes_transfered*/) { handleResponse(ec); });
138}
139
140PSUSubEvent::~PSUSubEvent()
141{
142 inputDev.close();
143 waitTimer.cancel();
144}
145
146void PSUSubEvent::handleResponse(const boost::system::error_code& err)
147{
148 if (err == boost::system::errc::bad_file_descriptor)
149 {
150 return;
151 }
152 std::istream responseStream(&readBuf);
153 if (!err)
154 {
155 std::string response;
156 try
157 {
158 std::getline(responseStream, response);
159 int nvalue = std::stof(response);
160 responseStream.clear();
161 if (nvalue != value)
162 {
163 updateValue(nvalue);
164 }
165 errCount = 0;
166 }
167 catch (const std::invalid_argument&)
168 {
169 errCount++;
170 }
171 }
172 else
173 {
174 errCount++;
175 }
176 if (errCount >= warnAfterErrorCount)
177 {
178 if (errCount == warnAfterErrorCount)
179 {
180 std::cerr << "Failure to read event at " << path << "\n";
181 }
182 updateValue(0);
183 errCount++;
184 }
185 responseStream.clear();
186 inputDev.close();
187 int fd = open(path.c_str(), O_RDONLY);
Jae Hyun Yooef9665a2019-10-10 10:26:39 -0700188 if (fd < 0)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800189 {
190 return;
191 }
192 inputDev.assign(fd);
193 waitTimer.expires_from_now(boost::posix_time::milliseconds(eventPollMs));
194 waitTimer.async_wait([&](const boost::system::error_code& ec) {
195 if (ec == boost::asio::error::operation_aborted)
196 {
197 return;
198 }
199 setupRead();
200 });
201}
202
203// Any of the sub events of one event is asserted, then the event will be
204// asserted. Only if none of the sub events are asserted, the event will be
205// deasserted.
206void PSUSubEvent::updateValue(const int& newValue)
207{
208 if (newValue == 0)
209 {
210 auto found = (*asserts).find(path);
211 if (found == (*asserts).end())
212 {
213 return;
214 }
Cheng C Yang9b53a622019-08-27 22:13:58 +0800215 (*asserts).erase(path);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800216
217 if (!(*asserts).empty())
218 {
219 return;
220 }
221 if (*assertState == true)
222 {
223 *assertState = false;
224 auto foundCombine = (*combineEvent).find(eventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800225 if (foundCombine == (*combineEvent).end())
Cheng C Yang58b2b532019-05-31 00:19:45 +0800226 {
jayaprakash Mutyala73c363f2019-12-04 19:34:17 +0000227 value = newValue;
Cheng C Yang58b2b532019-05-31 00:19:45 +0800228 return;
229 }
230 (*combineEvent).erase(eventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800231 if (!deassertMessage.empty())
232 {
233 // Fan Failed has two args
234 std::string sendMessage = eventName + " deassert";
235 if (deassertMessage == "OpenBMC.0.1.PowerSupplyFanRecovered")
236 {
237 sd_journal_send(
238 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
239 LOG_ERR, "REDFISH_MESSAGE_ID=%s",
240 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s,%s",
241 psuName.c_str(), fanName.c_str(), NULL);
242 }
243 else
244 {
245 sd_journal_send(
246 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
247 LOG_ERR, "REDFISH_MESSAGE_ID=%s",
248 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s",
249 psuName.c_str(), NULL);
250 }
251 }
252
Cheng C Yang58b2b532019-05-31 00:19:45 +0800253 if ((*combineEvent).empty())
254 {
255 eventInterface->set_property("functional", true);
256 }
257 }
258 }
259 else
260 {
261 (*asserts).emplace(path);
262 if (*assertState == false)
263 {
264 *assertState = true;
jayaprakash Mutyala73c363f2019-12-04 19:34:17 +0000265 auto foundCombine = (*combineEvent).find(eventName);
266 if (foundCombine != (*combineEvent).end())
267 {
268 value = newValue;
269 return;
270 }
Cheng C Yang9b53a622019-08-27 22:13:58 +0800271 if (!assertMessage.empty())
Cheng C Yang5665db22019-07-12 00:57:30 +0800272 {
273 // Fan Failed has two args
274 std::string sendMessage = eventName + " assert";
Cheng C Yang9b53a622019-08-27 22:13:58 +0800275 if (assertMessage == "OpenBMC.0.1.PowerSupplyFanFailed")
Cheng C Yang5665db22019-07-12 00:57:30 +0800276 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800277 sd_journal_send(
278 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
279 LOG_ERR, "REDFISH_MESSAGE_ID=%s", assertMessage.c_str(),
280 "REDFISH_MESSAGE_ARGS=%s,%s", psuName.c_str(),
281 fanName.c_str(), NULL);
Cheng C Yang5665db22019-07-12 00:57:30 +0800282 }
283 else
284 {
285 sd_journal_send(
286 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Cheng C Yang9b53a622019-08-27 22:13:58 +0800287 LOG_ERR, "REDFISH_MESSAGE_ID=%s", assertMessage.c_str(),
Cheng C Yang5665db22019-07-12 00:57:30 +0800288 "REDFISH_MESSAGE_ARGS=%s", psuName.c_str(), NULL);
289 }
290 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800291 if ((*combineEvent).empty())
292 {
293 eventInterface->set_property("functional", false);
294 }
295 (*combineEvent).emplace(eventName);
296 }
297 }
298 value = newValue;
299}