blob: fd929b3e3abb22d4e11636644c62847a58549e1f [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
Cheng C Yang5665db22019-07-12 00:57:30 +080017#include <systemd/sd-journal.h>
18
Cheng C Yang58b2b532019-05-31 00:19:45 +080019#include <PSUEvent.hpp>
20#include <iostream>
21#include <sdbusplus/asio/connection.hpp>
22#include <sdbusplus/asio/object_server.hpp>
23
24PSUCombineEvent::PSUCombineEvent(
25 sdbusplus::asio::object_server& objectServer, boost::asio::io_service& io,
26 const std::string& psuName,
27 boost::container::flat_map<std::string, std::vector<std::string>>&
28 eventPathList,
29 const std::string& combineEventName) :
30 objServer(objectServer)
31{
32 eventInterface = objServer.add_interface(
33 "/xyz/openbmc_project/State/Decorator/" + psuName + "_" +
34 combineEventName,
35 "xyz.openbmc_project.State.Decorator.OperationalStatus");
James Feistb6c0b912019-07-09 12:21:44 -070036 eventInterface->register_property("functional", true);
Cheng C Yang58b2b532019-05-31 00:19:45 +080037
38 if (!eventInterface->initialize())
39 {
40 std::cerr << "error initializing event interface\n";
41 }
42
43 std::shared_ptr<std::set<std::string>> combineEvent =
44 std::make_shared<std::set<std::string>>();
45 for (const auto& pathList : eventPathList)
46 {
47 const std::string& eventName = pathList.first;
48 std::string eventPSUName = eventName + psuName;
49 for (const auto& path : pathList.second)
50 {
51 std::shared_ptr<std::set<std::string>> assert =
52 std::make_shared<std::set<std::string>>();
53 std::shared_ptr<bool> state = std::make_shared<bool>(false);
54 events[eventPSUName].emplace_back(std::make_unique<PSUSubEvent>(
55 eventInterface, path, io, eventName, assert, combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +080056 state, psuName));
Cheng C Yang58b2b532019-05-31 00:19:45 +080057 asserts.emplace_back(assert);
58 states.emplace_back(state);
59 }
60 }
61}
62
63PSUCombineEvent::~PSUCombineEvent()
64{
65 events.clear();
66 objServer.remove_interface(eventInterface);
67}
68
Cheng C Yang5665db22019-07-12 00:57:30 +080069static boost::container::flat_map<std::string, std::string> logID = {
70 {"PredictiveFailure", "OpenBMC.0.1.PowerSupplyFailurePredicted"},
71 {"Failure", "OpenBMC.0.1.PowerSupplyFailed"},
72 {"ACLost", "OpenBMC.0.1.PowerSupplyACLost"},
73 {"FanFault", "OpenBMC.0.1.PowerSupplyFanFailed"}};
74
Cheng C Yang58b2b532019-05-31 00:19:45 +080075PSUSubEvent::PSUSubEvent(
76 std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
77 const std::string& path, boost::asio::io_service& io,
78 const std::string& eventName,
79 std::shared_ptr<std::set<std::string>> asserts,
80 std::shared_ptr<std::set<std::string>> combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +080081 std::shared_ptr<bool> state, const std::string& psuName) :
Cheng C Yang58b2b532019-05-31 00:19:45 +080082 eventInterface(eventInterface),
83 inputDev(io, open(path.c_str(), O_RDONLY)), waitTimer(io), errCount(0),
84 path(path), eventName(eventName), assertState(state), asserts(asserts),
Cheng C Yang5665db22019-07-12 00:57:30 +080085 combineEvent(combineEvent), psuName(psuName)
Cheng C Yang58b2b532019-05-31 00:19:45 +080086{
Cheng C Yang5665db22019-07-12 00:57:30 +080087 auto found = logID.find(eventName);
88 if (found == logID.end())
89 {
90 messageID.clear();
91 }
92 else
93 {
94 messageID = found->second;
95 }
96
97 auto fanPos = path.find("fan");
98 if (fanPos != std::string::npos)
99 {
100 fanName = path.substr(fanPos);
101 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800102 setupRead();
103}
104
105void PSUSubEvent::setupRead(void)
106{
107 boost::asio::async_read_until(
108 inputDev, readBuf, '\n',
109 [&](const boost::system::error_code& ec,
110 std::size_t /*bytes_transfered*/) { handleResponse(ec); });
111}
112
113PSUSubEvent::~PSUSubEvent()
114{
115 inputDev.close();
116 waitTimer.cancel();
117}
118
119void PSUSubEvent::handleResponse(const boost::system::error_code& err)
120{
121 if (err == boost::system::errc::bad_file_descriptor)
122 {
123 return;
124 }
125 std::istream responseStream(&readBuf);
126 if (!err)
127 {
128 std::string response;
129 try
130 {
131 std::getline(responseStream, response);
132 int nvalue = std::stof(response);
133 responseStream.clear();
134 if (nvalue != value)
135 {
136 updateValue(nvalue);
137 }
138 errCount = 0;
139 }
140 catch (const std::invalid_argument&)
141 {
142 errCount++;
143 }
144 }
145 else
146 {
147 errCount++;
148 }
149 if (errCount >= warnAfterErrorCount)
150 {
151 if (errCount == warnAfterErrorCount)
152 {
153 std::cerr << "Failure to read event at " << path << "\n";
154 }
155 updateValue(0);
156 errCount++;
157 }
158 responseStream.clear();
159 inputDev.close();
160 int fd = open(path.c_str(), O_RDONLY);
161 if (fd <= 0)
162 {
163 return;
164 }
165 inputDev.assign(fd);
166 waitTimer.expires_from_now(boost::posix_time::milliseconds(eventPollMs));
167 waitTimer.async_wait([&](const boost::system::error_code& ec) {
168 if (ec == boost::asio::error::operation_aborted)
169 {
170 return;
171 }
172 setupRead();
173 });
174}
175
176// Any of the sub events of one event is asserted, then the event will be
177// asserted. Only if none of the sub events are asserted, the event will be
178// deasserted.
179void PSUSubEvent::updateValue(const int& newValue)
180{
181 if (newValue == 0)
182 {
183 auto found = (*asserts).find(path);
184 if (found == (*asserts).end())
185 {
186 return;
187 }
188 (*asserts).erase(found);
189
190 if (!(*asserts).empty())
191 {
192 return;
193 }
194 if (*assertState == true)
195 {
196 *assertState = false;
197 auto foundCombine = (*combineEvent).find(eventName);
198 if (foundCombine != (*combineEvent).end())
199 {
200 return;
201 }
202 (*combineEvent).erase(eventName);
203 if ((*combineEvent).empty())
204 {
205 eventInterface->set_property("functional", true);
206 }
207 }
208 }
209 else
210 {
211 (*asserts).emplace(path);
212 if (*assertState == false)
213 {
214 *assertState = true;
Cheng C Yang5665db22019-07-12 00:57:30 +0800215 if (!messageID.empty())
216 {
217 // Fan Failed has two args
218 std::string sendMessage = eventName + " assert";
219 if (messageID == "OpenBMC.0.1.PowerSupplyFanFailed")
220 {
221 sd_journal_send("MESSAGE=%s", sendMessage.c_str(),
222 "PRIORITY=%i", LOG_ERR,
223 "REDFISH_MESSAGE_ID=%s", messageID.c_str(),
224 "REDFISH_MESSAGE_ARGS=%s,%s",
225 psuName.c_str(), fanName.c_str(), NULL);
226 }
227 else
228 {
229 sd_journal_send(
230 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
231 LOG_ERR, "REDFISH_MESSAGE_ID=%s", messageID.c_str(),
232 "REDFISH_MESSAGE_ARGS=%s", psuName.c_str(), NULL);
233 }
234 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800235 if ((*combineEvent).empty())
236 {
237 eventInterface->set_property("functional", false);
238 }
239 (*combineEvent).emplace(eventName);
240 }
241 }
242 value = newValue;
243}