blob: 353e1f18ed5fb882c9ad4957bb667753d5b1ccae [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
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103017#include "PSUEvent.hpp"
18
19#include "SensorPaths.hpp"
Ed Tanouseacbfdd2024-04-04 12:00:24 -070020#include "Utils.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103021
Ed Tanouseacbfdd2024-04-04 12:00:24 -070022#include <boost/asio/buffer.hpp>
23#include <boost/asio/error.hpp>
Ed Tanous1f978632023-02-28 18:16:39 -080024#include <boost/asio/io_context.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070025#include <boost/asio/random_access_file.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070026#include <boost/container/flat_map.hpp>
Patrick Williams0c42f402021-08-27 16:05:45 -050027#include <phosphor-logging/lg2.hpp>
Cheng C Yang58b2b532019-05-31 00:19:45 +080028#include <sdbusplus/asio/connection.hpp>
29#include <sdbusplus/asio/object_server.hpp>
James Feist38fb5982020-05-28 10:09:54 -070030
Ed Tanouseacbfdd2024-04-04 12:00:24 -070031#include <array>
32#include <chrono>
33#include <cstddef>
James Feist38fb5982020-05-28 10:09:54 -070034#include <memory>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070035#include <set>
Patrick Venture96e97db2019-10-31 13:44:38 -070036#include <stdexcept>
37#include <string>
38#include <utility>
Patrick Venture96e97db2019-10-31 13:44:38 -070039#include <vector>
Cheng C Yang58b2b532019-05-31 00:19:45 +080040
41PSUCombineEvent::PSUCombineEvent(
Yong Li3046a022020-04-03 13:01:02 +080042 sdbusplus::asio::object_server& objectServer,
43 std::shared_ptr<sdbusplus::asio::connection>& conn,
Ed Tanous1f978632023-02-28 18:16:39 -080044 boost::asio::io_context& io, const std::string& psuName,
George Liu5b3542e2023-10-31 17:27:12 +080045 const PowerState& powerState, EventPathList& eventPathList,
46 GroupEventPathList& groupEventPathList, const std::string& combineEventName,
Patrick Williams2aaf7172024-08-16 15:20:40 -040047 double pollRate) : objServer(objectServer)
Cheng C Yang58b2b532019-05-31 00:19:45 +080048{
Ed Tanous6cb732a2021-02-18 15:33:51 -080049 std::string psuNameEscaped = sensor_paths::escapePathForDbus(psuName);
Cheng C Yang58b2b532019-05-31 00:19:45 +080050 eventInterface = objServer.add_interface(
Ed Tanous6cb732a2021-02-18 15:33:51 -080051 "/xyz/openbmc_project/State/Decorator/" + psuNameEscaped + "_" +
Cheng C Yang58b2b532019-05-31 00:19:45 +080052 combineEventName,
53 "xyz.openbmc_project.State.Decorator.OperationalStatus");
James Feistb6c0b912019-07-09 12:21:44 -070054 eventInterface->register_property("functional", true);
Cheng C Yang58b2b532019-05-31 00:19:45 +080055
56 if (!eventInterface->initialize())
57 {
George Liu4155a5a2025-01-24 15:26:27 +080058 lg2::error("error initializing event interface");
Cheng C Yang58b2b532019-05-31 00:19:45 +080059 }
60
61 std::shared_ptr<std::set<std::string>> combineEvent =
62 std::make_shared<std::set<std::string>>();
Zev Weissb85145c2022-08-12 18:21:02 -070063 for (const auto& [eventName, paths] : eventPathList)
Cheng C Yang58b2b532019-05-31 00:19:45 +080064 {
Yong Li591b1e42019-12-19 17:46:31 +080065 std::shared_ptr<std::set<std::string>> assert =
66 std::make_shared<std::set<std::string>>();
Cheng C Yang202a1ff2020-01-09 09:34:22 +080067 std::shared_ptr<bool> state = std::make_shared<bool>(false);
Yong Li591b1e42019-12-19 17:46:31 +080068
Cheng C Yang58b2b532019-05-31 00:19:45 +080069 std::string eventPSUName = eventName + psuName;
Zev Weissb85145c2022-08-12 18:21:02 -070070 for (const auto& path : paths)
Cheng C Yang58b2b532019-05-31 00:19:45 +080071 {
Yong Libf8b1da2020-04-15 16:32:50 +080072 auto p = std::make_shared<PSUSubEvent>(
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +000073 eventInterface, path, conn, io, powerState, eventName,
74 eventName, assert, combineEvent, state, psuName, pollRate);
Yong Libf8b1da2020-04-15 16:32:50 +080075 p->setupRead();
76
77 events[eventPSUName].emplace_back(p);
Cheng C Yang58b2b532019-05-31 00:19:45 +080078 asserts.emplace_back(assert);
79 states.emplace_back(state);
80 }
81 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +080082
Zev Weissb85145c2022-08-12 18:21:02 -070083 for (const auto& [eventName, groupEvents] : groupEventPathList)
Cheng C Yang202a1ff2020-01-09 09:34:22 +080084 {
Zev Weissb85145c2022-08-12 18:21:02 -070085 for (const auto& [groupEventName, paths] : groupEvents)
Cheng C Yang202a1ff2020-01-09 09:34:22 +080086 {
87 std::shared_ptr<std::set<std::string>> assert =
88 std::make_shared<std::set<std::string>>();
89 std::shared_ptr<bool> state = std::make_shared<bool>(false);
90
Cheng C Yang202a1ff2020-01-09 09:34:22 +080091 std::string eventPSUName = groupEventName + psuName;
Zev Weissb85145c2022-08-12 18:21:02 -070092 for (const auto& path : paths)
Cheng C Yang202a1ff2020-01-09 09:34:22 +080093 {
Yong Libf8b1da2020-04-15 16:32:50 +080094 auto p = std::make_shared<PSUSubEvent>(
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +000095 eventInterface, path, conn, io, powerState, groupEventName,
Zev Weissb85145c2022-08-12 18:21:02 -070096 eventName, assert, combineEvent, state, psuName, pollRate);
Yong Libf8b1da2020-04-15 16:32:50 +080097 p->setupRead();
98 events[eventPSUName].emplace_back(p);
99
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800100 asserts.emplace_back(assert);
101 states.emplace_back(state);
102 }
103 }
104 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800105}
106
107PSUCombineEvent::~PSUCombineEvent()
108{
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800109 // Clear unique_ptr first
Zev Weissb85145c2022-08-12 18:21:02 -0700110 for (auto& [psuName, subEvents] : events)
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800111 {
Zev Weissb85145c2022-08-12 18:21:02 -0700112 for (auto& subEventPtr : subEvents)
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800113 {
114 subEventPtr.reset();
115 }
116 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800117 events.clear();
118 objServer.remove_interface(eventInterface);
119}
120
Cheng C Yang9b53a622019-08-27 22:13:58 +0800121static boost::container::flat_map<std::string,
122 std::pair<std::string, std::string>>
123 logID = {
124 {"PredictiveFailure",
125 {"OpenBMC.0.1.PowerSupplyFailurePredicted",
126 "OpenBMC.0.1.PowerSupplyPredictedFailureRecovered"}},
127 {"Failure",
128 {"OpenBMC.0.1.PowerSupplyFailed", "OpenBMC.0.1.PowerSupplyRecovered"}},
129 {"ACLost",
Cheng C Yangbb732ef2019-09-18 16:25:58 +0800130 {"OpenBMC.0.1.PowerSupplyPowerLost",
131 "OpenBMC.0.1.PowerSupplyPowerRestored"}},
Cheng C Yang9b53a622019-08-27 22:13:58 +0800132 {"FanFault",
133 {"OpenBMC.0.1.PowerSupplyFanFailed",
134 "OpenBMC.0.1.PowerSupplyFanRecovered"}},
jayaprakash Mutyalad12f23e2019-12-03 23:03:52 +0000135 {"ConfigureError",
136 {"OpenBMC.0.1.PowerSupplyConfigurationError",
137 "OpenBMC.0.1.PowerSupplyConfigurationErrorRecovered"}}};
Cheng C Yang5665db22019-07-12 00:57:30 +0800138
Cheng C Yang58b2b532019-05-31 00:19:45 +0800139PSUSubEvent::PSUSubEvent(
140 std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
Yong Li3046a022020-04-03 13:01:02 +0800141 const std::string& path, std::shared_ptr<sdbusplus::asio::connection>& conn,
Ed Tanous1f978632023-02-28 18:16:39 -0800142 boost::asio::io_context& io, const PowerState& powerState,
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000143 const std::string& groupEventName, const std::string& eventName,
Cheng C Yang58b2b532019-05-31 00:19:45 +0800144 std::shared_ptr<std::set<std::string>> asserts,
145 std::shared_ptr<std::set<std::string>> combineEvent,
Lei YU7170a232021-02-04 16:19:27 +0800146 std::shared_ptr<bool> state, const std::string& psuName, double pollRate) :
Patrick Williams2aaf7172024-08-16 15:20:40 -0400147 eventInterface(std::move(eventInterface)), asserts(std::move(asserts)),
148 combineEvent(std::move(combineEvent)), assertState(std::move(state)),
149 path(path), eventName(eventName), readState(powerState), waitTimer(io),
Ed Tanous16966b52021-09-15 15:06:59 -0700150
151 inputDev(io, path, boost::asio::random_access_file::read_only),
152 psuName(psuName), groupEventName(groupEventName), systemBus(conn)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800153{
Ed Tanous16966b52021-09-15 15:06:59 -0700154 buffer = std::make_shared<std::array<char, 128>>();
Lei YU7170a232021-02-04 16:19:27 +0800155 if (pollRate > 0.0)
156 {
157 eventPollMs = static_cast<unsigned int>(pollRate * 1000);
158 }
Ed Tanous99c44092022-01-14 09:59:09 -0800159
Cheng C Yang5665db22019-07-12 00:57:30 +0800160 auto found = logID.find(eventName);
161 if (found == logID.end())
162 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800163 assertMessage.clear();
164 deassertMessage.clear();
Cheng C Yang5665db22019-07-12 00:57:30 +0800165 }
166 else
167 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800168 assertMessage = found->second.first;
169 deassertMessage = found->second.second;
Cheng C Yang5665db22019-07-12 00:57:30 +0800170 }
171
172 auto fanPos = path.find("fan");
173 if (fanPos != std::string::npos)
174 {
175 fanName = path.substr(fanPos);
Ed Tanous8a57ec02020-10-09 12:46:52 -0700176 auto fanNamePos = fanName.find('_');
Cheng C Yang9b53a622019-08-27 22:13:58 +0800177 if (fanNamePos != std::string::npos)
178 {
179 fanName = fanName.substr(0, fanNamePos);
180 }
Cheng C Yang5665db22019-07-12 00:57:30 +0800181 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800182}
183
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000184PSUSubEvent::~PSUSubEvent()
185{
186 waitTimer.cancel();
187 inputDev.close();
188}
189
Ed Tanous201a1012024-04-03 18:07:28 -0700190void PSUSubEvent::setupRead()
Cheng C Yang58b2b532019-05-31 00:19:45 +0800191{
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000192 if (!readingStateGood(readState))
193 {
194 // Deassert the event
195 updateValue(0);
196 restartRead();
197 return;
198 }
Ed Tanous16966b52021-09-15 15:06:59 -0700199 if (!buffer)
200 {
George Liu4155a5a2025-01-24 15:26:27 +0800201 lg2::error("Buffer was invalid?");
Ed Tanous16966b52021-09-15 15:06:59 -0700202 return;
203 }
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000204
Yong Libf8b1da2020-04-15 16:32:50 +0800205 std::weak_ptr<PSUSubEvent> weakRef = weak_from_this();
Ed Tanous16966b52021-09-15 15:06:59 -0700206 inputDev.async_read_some_at(
207 0, boost::asio::buffer(buffer->data(), buffer->size() - 1),
208 [weakRef, buffer{buffer}](const boost::system::error_code& ec,
209 std::size_t bytesTransferred) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400210 std::shared_ptr<PSUSubEvent> self = weakRef.lock();
211 if (self)
212 {
213 self->handleResponse(ec, bytesTransferred);
214 }
215 });
Cheng C Yang58b2b532019-05-31 00:19:45 +0800216}
217
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000218void PSUSubEvent::restartRead()
Cheng C Yang58b2b532019-05-31 00:19:45 +0800219{
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000220 std::weak_ptr<PSUSubEvent> weakRef = weak_from_this();
Ed Tanous83db50c2023-03-01 10:20:24 -0800221 waitTimer.expires_after(std::chrono::milliseconds(eventPollMs));
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000222 waitTimer.async_wait([weakRef](const boost::system::error_code& ec) {
223 if (ec == boost::asio::error::operation_aborted)
224 {
225 return;
226 }
227 std::shared_ptr<PSUSubEvent> self = weakRef.lock();
228 if (self)
229 {
230 self->setupRead();
231 }
232 });
Cheng C Yang58b2b532019-05-31 00:19:45 +0800233}
234
Ed Tanous16966b52021-09-15 15:06:59 -0700235void PSUSubEvent::handleResponse(const boost::system::error_code& err,
236 size_t bytesTransferred)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800237{
Ed Tanous16966b52021-09-15 15:06:59 -0700238 if (err == boost::asio::error::operation_aborted)
239 {
240 return;
241 }
242
Yong Libf8b1da2020-04-15 16:32:50 +0800243 if ((err == boost::system::errc::bad_file_descriptor) ||
244 (err == boost::asio::error::misc_errors::not_found))
Cheng C Yang58b2b532019-05-31 00:19:45 +0800245 {
246 return;
247 }
Ed Tanous16966b52021-09-15 15:06:59 -0700248 if (!buffer)
249 {
George Liu4155a5a2025-01-24 15:26:27 +0800250 lg2::error("Buffer was invalid?");
Ed Tanous16966b52021-09-15 15:06:59 -0700251 return;
252 }
253 // null terminate the string so we don't walk off the end
254 std::array<char, 128>& bufferRef = *buffer;
255 bufferRef[bytesTransferred] = '\0';
256
Cheng C Yang58b2b532019-05-31 00:19:45 +0800257 if (!err)
258 {
Cheng C Yang58b2b532019-05-31 00:19:45 +0800259 try
260 {
Ed Tanous16966b52021-09-15 15:06:59 -0700261 int nvalue = std::stoi(bufferRef.data());
Josh Lehan833661a2020-03-04 17:35:41 -0800262 updateValue(nvalue);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800263 errCount = 0;
264 }
265 catch (const std::invalid_argument&)
266 {
267 errCount++;
268 }
269 }
270 else
271 {
272 errCount++;
273 }
274 if (errCount >= warnAfterErrorCount)
275 {
276 if (errCount == warnAfterErrorCount)
277 {
George Liu4155a5a2025-01-24 15:26:27 +0800278 lg2::error("Failure to read event at '{PATH}'", "PATH", path);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800279 }
280 updateValue(0);
281 errCount++;
282 }
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000283 restartRead();
Cheng C Yang58b2b532019-05-31 00:19:45 +0800284}
285
286// Any of the sub events of one event is asserted, then the event will be
287// asserted. Only if none of the sub events are asserted, the event will be
288// deasserted.
289void PSUSubEvent::updateValue(const int& newValue)
290{
Josh Lehan833661a2020-03-04 17:35:41 -0800291 // Take no action if value already equal
292 // Same semantics as Sensor::updateValue(const double&)
293 if (newValue == value)
294 {
295 return;
296 }
297
Cheng C Yang58b2b532019-05-31 00:19:45 +0800298 if (newValue == 0)
299 {
Yong Li591b1e42019-12-19 17:46:31 +0800300 // log deassert only after all asserts are gone
Cheng C Yang58b2b532019-05-31 00:19:45 +0800301 if (!(*asserts).empty())
302 {
Yong Li591b1e42019-12-19 17:46:31 +0800303 auto found = (*asserts).find(path);
304 if (found == (*asserts).end())
305 {
306 return;
307 }
308 (*asserts).erase(path);
309
Cheng C Yang58b2b532019-05-31 00:19:45 +0800310 return;
311 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700312 if (*assertState)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800313 {
314 *assertState = false;
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800315 auto foundCombine = (*combineEvent).find(groupEventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800316 if (foundCombine == (*combineEvent).end())
Cheng C Yang58b2b532019-05-31 00:19:45 +0800317 {
318 return;
319 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800320 (*combineEvent).erase(groupEventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800321 if (!deassertMessage.empty())
322 {
323 // Fan Failed has two args
Cheng C Yang9b53a622019-08-27 22:13:58 +0800324 if (deassertMessage == "OpenBMC.0.1.PowerSupplyFanRecovered")
325 {
George Liu4155a5a2025-01-24 15:26:27 +0800326 lg2::info("'{EVENT}' deassert", "EVENT", eventName,
Patrick Williams0c42f402021-08-27 16:05:45 -0500327 "REDFISH_MESSAGE_ID", deassertMessage,
328 "REDFISH_MESSAGE_ARGS",
329 (psuName + ',' + fanName));
Cheng C Yang9b53a622019-08-27 22:13:58 +0800330 }
331 else
332 {
George Liu4155a5a2025-01-24 15:26:27 +0800333 lg2::info("'{EVENT}' deassert", "EVENT", eventName,
Patrick Williams0c42f402021-08-27 16:05:45 -0500334 "REDFISH_MESSAGE_ID", deassertMessage,
335 "REDFISH_MESSAGE_ARGS", psuName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800336 }
337 }
338
Cheng C Yang58b2b532019-05-31 00:19:45 +0800339 if ((*combineEvent).empty())
340 {
341 eventInterface->set_property("functional", true);
342 }
343 }
344 }
345 else
346 {
George Liu4155a5a2025-01-24 15:26:27 +0800347 lg2::error("PSUSubEvent asserted by '{PATH}'", "PATH", path);
Paul Fertser34533542021-07-20 08:29:09 +0000348
Ed Tanous2049bd22022-07-09 07:20:26 -0700349 if ((!*assertState) && ((*asserts).empty()))
Cheng C Yang58b2b532019-05-31 00:19:45 +0800350 {
351 *assertState = true;
Cheng C Yang9b53a622019-08-27 22:13:58 +0800352 if (!assertMessage.empty())
Cheng C Yang5665db22019-07-12 00:57:30 +0800353 {
354 // Fan Failed has two args
Cheng C Yang9b53a622019-08-27 22:13:58 +0800355 if (assertMessage == "OpenBMC.0.1.PowerSupplyFanFailed")
Cheng C Yang5665db22019-07-12 00:57:30 +0800356 {
George Liu4155a5a2025-01-24 15:26:27 +0800357 lg2::warning("'{EVENT}' assert", "EVENT", eventName,
Patrick Williams0c42f402021-08-27 16:05:45 -0500358 "REDFISH_MESSAGE_ID", assertMessage,
359 "REDFISH_MESSAGE_ARGS",
360 (psuName + ',' + fanName));
Cheng C Yang5665db22019-07-12 00:57:30 +0800361 }
362 else
363 {
George Liu4155a5a2025-01-24 15:26:27 +0800364 lg2::warning("'{EVENT}' assert", "EVENT", eventName,
Patrick Williams0c42f402021-08-27 16:05:45 -0500365 "REDFISH_MESSAGE_ID", assertMessage,
366 "REDFISH_MESSAGE_ARGS", psuName);
Cheng C Yang5665db22019-07-12 00:57:30 +0800367 }
368 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800369 if ((*combineEvent).empty())
370 {
371 eventInterface->set_property("functional", false);
372 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800373 (*combineEvent).emplace(groupEventName);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800374 }
Yong Li591b1e42019-12-19 17:46:31 +0800375 (*asserts).emplace(path);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800376 }
377 value = newValue;
378}