blob: 1e228fe460ff58919a2a80e71e5a558d358af474 [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(
Yong Li3046a022020-04-03 13:01:02 +080033 sdbusplus::asio::object_server& objectServer,
34 std::shared_ptr<sdbusplus::asio::connection>& conn,
35 boost::asio::io_service& io, const std::string& psuName,
Cheng C Yang58b2b532019-05-31 00:19:45 +080036 boost::container::flat_map<std::string, std::vector<std::string>>&
37 eventPathList,
Cheng C Yang202a1ff2020-01-09 09:34:22 +080038 boost::container::flat_map<
39 std::string,
40 boost::container::flat_map<std::string, std::vector<std::string>>>&
41 groupEventPathList,
Cheng C Yang58b2b532019-05-31 00:19:45 +080042 const std::string& combineEventName) :
43 objServer(objectServer)
44{
45 eventInterface = objServer.add_interface(
46 "/xyz/openbmc_project/State/Decorator/" + psuName + "_" +
47 combineEventName,
48 "xyz.openbmc_project.State.Decorator.OperationalStatus");
James Feistb6c0b912019-07-09 12:21:44 -070049 eventInterface->register_property("functional", true);
Cheng C Yang58b2b532019-05-31 00:19:45 +080050
51 if (!eventInterface->initialize())
52 {
53 std::cerr << "error initializing event interface\n";
54 }
55
56 std::shared_ptr<std::set<std::string>> combineEvent =
57 std::make_shared<std::set<std::string>>();
58 for (const auto& pathList : eventPathList)
59 {
Yong Li591b1e42019-12-19 17:46:31 +080060 std::shared_ptr<std::set<std::string>> assert =
61 std::make_shared<std::set<std::string>>();
Cheng C Yang202a1ff2020-01-09 09:34:22 +080062 std::shared_ptr<bool> state = std::make_shared<bool>(false);
Yong Li591b1e42019-12-19 17:46:31 +080063
Cheng C Yang58b2b532019-05-31 00:19:45 +080064 const std::string& eventName = pathList.first;
65 std::string eventPSUName = eventName + psuName;
66 for (const auto& path : pathList.second)
67 {
Cheng C Yang58b2b532019-05-31 00:19:45 +080068 events[eventPSUName].emplace_back(std::make_unique<PSUSubEvent>(
Yong Li3046a022020-04-03 13:01:02 +080069 eventInterface, path, conn, io, eventName, eventName, assert,
Cheng C Yang202a1ff2020-01-09 09:34:22 +080070 combineEvent, state, psuName));
Cheng C Yang58b2b532019-05-31 00:19:45 +080071 asserts.emplace_back(assert);
72 states.emplace_back(state);
73 }
74 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +080075
76 for (const auto& groupPathList : groupEventPathList)
77 {
78 for (const auto& pathList : groupPathList.second)
79 {
80 std::shared_ptr<std::set<std::string>> assert =
81 std::make_shared<std::set<std::string>>();
82 std::shared_ptr<bool> state = std::make_shared<bool>(false);
83
84 const std::string& groupEventName = pathList.first;
85 std::string eventPSUName = groupEventName + psuName;
86 for (const auto& path : pathList.second)
87 {
88 events[eventPSUName].emplace_back(std::make_unique<PSUSubEvent>(
Yong Li3046a022020-04-03 13:01:02 +080089 eventInterface, path, conn, io, groupEventName,
Cheng C Yang202a1ff2020-01-09 09:34:22 +080090 groupPathList.first, assert, combineEvent, state, psuName));
91 asserts.emplace_back(assert);
92 states.emplace_back(state);
93 }
94 }
95 }
Cheng C Yang58b2b532019-05-31 00:19:45 +080096}
97
98PSUCombineEvent::~PSUCombineEvent()
99{
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800100 // Clear unique_ptr first
101 for (auto& event : events)
102 {
103 for (auto& subEventPtr : event.second)
104 {
105 subEventPtr.reset();
106 }
107 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800108 events.clear();
109 objServer.remove_interface(eventInterface);
110}
111
Cheng C Yang9b53a622019-08-27 22:13:58 +0800112static boost::container::flat_map<std::string,
113 std::pair<std::string, std::string>>
114 logID = {
115 {"PredictiveFailure",
116 {"OpenBMC.0.1.PowerSupplyFailurePredicted",
117 "OpenBMC.0.1.PowerSupplyPredictedFailureRecovered"}},
118 {"Failure",
119 {"OpenBMC.0.1.PowerSupplyFailed", "OpenBMC.0.1.PowerSupplyRecovered"}},
120 {"ACLost",
Cheng C Yangbb732ef2019-09-18 16:25:58 +0800121 {"OpenBMC.0.1.PowerSupplyPowerLost",
122 "OpenBMC.0.1.PowerSupplyPowerRestored"}},
Cheng C Yang9b53a622019-08-27 22:13:58 +0800123 {"FanFault",
124 {"OpenBMC.0.1.PowerSupplyFanFailed",
125 "OpenBMC.0.1.PowerSupplyFanRecovered"}},
jayaprakash Mutyalad12f23e2019-12-03 23:03:52 +0000126 {"ConfigureError",
127 {"OpenBMC.0.1.PowerSupplyConfigurationError",
128 "OpenBMC.0.1.PowerSupplyConfigurationErrorRecovered"}}};
Cheng C Yang5665db22019-07-12 00:57:30 +0800129
Cheng C Yang58b2b532019-05-31 00:19:45 +0800130PSUSubEvent::PSUSubEvent(
131 std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
Yong Li3046a022020-04-03 13:01:02 +0800132 const std::string& path, std::shared_ptr<sdbusplus::asio::connection>& conn,
133 boost::asio::io_service& io, const std::string& groupEventName,
134 const std::string& eventName,
Cheng C Yang58b2b532019-05-31 00:19:45 +0800135 std::shared_ptr<std::set<std::string>> asserts,
136 std::shared_ptr<std::set<std::string>> combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +0800137 std::shared_ptr<bool> state, const std::string& psuName) :
Cheng C Yang58b2b532019-05-31 00:19:45 +0800138 eventInterface(eventInterface),
Brad Bishopfbb44ad2019-11-08 09:42:37 -0500139 asserts(asserts), combineEvent(combineEvent), assertState(state),
Cheng C Yanga97f1342020-02-11 15:10:41 +0800140 errCount(0), path(path), eventName(eventName), waitTimer(io), inputDev(io),
Yong Li3046a022020-04-03 13:01:02 +0800141 psuName(psuName), groupEventName(groupEventName), systemBus(conn)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800142{
Cheng C Yanga97f1342020-02-11 15:10:41 +0800143 fd = open(path.c_str(), O_RDONLY);
144 if (fd < 0)
145 {
146 std::cerr << "PSU sub event failed to open file\n";
147 return;
148 }
149 inputDev.assign(fd);
150
Cheng C Yang5665db22019-07-12 00:57:30 +0800151 auto found = logID.find(eventName);
152 if (found == logID.end())
153 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800154 assertMessage.clear();
155 deassertMessage.clear();
Cheng C Yang5665db22019-07-12 00:57:30 +0800156 }
157 else
158 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800159 assertMessage = found->second.first;
160 deassertMessage = found->second.second;
Cheng C Yang5665db22019-07-12 00:57:30 +0800161 }
162
163 auto fanPos = path.find("fan");
164 if (fanPos != std::string::npos)
165 {
166 fanName = path.substr(fanPos);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800167 auto fanNamePos = fanName.find("_");
168 if (fanNamePos != std::string::npos)
169 {
170 fanName = fanName.substr(0, fanNamePos);
171 }
Cheng C Yang5665db22019-07-12 00:57:30 +0800172 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800173 setupRead();
174}
175
176void PSUSubEvent::setupRead(void)
177{
178 boost::asio::async_read_until(
179 inputDev, readBuf, '\n',
180 [&](const boost::system::error_code& ec,
181 std::size_t /*bytes_transfered*/) { handleResponse(ec); });
182}
183
184PSUSubEvent::~PSUSubEvent()
185{
Cheng C Yang58b2b532019-05-31 00:19:45 +0800186 waitTimer.cancel();
Cheng C Yanga97f1342020-02-11 15:10:41 +0800187 inputDev.close();
Cheng C Yang58b2b532019-05-31 00:19:45 +0800188}
189
190void PSUSubEvent::handleResponse(const boost::system::error_code& err)
191{
192 if (err == boost::system::errc::bad_file_descriptor)
193 {
194 return;
195 }
196 std::istream responseStream(&readBuf);
197 if (!err)
198 {
199 std::string response;
200 try
201 {
202 std::getline(responseStream, response);
Josh Lehan833661a2020-03-04 17:35:41 -0800203 int nvalue = std::stoi(response);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800204 responseStream.clear();
Josh Lehan833661a2020-03-04 17:35:41 -0800205
206 updateValue(nvalue);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800207 errCount = 0;
208 }
209 catch (const std::invalid_argument&)
210 {
211 errCount++;
212 }
213 }
214 else
215 {
216 errCount++;
217 }
218 if (errCount >= warnAfterErrorCount)
219 {
220 if (errCount == warnAfterErrorCount)
221 {
222 std::cerr << "Failure to read event at " << path << "\n";
223 }
224 updateValue(0);
225 errCount++;
226 }
Cheng C Yanga97f1342020-02-11 15:10:41 +0800227 lseek(fd, 0, SEEK_SET);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800228 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{
Josh Lehan833661a2020-03-04 17:35:41 -0800243 // Take no action if value already equal
244 // Same semantics as Sensor::updateValue(const double&)
245 if (newValue == value)
246 {
247 return;
248 }
249
Cheng C Yang58b2b532019-05-31 00:19:45 +0800250 if (newValue == 0)
251 {
Yong Li591b1e42019-12-19 17:46:31 +0800252 // log deassert only after all asserts are gone
Cheng C Yang58b2b532019-05-31 00:19:45 +0800253 if (!(*asserts).empty())
254 {
Yong Li591b1e42019-12-19 17:46:31 +0800255 auto found = (*asserts).find(path);
256 if (found == (*asserts).end())
257 {
258 return;
259 }
260 (*asserts).erase(path);
261
Cheng C Yang58b2b532019-05-31 00:19:45 +0800262 return;
263 }
264 if (*assertState == true)
265 {
266 *assertState = false;
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800267 auto foundCombine = (*combineEvent).find(groupEventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800268 if (foundCombine == (*combineEvent).end())
Cheng C Yang58b2b532019-05-31 00:19:45 +0800269 {
270 return;
271 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800272 (*combineEvent).erase(groupEventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800273 if (!deassertMessage.empty())
274 {
275 // Fan Failed has two args
276 std::string sendMessage = eventName + " deassert";
277 if (deassertMessage == "OpenBMC.0.1.PowerSupplyFanRecovered")
278 {
279 sd_journal_send(
280 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800281 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
Cheng C Yang9b53a622019-08-27 22:13:58 +0800282 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s,%s",
283 psuName.c_str(), fanName.c_str(), NULL);
284 }
285 else
286 {
287 sd_journal_send(
288 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800289 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
Cheng C Yang9b53a622019-08-27 22:13:58 +0800290 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s",
291 psuName.c_str(), NULL);
292 }
293 }
294
Cheng C Yang58b2b532019-05-31 00:19:45 +0800295 if ((*combineEvent).empty())
296 {
297 eventInterface->set_property("functional", true);
298 }
299 }
300 }
301 else
302 {
Yong Li591b1e42019-12-19 17:46:31 +0800303 if ((*assertState == false) && ((*asserts).empty()))
Cheng C Yang58b2b532019-05-31 00:19:45 +0800304 {
305 *assertState = true;
Cheng C Yang9b53a622019-08-27 22:13:58 +0800306 if (!assertMessage.empty())
Cheng C Yang5665db22019-07-12 00:57:30 +0800307 {
Yong Li3046a022020-04-03 13:01:02 +0800308 // For failure and configure error, spec requires a beep
309 if ((assertMessage == "OpenBMC.0.1.PowerSupplyFailed") ||
310 (assertMessage ==
311 "OpenBMC.0.1.PowerSupplyConfigurationError"))
312 {
313 std::cout << " beep for " << assertMessage << "\n";
314 beep(beepPSUFailure);
315 }
316
Cheng C Yang5665db22019-07-12 00:57:30 +0800317 // Fan Failed has two args
318 std::string sendMessage = eventName + " assert";
Cheng C Yang9b53a622019-08-27 22:13:58 +0800319 if (assertMessage == "OpenBMC.0.1.PowerSupplyFanFailed")
Cheng C Yang5665db22019-07-12 00:57:30 +0800320 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800321 sd_journal_send(
322 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800323 LOG_WARNING, "REDFISH_MESSAGE_ID=%s",
324 assertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s,%s",
325 psuName.c_str(), fanName.c_str(), NULL);
Cheng C Yang5665db22019-07-12 00:57:30 +0800326 }
327 else
328 {
329 sd_journal_send(
330 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Yong Li591b1e42019-12-19 17:46:31 +0800331 LOG_WARNING, "REDFISH_MESSAGE_ID=%s",
332 assertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s",
333 psuName.c_str(), NULL);
Cheng C Yang5665db22019-07-12 00:57:30 +0800334 }
335 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800336 if ((*combineEvent).empty())
337 {
338 eventInterface->set_property("functional", false);
339 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800340 (*combineEvent).emplace(groupEventName);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800341 }
Yong Li591b1e42019-12-19 17:46:31 +0800342 (*asserts).emplace(path);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800343 }
344 value = newValue;
345}
Yong Li3046a022020-04-03 13:01:02 +0800346
347void PSUSubEvent::beep(const uint8_t& beepPriority)
348{
349 systemBus->async_method_call(
350 [](boost::system::error_code ec) {
351 if (ec)
352 {
353 std::cerr << "beep error (ec = " << ec << ")\n";
354 return;
355 }
356 },
357 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
358 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
359}