blob: d40dc54f77ac2f3e7b991f1fbb6bb0a408513f8a [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
Cheng C Yang58b2b532019-05-31 00:19:45 +080021#include <iostream>
22#include <sdbusplus/asio/connection.hpp>
23#include <sdbusplus/asio/object_server.hpp>
24
25PSUCombineEvent::PSUCombineEvent(
26 sdbusplus::asio::object_server& objectServer, boost::asio::io_service& io,
27 const std::string& psuName,
28 boost::container::flat_map<std::string, std::vector<std::string>>&
29 eventPathList,
30 const std::string& combineEventName) :
31 objServer(objectServer)
32{
33 eventInterface = objServer.add_interface(
34 "/xyz/openbmc_project/State/Decorator/" + psuName + "_" +
35 combineEventName,
36 "xyz.openbmc_project.State.Decorator.OperationalStatus");
James Feistb6c0b912019-07-09 12:21:44 -070037 eventInterface->register_property("functional", true);
Cheng C Yang58b2b532019-05-31 00:19:45 +080038
39 if (!eventInterface->initialize())
40 {
41 std::cerr << "error initializing event interface\n";
42 }
43
44 std::shared_ptr<std::set<std::string>> combineEvent =
45 std::make_shared<std::set<std::string>>();
46 for (const auto& pathList : eventPathList)
47 {
48 const std::string& eventName = pathList.first;
49 std::string eventPSUName = eventName + psuName;
50 for (const auto& path : pathList.second)
51 {
52 std::shared_ptr<std::set<std::string>> assert =
53 std::make_shared<std::set<std::string>>();
54 std::shared_ptr<bool> state = std::make_shared<bool>(false);
55 events[eventPSUName].emplace_back(std::make_unique<PSUSubEvent>(
56 eventInterface, path, io, eventName, assert, combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +080057 state, psuName));
Cheng C Yang58b2b532019-05-31 00:19:45 +080058 asserts.emplace_back(assert);
59 states.emplace_back(state);
60 }
61 }
62}
63
64PSUCombineEvent::~PSUCombineEvent()
65{
66 events.clear();
67 objServer.remove_interface(eventInterface);
68}
69
Cheng C Yang9b53a622019-08-27 22:13:58 +080070static boost::container::flat_map<std::string,
71 std::pair<std::string, std::string>>
72 logID = {
73 {"PredictiveFailure",
74 {"OpenBMC.0.1.PowerSupplyFailurePredicted",
75 "OpenBMC.0.1.PowerSupplyPredictedFailureRecovered"}},
76 {"Failure",
77 {"OpenBMC.0.1.PowerSupplyFailed", "OpenBMC.0.1.PowerSupplyRecovered"}},
78 {"ACLost",
Cheng C Yangbb732ef2019-09-18 16:25:58 +080079 {"OpenBMC.0.1.PowerSupplyPowerLost",
80 "OpenBMC.0.1.PowerSupplyPowerRestored"}},
Cheng C Yang9b53a622019-08-27 22:13:58 +080081 {"FanFault",
82 {"OpenBMC.0.1.PowerSupplyFanFailed",
83 "OpenBMC.0.1.PowerSupplyFanRecovered"}},
84 {"ConfigureError", {"OpenBMC.0.1.PowerSupplyConfigurationError", ""}}};
Cheng C Yang5665db22019-07-12 00:57:30 +080085
Cheng C Yang58b2b532019-05-31 00:19:45 +080086PSUSubEvent::PSUSubEvent(
87 std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
88 const std::string& path, boost::asio::io_service& io,
89 const std::string& eventName,
90 std::shared_ptr<std::set<std::string>> asserts,
91 std::shared_ptr<std::set<std::string>> combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +080092 std::shared_ptr<bool> state, const std::string& psuName) :
Cheng C Yang58b2b532019-05-31 00:19:45 +080093 eventInterface(eventInterface),
94 inputDev(io, open(path.c_str(), O_RDONLY)), waitTimer(io), errCount(0),
95 path(path), eventName(eventName), assertState(state), asserts(asserts),
Cheng C Yang5665db22019-07-12 00:57:30 +080096 combineEvent(combineEvent), psuName(psuName)
Cheng C Yang58b2b532019-05-31 00:19:45 +080097{
Cheng C Yang5665db22019-07-12 00:57:30 +080098 auto found = logID.find(eventName);
99 if (found == logID.end())
100 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800101 assertMessage.clear();
102 deassertMessage.clear();
Cheng C Yang5665db22019-07-12 00:57:30 +0800103 }
104 else
105 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800106 assertMessage = found->second.first;
107 deassertMessage = found->second.second;
Cheng C Yang5665db22019-07-12 00:57:30 +0800108 }
109
110 auto fanPos = path.find("fan");
111 if (fanPos != std::string::npos)
112 {
113 fanName = path.substr(fanPos);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800114 auto fanNamePos = fanName.find("_");
115 if (fanNamePos != std::string::npos)
116 {
117 fanName = fanName.substr(0, fanNamePos);
118 }
Cheng C Yang5665db22019-07-12 00:57:30 +0800119 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800120 setupRead();
121}
122
123void PSUSubEvent::setupRead(void)
124{
125 boost::asio::async_read_until(
126 inputDev, readBuf, '\n',
127 [&](const boost::system::error_code& ec,
128 std::size_t /*bytes_transfered*/) { handleResponse(ec); });
129}
130
131PSUSubEvent::~PSUSubEvent()
132{
133 inputDev.close();
134 waitTimer.cancel();
135}
136
137void PSUSubEvent::handleResponse(const boost::system::error_code& err)
138{
139 if (err == boost::system::errc::bad_file_descriptor)
140 {
141 return;
142 }
143 std::istream responseStream(&readBuf);
144 if (!err)
145 {
146 std::string response;
147 try
148 {
149 std::getline(responseStream, response);
150 int nvalue = std::stof(response);
151 responseStream.clear();
152 if (nvalue != value)
153 {
154 updateValue(nvalue);
155 }
156 errCount = 0;
157 }
158 catch (const std::invalid_argument&)
159 {
160 errCount++;
161 }
162 }
163 else
164 {
165 errCount++;
166 }
167 if (errCount >= warnAfterErrorCount)
168 {
169 if (errCount == warnAfterErrorCount)
170 {
171 std::cerr << "Failure to read event at " << path << "\n";
172 }
173 updateValue(0);
174 errCount++;
175 }
176 responseStream.clear();
177 inputDev.close();
178 int fd = open(path.c_str(), O_RDONLY);
Jae Hyun Yooef9665a2019-10-10 10:26:39 -0700179 if (fd < 0)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800180 {
181 return;
182 }
183 inputDev.assign(fd);
184 waitTimer.expires_from_now(boost::posix_time::milliseconds(eventPollMs));
185 waitTimer.async_wait([&](const boost::system::error_code& ec) {
186 if (ec == boost::asio::error::operation_aborted)
187 {
188 return;
189 }
190 setupRead();
191 });
192}
193
194// Any of the sub events of one event is asserted, then the event will be
195// asserted. Only if none of the sub events are asserted, the event will be
196// deasserted.
197void PSUSubEvent::updateValue(const int& newValue)
198{
199 if (newValue == 0)
200 {
201 auto found = (*asserts).find(path);
202 if (found == (*asserts).end())
203 {
204 return;
205 }
Cheng C Yang9b53a622019-08-27 22:13:58 +0800206 (*asserts).erase(path);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800207
208 if (!(*asserts).empty())
209 {
210 return;
211 }
212 if (*assertState == true)
213 {
214 *assertState = false;
215 auto foundCombine = (*combineEvent).find(eventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800216 if (foundCombine == (*combineEvent).end())
Cheng C Yang58b2b532019-05-31 00:19:45 +0800217 {
218 return;
219 }
220 (*combineEvent).erase(eventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800221 if (!deassertMessage.empty())
222 {
223 // Fan Failed has two args
224 std::string sendMessage = eventName + " deassert";
225 if (deassertMessage == "OpenBMC.0.1.PowerSupplyFanRecovered")
226 {
227 sd_journal_send(
228 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
229 LOG_ERR, "REDFISH_MESSAGE_ID=%s",
230 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s,%s",
231 psuName.c_str(), fanName.c_str(), NULL);
232 }
233 else
234 {
235 sd_journal_send(
236 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
237 LOG_ERR, "REDFISH_MESSAGE_ID=%s",
238 deassertMessage.c_str(), "REDFISH_MESSAGE_ARGS=%s",
239 psuName.c_str(), NULL);
240 }
241 }
242
Cheng C Yang58b2b532019-05-31 00:19:45 +0800243 if ((*combineEvent).empty())
244 {
245 eventInterface->set_property("functional", true);
246 }
247 }
248 }
249 else
250 {
251 (*asserts).emplace(path);
252 if (*assertState == false)
253 {
254 *assertState = true;
Cheng C Yang9b53a622019-08-27 22:13:58 +0800255 if (!assertMessage.empty())
Cheng C Yang5665db22019-07-12 00:57:30 +0800256 {
257 // Fan Failed has two args
258 std::string sendMessage = eventName + " assert";
Cheng C Yang9b53a622019-08-27 22:13:58 +0800259 if (assertMessage == "OpenBMC.0.1.PowerSupplyFanFailed")
Cheng C Yang5665db22019-07-12 00:57:30 +0800260 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800261 sd_journal_send(
262 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
263 LOG_ERR, "REDFISH_MESSAGE_ID=%s", assertMessage.c_str(),
264 "REDFISH_MESSAGE_ARGS=%s,%s", psuName.c_str(),
265 fanName.c_str(), NULL);
Cheng C Yang5665db22019-07-12 00:57:30 +0800266 }
267 else
268 {
269 sd_journal_send(
270 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
Cheng C Yang9b53a622019-08-27 22:13:58 +0800271 LOG_ERR, "REDFISH_MESSAGE_ID=%s", assertMessage.c_str(),
Cheng C Yang5665db22019-07-12 00:57:30 +0800272 "REDFISH_MESSAGE_ARGS=%s", psuName.c_str(), NULL);
273 }
274 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800275 if ((*combineEvent).empty())
276 {
277 eventInterface->set_property("functional", false);
278 }
279 (*combineEvent).emplace(eventName);
280 }
281 }
282 value = newValue;
283}