blob: 0849500ef684aa2c4eb07abc63aa29f4634cf52c [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),
Cheng C Yanga97f1342020-02-11 15:10:41 +0800138 errCount(0), path(path), eventName(eventName), waitTimer(io), inputDev(io),
139 psuName(psuName), groupEventName(groupEventName)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800140{
Cheng C Yanga97f1342020-02-11 15:10:41 +0800141 fd = open(path.c_str(), O_RDONLY);
142 if (fd < 0)
143 {
144 std::cerr << "PSU sub event failed to open file\n";
145 return;
146 }
147 inputDev.assign(fd);
148
Cheng C Yang5665db22019-07-12 00:57:30 +0800149 auto found = logID.find(eventName);
150 if (found == logID.end())
151 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800152 assertMessage.clear();
153 deassertMessage.clear();
Cheng C Yang5665db22019-07-12 00:57:30 +0800154 }
155 else
156 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800157 assertMessage = found->second.first;
158 deassertMessage = found->second.second;
Cheng C Yang5665db22019-07-12 00:57:30 +0800159 }
160
161 auto fanPos = path.find("fan");
162 if (fanPos != std::string::npos)
163 {
164 fanName = path.substr(fanPos);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800165 auto fanNamePos = fanName.find("_");
166 if (fanNamePos != std::string::npos)
167 {
168 fanName = fanName.substr(0, fanNamePos);
169 }
Cheng C Yang5665db22019-07-12 00:57:30 +0800170 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800171 setupRead();
172}
173
174void PSUSubEvent::setupRead(void)
175{
176 boost::asio::async_read_until(
177 inputDev, readBuf, '\n',
178 [&](const boost::system::error_code& ec,
179 std::size_t /*bytes_transfered*/) { handleResponse(ec); });
180}
181
182PSUSubEvent::~PSUSubEvent()
183{
Cheng C Yang58b2b532019-05-31 00:19:45 +0800184 waitTimer.cancel();
Cheng C Yanga97f1342020-02-11 15:10:41 +0800185 inputDev.close();
Cheng C Yang58b2b532019-05-31 00:19:45 +0800186}
187
188void PSUSubEvent::handleResponse(const boost::system::error_code& err)
189{
190 if (err == boost::system::errc::bad_file_descriptor)
191 {
192 return;
193 }
194 std::istream responseStream(&readBuf);
195 if (!err)
196 {
197 std::string response;
198 try
199 {
200 std::getline(responseStream, response);
Josh Lehan833661a2020-03-04 17:35:41 -0800201 int nvalue = std::stoi(response);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800202 responseStream.clear();
Josh Lehan833661a2020-03-04 17:35:41 -0800203
204 updateValue(nvalue);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800205 errCount = 0;
206 }
207 catch (const std::invalid_argument&)
208 {
209 errCount++;
210 }
211 }
212 else
213 {
214 errCount++;
215 }
216 if (errCount >= warnAfterErrorCount)
217 {
218 if (errCount == warnAfterErrorCount)
219 {
220 std::cerr << "Failure to read event at " << path << "\n";
221 }
222 updateValue(0);
223 errCount++;
224 }
Cheng C Yanga97f1342020-02-11 15:10:41 +0800225 lseek(fd, 0, SEEK_SET);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800226 waitTimer.expires_from_now(boost::posix_time::milliseconds(eventPollMs));
227 waitTimer.async_wait([&](const boost::system::error_code& ec) {
228 if (ec == boost::asio::error::operation_aborted)
229 {
230 return;
231 }
232 setupRead();
233 });
234}
235
236// Any of the sub events of one event is asserted, then the event will be
237// asserted. Only if none of the sub events are asserted, the event will be
238// deasserted.
239void PSUSubEvent::updateValue(const int& newValue)
240{
Josh Lehan833661a2020-03-04 17:35:41 -0800241 // Take no action if value already equal
242 // Same semantics as Sensor::updateValue(const double&)
243 if (newValue == value)
244 {
245 return;
246 }
247
Cheng C Yang58b2b532019-05-31 00:19:45 +0800248 if (newValue == 0)
249 {
Yong Li591b1e42019-12-19 17:46:31 +0800250 // log deassert only after all asserts are gone
Cheng C Yang58b2b532019-05-31 00:19:45 +0800251 if (!(*asserts).empty())
252 {
Yong Li591b1e42019-12-19 17:46:31 +0800253 auto found = (*asserts).find(path);
254 if (found == (*asserts).end())
255 {
256 return;
257 }
258 (*asserts).erase(path);
259
Cheng C Yang58b2b532019-05-31 00:19:45 +0800260 return;
261 }
262 if (*assertState == true)
263 {
264 *assertState = false;
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800265 auto foundCombine = (*combineEvent).find(groupEventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800266 if (foundCombine == (*combineEvent).end())
Cheng C Yang58b2b532019-05-31 00:19:45 +0800267 {
268 return;
269 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800270 (*combineEvent).erase(groupEventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800271 if (!deassertMessage.empty())
272 {
273 // Fan Failed has two args
274 std::string sendMessage = eventName + " deassert";
275 if (deassertMessage == "OpenBMC.0.1.PowerSupplyFanRecovered")
276 {
277 sd_journal_send(
278 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800279 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
Cheng C Yang9b53a622019-08-27 22:13:58 +0800280 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s,%s",
281 psuName.c_str(), fanName.c_str(), NULL);
282 }
283 else
284 {
285 sd_journal_send(
286 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800287 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
Cheng C Yang9b53a622019-08-27 22:13:58 +0800288 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s",
289 psuName.c_str(), NULL);
290 }
291 }
292
Cheng C Yang58b2b532019-05-31 00:19:45 +0800293 if ((*combineEvent).empty())
294 {
295 eventInterface->set_property("functional", true);
296 }
297 }
298 }
299 else
300 {
Yong Li591b1e42019-12-19 17:46:31 +0800301 if ((*assertState == false) && ((*asserts).empty()))
Cheng C Yang58b2b532019-05-31 00:19:45 +0800302 {
303 *assertState = true;
Cheng C Yang9b53a622019-08-27 22:13:58 +0800304 if (!assertMessage.empty())
Cheng C Yang5665db22019-07-12 00:57:30 +0800305 {
306 // Fan Failed has two args
307 std::string sendMessage = eventName + " assert";
Cheng C Yang9b53a622019-08-27 22:13:58 +0800308 if (assertMessage == "OpenBMC.0.1.PowerSupplyFanFailed")
Cheng C Yang5665db22019-07-12 00:57:30 +0800309 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800310 sd_journal_send(
311 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800312 LOG_WARNING, "REDFISH_MESSAGE_ID=%s",
313 assertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s,%s",
314 psuName.c_str(), fanName.c_str(), NULL);
Cheng C Yang5665db22019-07-12 00:57:30 +0800315 }
316 else
317 {
318 sd_journal_send(
319 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800320 LOG_WARNING, "REDFISH_MESSAGE_ID=%s",
321 assertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s",
322 psuName.c_str(), NULL);
Cheng C Yang5665db22019-07-12 00:57:30 +0800323 }
324 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800325 if ((*combineEvent).empty())
326 {
327 eventInterface->set_property("functional", false);
328 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800329 (*combineEvent).emplace(groupEventName);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800330 }
Yong Li591b1e42019-12-19 17:46:31 +0800331 (*asserts).emplace(path);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800332 }
333 value = newValue;
334}