blob: 7c6fbea43b68e83e8a9a8f35a844622dc741983e [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"},
Cheng C Yang9c45e6b2019-08-13 07:21:32 +080073 {"FanFault", "OpenBMC.0.1.PowerSupplyFanFailed"},
74 {"ConfigureError", "OpenBMC.0.1.PowerSupplyConfigurationError"}};
Cheng C Yang5665db22019-07-12 00:57:30 +080075
Cheng C Yang58b2b532019-05-31 00:19:45 +080076PSUSubEvent::PSUSubEvent(
77 std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
78 const std::string& path, boost::asio::io_service& io,
79 const std::string& eventName,
80 std::shared_ptr<std::set<std::string>> asserts,
81 std::shared_ptr<std::set<std::string>> combineEvent,
Cheng C Yang5665db22019-07-12 00:57:30 +080082 std::shared_ptr<bool> state, const std::string& psuName) :
Cheng C Yang58b2b532019-05-31 00:19:45 +080083 eventInterface(eventInterface),
84 inputDev(io, open(path.c_str(), O_RDONLY)), waitTimer(io), errCount(0),
85 path(path), eventName(eventName), assertState(state), asserts(asserts),
Cheng C Yang5665db22019-07-12 00:57:30 +080086 combineEvent(combineEvent), psuName(psuName)
Cheng C Yang58b2b532019-05-31 00:19:45 +080087{
Cheng C Yang5665db22019-07-12 00:57:30 +080088 auto found = logID.find(eventName);
89 if (found == logID.end())
90 {
91 messageID.clear();
92 }
93 else
94 {
95 messageID = found->second;
96 }
97
98 auto fanPos = path.find("fan");
99 if (fanPos != std::string::npos)
100 {
101 fanName = path.substr(fanPos);
102 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800103 setupRead();
104}
105
106void PSUSubEvent::setupRead(void)
107{
108 boost::asio::async_read_until(
109 inputDev, readBuf, '\n',
110 [&](const boost::system::error_code& ec,
111 std::size_t /*bytes_transfered*/) { handleResponse(ec); });
112}
113
114PSUSubEvent::~PSUSubEvent()
115{
116 inputDev.close();
117 waitTimer.cancel();
118}
119
120void PSUSubEvent::handleResponse(const boost::system::error_code& err)
121{
122 if (err == boost::system::errc::bad_file_descriptor)
123 {
124 return;
125 }
126 std::istream responseStream(&readBuf);
127 if (!err)
128 {
129 std::string response;
130 try
131 {
132 std::getline(responseStream, response);
133 int nvalue = std::stof(response);
134 responseStream.clear();
135 if (nvalue != value)
136 {
137 updateValue(nvalue);
138 }
139 errCount = 0;
140 }
141 catch (const std::invalid_argument&)
142 {
143 errCount++;
144 }
145 }
146 else
147 {
148 errCount++;
149 }
150 if (errCount >= warnAfterErrorCount)
151 {
152 if (errCount == warnAfterErrorCount)
153 {
154 std::cerr << "Failure to read event at " << path << "\n";
155 }
156 updateValue(0);
157 errCount++;
158 }
159 responseStream.clear();
160 inputDev.close();
161 int fd = open(path.c_str(), O_RDONLY);
162 if (fd <= 0)
163 {
164 return;
165 }
166 inputDev.assign(fd);
167 waitTimer.expires_from_now(boost::posix_time::milliseconds(eventPollMs));
168 waitTimer.async_wait([&](const boost::system::error_code& ec) {
169 if (ec == boost::asio::error::operation_aborted)
170 {
171 return;
172 }
173 setupRead();
174 });
175}
176
177// Any of the sub events of one event is asserted, then the event will be
178// asserted. Only if none of the sub events are asserted, the event will be
179// deasserted.
180void PSUSubEvent::updateValue(const int& newValue)
181{
182 if (newValue == 0)
183 {
184 auto found = (*asserts).find(path);
185 if (found == (*asserts).end())
186 {
187 return;
188 }
189 (*asserts).erase(found);
190
191 if (!(*asserts).empty())
192 {
193 return;
194 }
195 if (*assertState == true)
196 {
197 *assertState = false;
198 auto foundCombine = (*combineEvent).find(eventName);
199 if (foundCombine != (*combineEvent).end())
200 {
201 return;
202 }
203 (*combineEvent).erase(eventName);
204 if ((*combineEvent).empty())
205 {
206 eventInterface->set_property("functional", true);
207 }
208 }
209 }
210 else
211 {
212 (*asserts).emplace(path);
213 if (*assertState == false)
214 {
215 *assertState = true;
Cheng C Yang5665db22019-07-12 00:57:30 +0800216 if (!messageID.empty())
217 {
218 // Fan Failed has two args
219 std::string sendMessage = eventName + " assert";
220 if (messageID == "OpenBMC.0.1.PowerSupplyFanFailed")
221 {
222 sd_journal_send("MESSAGE=%s", sendMessage.c_str(),
223 "PRIORITY=%i", LOG_ERR,
224 "REDFISH_MESSAGE_ID=%s", messageID.c_str(),
225 "REDFISH_MESSAGE_ARGS=%s,%s",
226 psuName.c_str(), fanName.c_str(), NULL);
227 }
228 else
229 {
230 sd_journal_send(
231 "MESSAGE=%s", sendMessage.c_str(), "PRIORITY=%i",
232 LOG_ERR, "REDFISH_MESSAGE_ID=%s", messageID.c_str(),
233 "REDFISH_MESSAGE_ARGS=%s", psuName.c_str(), NULL);
234 }
235 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800236 if ((*combineEvent).empty())
237 {
238 eventInterface->set_property("functional", false);
239 }
240 (*combineEvent).emplace(eventName);
241 }
242 }
243 value = newValue;
244}