blob: 1201a19cafa44e8f55018d887c320d8cad361ccf [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"
20
Ed Tanous1f978632023-02-28 18:16:39 -080021#include <boost/asio/io_context.hpp>
James Feist8086aba2020-08-25 16:00:59 -070022#include <boost/asio/read_until.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070023#include <boost/container/flat_map.hpp>
Patrick Williams0c42f402021-08-27 16:05:45 -050024#include <phosphor-logging/lg2.hpp>
Cheng C Yang58b2b532019-05-31 00:19:45 +080025#include <sdbusplus/asio/connection.hpp>
26#include <sdbusplus/asio/object_server.hpp>
James Feist38fb5982020-05-28 10:09:54 -070027
28#include <iostream>
29#include <memory>
Patrick Venture96e97db2019-10-31 13:44:38 -070030#include <stdexcept>
31#include <string>
32#include <utility>
33#include <variant>
34#include <vector>
Cheng C Yang58b2b532019-05-31 00:19:45 +080035
36PSUCombineEvent::PSUCombineEvent(
Yong Li3046a022020-04-03 13:01:02 +080037 sdbusplus::asio::object_server& objectServer,
38 std::shared_ptr<sdbusplus::asio::connection>& conn,
Ed Tanous1f978632023-02-28 18:16:39 -080039 boost::asio::io_context& io, const std::string& psuName,
George Liu5b3542e2023-10-31 17:27:12 +080040 const PowerState& powerState, EventPathList& eventPathList,
41 GroupEventPathList& groupEventPathList, const std::string& combineEventName,
42 double pollRate) :
Cheng C Yang58b2b532019-05-31 00:19:45 +080043 objServer(objectServer)
44{
Ed Tanous6cb732a2021-02-18 15:33:51 -080045 std::string psuNameEscaped = sensor_paths::escapePathForDbus(psuName);
Cheng C Yang58b2b532019-05-31 00:19:45 +080046 eventInterface = objServer.add_interface(
Ed Tanous6cb732a2021-02-18 15:33:51 -080047 "/xyz/openbmc_project/State/Decorator/" + psuNameEscaped + "_" +
Cheng C Yang58b2b532019-05-31 00:19:45 +080048 combineEventName,
49 "xyz.openbmc_project.State.Decorator.OperationalStatus");
James Feistb6c0b912019-07-09 12:21:44 -070050 eventInterface->register_property("functional", true);
Cheng C Yang58b2b532019-05-31 00:19:45 +080051
52 if (!eventInterface->initialize())
53 {
54 std::cerr << "error initializing event interface\n";
55 }
56
57 std::shared_ptr<std::set<std::string>> combineEvent =
58 std::make_shared<std::set<std::string>>();
Zev Weissb85145c2022-08-12 18:21:02 -070059 for (const auto& [eventName, paths] : eventPathList)
Cheng C Yang58b2b532019-05-31 00:19:45 +080060 {
Yong Li591b1e42019-12-19 17:46:31 +080061 std::shared_ptr<std::set<std::string>> assert =
62 std::make_shared<std::set<std::string>>();
Cheng C Yang202a1ff2020-01-09 09:34:22 +080063 std::shared_ptr<bool> state = std::make_shared<bool>(false);
Yong Li591b1e42019-12-19 17:46:31 +080064
Cheng C Yang58b2b532019-05-31 00:19:45 +080065 std::string eventPSUName = eventName + psuName;
Zev Weissb85145c2022-08-12 18:21:02 -070066 for (const auto& path : paths)
Cheng C Yang58b2b532019-05-31 00:19:45 +080067 {
Yong Libf8b1da2020-04-15 16:32:50 +080068 auto p = std::make_shared<PSUSubEvent>(
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +000069 eventInterface, path, conn, io, powerState, eventName,
70 eventName, assert, combineEvent, state, psuName, pollRate);
Yong Libf8b1da2020-04-15 16:32:50 +080071 p->setupRead();
72
73 events[eventPSUName].emplace_back(p);
Cheng C Yang58b2b532019-05-31 00:19:45 +080074 asserts.emplace_back(assert);
75 states.emplace_back(state);
76 }
77 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +080078
Zev Weissb85145c2022-08-12 18:21:02 -070079 for (const auto& [eventName, groupEvents] : groupEventPathList)
Cheng C Yang202a1ff2020-01-09 09:34:22 +080080 {
Zev Weissb85145c2022-08-12 18:21:02 -070081 for (const auto& [groupEventName, paths] : groupEvents)
Cheng C Yang202a1ff2020-01-09 09:34:22 +080082 {
83 std::shared_ptr<std::set<std::string>> assert =
84 std::make_shared<std::set<std::string>>();
85 std::shared_ptr<bool> state = std::make_shared<bool>(false);
86
Cheng C Yang202a1ff2020-01-09 09:34:22 +080087 std::string eventPSUName = groupEventName + psuName;
Zev Weissb85145c2022-08-12 18:21:02 -070088 for (const auto& path : paths)
Cheng C Yang202a1ff2020-01-09 09:34:22 +080089 {
Yong Libf8b1da2020-04-15 16:32:50 +080090 auto p = std::make_shared<PSUSubEvent>(
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +000091 eventInterface, path, conn, io, powerState, groupEventName,
Zev Weissb85145c2022-08-12 18:21:02 -070092 eventName, assert, combineEvent, state, psuName, pollRate);
Yong Libf8b1da2020-04-15 16:32:50 +080093 p->setupRead();
94 events[eventPSUName].emplace_back(p);
95
Cheng C Yang202a1ff2020-01-09 09:34:22 +080096 asserts.emplace_back(assert);
97 states.emplace_back(state);
98 }
99 }
100 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800101}
102
103PSUCombineEvent::~PSUCombineEvent()
104{
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800105 // Clear unique_ptr first
Zev Weissb85145c2022-08-12 18:21:02 -0700106 for (auto& [psuName, subEvents] : events)
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800107 {
Zev Weissb85145c2022-08-12 18:21:02 -0700108 for (auto& subEventPtr : subEvents)
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800109 {
110 subEventPtr.reset();
111 }
112 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800113 events.clear();
114 objServer.remove_interface(eventInterface);
115}
116
Cheng C Yang9b53a622019-08-27 22:13:58 +0800117static boost::container::flat_map<std::string,
118 std::pair<std::string, std::string>>
119 logID = {
120 {"PredictiveFailure",
121 {"OpenBMC.0.1.PowerSupplyFailurePredicted",
122 "OpenBMC.0.1.PowerSupplyPredictedFailureRecovered"}},
123 {"Failure",
124 {"OpenBMC.0.1.PowerSupplyFailed", "OpenBMC.0.1.PowerSupplyRecovered"}},
125 {"ACLost",
Cheng C Yangbb732ef2019-09-18 16:25:58 +0800126 {"OpenBMC.0.1.PowerSupplyPowerLost",
127 "OpenBMC.0.1.PowerSupplyPowerRestored"}},
Cheng C Yang9b53a622019-08-27 22:13:58 +0800128 {"FanFault",
129 {"OpenBMC.0.1.PowerSupplyFanFailed",
130 "OpenBMC.0.1.PowerSupplyFanRecovered"}},
jayaprakash Mutyalad12f23e2019-12-03 23:03:52 +0000131 {"ConfigureError",
132 {"OpenBMC.0.1.PowerSupplyConfigurationError",
133 "OpenBMC.0.1.PowerSupplyConfigurationErrorRecovered"}}};
Cheng C Yang5665db22019-07-12 00:57:30 +0800134
Cheng C Yang58b2b532019-05-31 00:19:45 +0800135PSUSubEvent::PSUSubEvent(
136 std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
Yong Li3046a022020-04-03 13:01:02 +0800137 const std::string& path, std::shared_ptr<sdbusplus::asio::connection>& conn,
Ed Tanous1f978632023-02-28 18:16:39 -0800138 boost::asio::io_context& io, const PowerState& powerState,
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000139 const std::string& groupEventName, const std::string& eventName,
Cheng C Yang58b2b532019-05-31 00:19:45 +0800140 std::shared_ptr<std::set<std::string>> asserts,
141 std::shared_ptr<std::set<std::string>> combineEvent,
Lei YU7170a232021-02-04 16:19:27 +0800142 std::shared_ptr<bool> state, const std::string& psuName, double pollRate) :
Ed Tanous2049bd22022-07-09 07:20:26 -0700143 eventInterface(std::move(eventInterface)),
144 asserts(std::move(asserts)), combineEvent(std::move(combineEvent)),
145 assertState(std::move(state)), path(path), eventName(eventName),
Ed Tanous16966b52021-09-15 15:06:59 -0700146 readState(powerState), waitTimer(io),
147
148 inputDev(io, path, boost::asio::random_access_file::read_only),
149 psuName(psuName), groupEventName(groupEventName), systemBus(conn)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800150{
Ed Tanous16966b52021-09-15 15:06:59 -0700151 buffer = std::make_shared<std::array<char, 128>>();
Lei YU7170a232021-02-04 16:19:27 +0800152 if (pollRate > 0.0)
153 {
154 eventPollMs = static_cast<unsigned int>(pollRate * 1000);
155 }
Ed Tanous99c44092022-01-14 09:59:09 -0800156
Cheng C Yang5665db22019-07-12 00:57:30 +0800157 auto found = logID.find(eventName);
158 if (found == logID.end())
159 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800160 assertMessage.clear();
161 deassertMessage.clear();
Cheng C Yang5665db22019-07-12 00:57:30 +0800162 }
163 else
164 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800165 assertMessage = found->second.first;
166 deassertMessage = found->second.second;
Cheng C Yang5665db22019-07-12 00:57:30 +0800167 }
168
169 auto fanPos = path.find("fan");
170 if (fanPos != std::string::npos)
171 {
172 fanName = path.substr(fanPos);
Ed Tanous8a57ec02020-10-09 12:46:52 -0700173 auto fanNamePos = fanName.find('_');
Cheng C Yang9b53a622019-08-27 22:13:58 +0800174 if (fanNamePos != std::string::npos)
175 {
176 fanName = fanName.substr(0, fanNamePos);
177 }
Cheng C Yang5665db22019-07-12 00:57:30 +0800178 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800179}
180
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000181PSUSubEvent::~PSUSubEvent()
182{
183 waitTimer.cancel();
184 inputDev.close();
185}
186
Ed Tanous201a1012024-04-03 18:07:28 -0700187void PSUSubEvent::setupRead()
Cheng C Yang58b2b532019-05-31 00:19:45 +0800188{
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000189 if (!readingStateGood(readState))
190 {
191 // Deassert the event
192 updateValue(0);
193 restartRead();
194 return;
195 }
Ed Tanous16966b52021-09-15 15:06:59 -0700196 if (!buffer)
197 {
198 std::cerr << "Buffer was invalid?";
199 return;
200 }
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000201
Yong Libf8b1da2020-04-15 16:32:50 +0800202 std::weak_ptr<PSUSubEvent> weakRef = weak_from_this();
Ed Tanous16966b52021-09-15 15:06:59 -0700203 inputDev.async_read_some_at(
204 0, boost::asio::buffer(buffer->data(), buffer->size() - 1),
205 [weakRef, buffer{buffer}](const boost::system::error_code& ec,
206 std::size_t bytesTransferred) {
Ed Tanousbb679322022-05-16 16:10:00 -0700207 std::shared_ptr<PSUSubEvent> self = weakRef.lock();
208 if (self)
209 {
Ed Tanous16966b52021-09-15 15:06:59 -0700210 self->handleResponse(ec, bytesTransferred);
Ed Tanousbb679322022-05-16 16:10:00 -0700211 }
Patrick Williams597e8422023-10-20 11:19:01 -0500212 });
Cheng C Yang58b2b532019-05-31 00:19:45 +0800213}
214
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000215void PSUSubEvent::restartRead()
Cheng C Yang58b2b532019-05-31 00:19:45 +0800216{
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000217 std::weak_ptr<PSUSubEvent> weakRef = weak_from_this();
Ed Tanous83db50c2023-03-01 10:20:24 -0800218 waitTimer.expires_after(std::chrono::milliseconds(eventPollMs));
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000219 waitTimer.async_wait([weakRef](const boost::system::error_code& ec) {
220 if (ec == boost::asio::error::operation_aborted)
221 {
222 return;
223 }
224 std::shared_ptr<PSUSubEvent> self = weakRef.lock();
225 if (self)
226 {
227 self->setupRead();
228 }
229 });
Cheng C Yang58b2b532019-05-31 00:19:45 +0800230}
231
Ed Tanous16966b52021-09-15 15:06:59 -0700232void PSUSubEvent::handleResponse(const boost::system::error_code& err,
233 size_t bytesTransferred)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800234{
Ed Tanous16966b52021-09-15 15:06:59 -0700235 if (err == boost::asio::error::operation_aborted)
236 {
237 return;
238 }
239
Yong Libf8b1da2020-04-15 16:32:50 +0800240 if ((err == boost::system::errc::bad_file_descriptor) ||
241 (err == boost::asio::error::misc_errors::not_found))
Cheng C Yang58b2b532019-05-31 00:19:45 +0800242 {
243 return;
244 }
Ed Tanous16966b52021-09-15 15:06:59 -0700245 if (!buffer)
246 {
247 std::cerr << "Buffer was invalid?";
248 return;
249 }
250 // null terminate the string so we don't walk off the end
251 std::array<char, 128>& bufferRef = *buffer;
252 bufferRef[bytesTransferred] = '\0';
253
Cheng C Yang58b2b532019-05-31 00:19:45 +0800254 if (!err)
255 {
Cheng C Yang58b2b532019-05-31 00:19:45 +0800256 try
257 {
Ed Tanous16966b52021-09-15 15:06:59 -0700258 int nvalue = std::stoi(bufferRef.data());
Josh Lehan833661a2020-03-04 17:35:41 -0800259 updateValue(nvalue);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800260 errCount = 0;
261 }
262 catch (const std::invalid_argument&)
263 {
264 errCount++;
265 }
266 }
267 else
268 {
269 errCount++;
270 }
271 if (errCount >= warnAfterErrorCount)
272 {
273 if (errCount == warnAfterErrorCount)
274 {
275 std::cerr << "Failure to read event at " << path << "\n";
276 }
277 updateValue(0);
278 errCount++;
279 }
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000280 restartRead();
Cheng C Yang58b2b532019-05-31 00:19:45 +0800281}
282
283// Any of the sub events of one event is asserted, then the event will be
284// asserted. Only if none of the sub events are asserted, the event will be
285// deasserted.
286void PSUSubEvent::updateValue(const int& newValue)
287{
Josh Lehan833661a2020-03-04 17:35:41 -0800288 // Take no action if value already equal
289 // Same semantics as Sensor::updateValue(const double&)
290 if (newValue == value)
291 {
292 return;
293 }
294
Cheng C Yang58b2b532019-05-31 00:19:45 +0800295 if (newValue == 0)
296 {
Yong Li591b1e42019-12-19 17:46:31 +0800297 // log deassert only after all asserts are gone
Cheng C Yang58b2b532019-05-31 00:19:45 +0800298 if (!(*asserts).empty())
299 {
Yong Li591b1e42019-12-19 17:46:31 +0800300 auto found = (*asserts).find(path);
301 if (found == (*asserts).end())
302 {
303 return;
304 }
305 (*asserts).erase(path);
306
Cheng C Yang58b2b532019-05-31 00:19:45 +0800307 return;
308 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700309 if (*assertState)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800310 {
311 *assertState = false;
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800312 auto foundCombine = (*combineEvent).find(groupEventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800313 if (foundCombine == (*combineEvent).end())
Cheng C Yang58b2b532019-05-31 00:19:45 +0800314 {
315 return;
316 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800317 (*combineEvent).erase(groupEventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800318 if (!deassertMessage.empty())
319 {
320 // Fan Failed has two args
Cheng C Yang9b53a622019-08-27 22:13:58 +0800321 if (deassertMessage == "OpenBMC.0.1.PowerSupplyFanRecovered")
322 {
Patrick Williams0c42f402021-08-27 16:05:45 -0500323 lg2::info("{EVENT} deassert", "EVENT", eventName,
324 "REDFISH_MESSAGE_ID", deassertMessage,
325 "REDFISH_MESSAGE_ARGS",
326 (psuName + ',' + fanName));
Cheng C Yang9b53a622019-08-27 22:13:58 +0800327 }
328 else
329 {
Patrick Williams0c42f402021-08-27 16:05:45 -0500330 lg2::info("{EVENT} deassert", "EVENT", eventName,
331 "REDFISH_MESSAGE_ID", deassertMessage,
332 "REDFISH_MESSAGE_ARGS", psuName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800333 }
334 }
335
Cheng C Yang58b2b532019-05-31 00:19:45 +0800336 if ((*combineEvent).empty())
337 {
338 eventInterface->set_property("functional", true);
339 }
340 }
341 }
342 else
343 {
Paul Fertser34533542021-07-20 08:29:09 +0000344 std::cerr << "PSUSubEvent asserted by " << path << "\n";
345
Ed Tanous2049bd22022-07-09 07:20:26 -0700346 if ((!*assertState) && ((*asserts).empty()))
Cheng C Yang58b2b532019-05-31 00:19:45 +0800347 {
348 *assertState = true;
Cheng C Yang9b53a622019-08-27 22:13:58 +0800349 if (!assertMessage.empty())
Cheng C Yang5665db22019-07-12 00:57:30 +0800350 {
351 // Fan Failed has two args
Cheng C Yang9b53a622019-08-27 22:13:58 +0800352 if (assertMessage == "OpenBMC.0.1.PowerSupplyFanFailed")
Cheng C Yang5665db22019-07-12 00:57:30 +0800353 {
Patrick Williams0c42f402021-08-27 16:05:45 -0500354 lg2::warning("{EVENT} assert", "EVENT", eventName,
355 "REDFISH_MESSAGE_ID", assertMessage,
356 "REDFISH_MESSAGE_ARGS",
357 (psuName + ',' + fanName));
Cheng C Yang5665db22019-07-12 00:57:30 +0800358 }
359 else
360 {
Patrick Williams0c42f402021-08-27 16:05:45 -0500361 lg2::warning("{EVENT} assert", "EVENT", eventName,
362 "REDFISH_MESSAGE_ID", assertMessage,
363 "REDFISH_MESSAGE_ARGS", psuName);
Cheng C Yang5665db22019-07-12 00:57:30 +0800364 }
365 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800366 if ((*combineEvent).empty())
367 {
368 eventInterface->set_property("functional", false);
369 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800370 (*combineEvent).emplace(groupEventName);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800371 }
Yong Li591b1e42019-12-19 17:46:31 +0800372 (*asserts).emplace(path);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800373 }
374 value = newValue;
375}