blob: c5ad0febed80875040cf0c347302b40c6e729fa5 [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,
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +000040 const PowerState& powerState,
Cheng C Yang58b2b532019-05-31 00:19:45 +080041 boost::container::flat_map<std::string, std::vector<std::string>>&
42 eventPathList,
Cheng C Yang202a1ff2020-01-09 09:34:22 +080043 boost::container::flat_map<
44 std::string,
45 boost::container::flat_map<std::string, std::vector<std::string>>>&
46 groupEventPathList,
Lei YU7170a232021-02-04 16:19:27 +080047 const std::string& combineEventName, double pollRate) :
Cheng C Yang58b2b532019-05-31 00:19:45 +080048 objServer(objectServer)
49{
Ed Tanous6cb732a2021-02-18 15:33:51 -080050 std::string psuNameEscaped = sensor_paths::escapePathForDbus(psuName);
Cheng C Yang58b2b532019-05-31 00:19:45 +080051 eventInterface = objServer.add_interface(
Ed Tanous6cb732a2021-02-18 15:33:51 -080052 "/xyz/openbmc_project/State/Decorator/" + psuNameEscaped + "_" +
Cheng C Yang58b2b532019-05-31 00:19:45 +080053 combineEventName,
54 "xyz.openbmc_project.State.Decorator.OperationalStatus");
James Feistb6c0b912019-07-09 12:21:44 -070055 eventInterface->register_property("functional", true);
Cheng C Yang58b2b532019-05-31 00:19:45 +080056
57 if (!eventInterface->initialize())
58 {
59 std::cerr << "error initializing event interface\n";
60 }
61
62 std::shared_ptr<std::set<std::string>> combineEvent =
63 std::make_shared<std::set<std::string>>();
Zev Weissb85145c2022-08-12 18:21:02 -070064 for (const auto& [eventName, paths] : eventPathList)
Cheng C Yang58b2b532019-05-31 00:19:45 +080065 {
Yong Li591b1e42019-12-19 17:46:31 +080066 std::shared_ptr<std::set<std::string>> assert =
67 std::make_shared<std::set<std::string>>();
Cheng C Yang202a1ff2020-01-09 09:34:22 +080068 std::shared_ptr<bool> state = std::make_shared<bool>(false);
Yong Li591b1e42019-12-19 17:46:31 +080069
Cheng C Yang58b2b532019-05-31 00:19:45 +080070 std::string eventPSUName = eventName + psuName;
Zev Weissb85145c2022-08-12 18:21:02 -070071 for (const auto& path : paths)
Cheng C Yang58b2b532019-05-31 00:19:45 +080072 {
Yong Libf8b1da2020-04-15 16:32:50 +080073 auto p = std::make_shared<PSUSubEvent>(
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +000074 eventInterface, path, conn, io, powerState, eventName,
75 eventName, assert, combineEvent, state, psuName, pollRate);
Yong Libf8b1da2020-04-15 16:32:50 +080076 p->setupRead();
77
78 events[eventPSUName].emplace_back(p);
Cheng C Yang58b2b532019-05-31 00:19:45 +080079 asserts.emplace_back(assert);
80 states.emplace_back(state);
81 }
82 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +080083
Zev Weissb85145c2022-08-12 18:21:02 -070084 for (const auto& [eventName, groupEvents] : groupEventPathList)
Cheng C Yang202a1ff2020-01-09 09:34:22 +080085 {
Zev Weissb85145c2022-08-12 18:21:02 -070086 for (const auto& [groupEventName, paths] : groupEvents)
Cheng C Yang202a1ff2020-01-09 09:34:22 +080087 {
88 std::shared_ptr<std::set<std::string>> assert =
89 std::make_shared<std::set<std::string>>();
90 std::shared_ptr<bool> state = std::make_shared<bool>(false);
91
Cheng C Yang202a1ff2020-01-09 09:34:22 +080092 std::string eventPSUName = groupEventName + psuName;
Zev Weissb85145c2022-08-12 18:21:02 -070093 for (const auto& path : paths)
Cheng C Yang202a1ff2020-01-09 09:34:22 +080094 {
Yong Libf8b1da2020-04-15 16:32:50 +080095 auto p = std::make_shared<PSUSubEvent>(
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +000096 eventInterface, path, conn, io, powerState, groupEventName,
Zev Weissb85145c2022-08-12 18:21:02 -070097 eventName, assert, combineEvent, state, psuName, pollRate);
Yong Libf8b1da2020-04-15 16:32:50 +080098 p->setupRead();
99 events[eventPSUName].emplace_back(p);
100
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800101 asserts.emplace_back(assert);
102 states.emplace_back(state);
103 }
104 }
105 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800106}
107
108PSUCombineEvent::~PSUCombineEvent()
109{
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800110 // Clear unique_ptr first
Zev Weissb85145c2022-08-12 18:21:02 -0700111 for (auto& [psuName, subEvents] : events)
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800112 {
Zev Weissb85145c2022-08-12 18:21:02 -0700113 for (auto& subEventPtr : subEvents)
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800114 {
115 subEventPtr.reset();
116 }
117 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800118 events.clear();
119 objServer.remove_interface(eventInterface);
120}
121
Cheng C Yang9b53a622019-08-27 22:13:58 +0800122static boost::container::flat_map<std::string,
123 std::pair<std::string, std::string>>
124 logID = {
125 {"PredictiveFailure",
126 {"OpenBMC.0.1.PowerSupplyFailurePredicted",
127 "OpenBMC.0.1.PowerSupplyPredictedFailureRecovered"}},
128 {"Failure",
129 {"OpenBMC.0.1.PowerSupplyFailed", "OpenBMC.0.1.PowerSupplyRecovered"}},
130 {"ACLost",
Cheng C Yangbb732ef2019-09-18 16:25:58 +0800131 {"OpenBMC.0.1.PowerSupplyPowerLost",
132 "OpenBMC.0.1.PowerSupplyPowerRestored"}},
Cheng C Yang9b53a622019-08-27 22:13:58 +0800133 {"FanFault",
134 {"OpenBMC.0.1.PowerSupplyFanFailed",
135 "OpenBMC.0.1.PowerSupplyFanRecovered"}},
jayaprakash Mutyalad12f23e2019-12-03 23:03:52 +0000136 {"ConfigureError",
137 {"OpenBMC.0.1.PowerSupplyConfigurationError",
138 "OpenBMC.0.1.PowerSupplyConfigurationErrorRecovered"}}};
Cheng C Yang5665db22019-07-12 00:57:30 +0800139
Cheng C Yang58b2b532019-05-31 00:19:45 +0800140PSUSubEvent::PSUSubEvent(
141 std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
Yong Li3046a022020-04-03 13:01:02 +0800142 const std::string& path, std::shared_ptr<sdbusplus::asio::connection>& conn,
Ed Tanous1f978632023-02-28 18:16:39 -0800143 boost::asio::io_context& io, const PowerState& powerState,
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000144 const std::string& groupEventName, const std::string& eventName,
Cheng C Yang58b2b532019-05-31 00:19:45 +0800145 std::shared_ptr<std::set<std::string>> asserts,
146 std::shared_ptr<std::set<std::string>> combineEvent,
Lei YU7170a232021-02-04 16:19:27 +0800147 std::shared_ptr<bool> state, const std::string& psuName, double pollRate) :
Ed Tanous2049bd22022-07-09 07:20:26 -0700148 eventInterface(std::move(eventInterface)),
149 asserts(std::move(asserts)), combineEvent(std::move(combineEvent)),
150 assertState(std::move(state)), path(path), eventName(eventName),
Ed Tanous16966b52021-09-15 15:06:59 -0700151 readState(powerState), waitTimer(io),
152
153 inputDev(io, path, boost::asio::random_access_file::read_only),
154 psuName(psuName), groupEventName(groupEventName), systemBus(conn)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800155{
Ed Tanous16966b52021-09-15 15:06:59 -0700156 buffer = std::make_shared<std::array<char, 128>>();
Lei YU7170a232021-02-04 16:19:27 +0800157 if (pollRate > 0.0)
158 {
159 eventPollMs = static_cast<unsigned int>(pollRate * 1000);
160 }
Ed Tanous99c44092022-01-14 09:59:09 -0800161
Cheng C Yang5665db22019-07-12 00:57:30 +0800162 auto found = logID.find(eventName);
163 if (found == logID.end())
164 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800165 assertMessage.clear();
166 deassertMessage.clear();
Cheng C Yang5665db22019-07-12 00:57:30 +0800167 }
168 else
169 {
Cheng C Yang9b53a622019-08-27 22:13:58 +0800170 assertMessage = found->second.first;
171 deassertMessage = found->second.second;
Cheng C Yang5665db22019-07-12 00:57:30 +0800172 }
173
174 auto fanPos = path.find("fan");
175 if (fanPos != std::string::npos)
176 {
177 fanName = path.substr(fanPos);
Ed Tanous8a57ec02020-10-09 12:46:52 -0700178 auto fanNamePos = fanName.find('_');
Cheng C Yang9b53a622019-08-27 22:13:58 +0800179 if (fanNamePos != std::string::npos)
180 {
181 fanName = fanName.substr(0, fanNamePos);
182 }
Cheng C Yang5665db22019-07-12 00:57:30 +0800183 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800184}
185
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000186PSUSubEvent::~PSUSubEvent()
187{
188 waitTimer.cancel();
189 inputDev.close();
190}
191
Cheng C Yang58b2b532019-05-31 00:19:45 +0800192void PSUSubEvent::setupRead(void)
193{
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000194 if (!readingStateGood(readState))
195 {
196 // Deassert the event
197 updateValue(0);
198 restartRead();
199 return;
200 }
Ed Tanous16966b52021-09-15 15:06:59 -0700201 if (!buffer)
202 {
203 std::cerr << "Buffer was invalid?";
204 return;
205 }
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000206
Yong Libf8b1da2020-04-15 16:32:50 +0800207 std::weak_ptr<PSUSubEvent> weakRef = weak_from_this();
Ed Tanous16966b52021-09-15 15:06:59 -0700208 inputDev.async_read_some_at(
209 0, boost::asio::buffer(buffer->data(), buffer->size() - 1),
210 [weakRef, buffer{buffer}](const boost::system::error_code& ec,
211 std::size_t bytesTransferred) {
Ed Tanousbb679322022-05-16 16:10:00 -0700212 std::shared_ptr<PSUSubEvent> self = weakRef.lock();
213 if (self)
214 {
Ed Tanous16966b52021-09-15 15:06:59 -0700215 self->handleResponse(ec, bytesTransferred);
Ed Tanousbb679322022-05-16 16:10:00 -0700216 }
Patrick Williams597e8422023-10-20 11:19:01 -0500217 });
Cheng C Yang58b2b532019-05-31 00:19:45 +0800218}
219
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000220void PSUSubEvent::restartRead()
Cheng C Yang58b2b532019-05-31 00:19:45 +0800221{
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000222 std::weak_ptr<PSUSubEvent> weakRef = weak_from_this();
Ed Tanous83db50c2023-03-01 10:20:24 -0800223 waitTimer.expires_after(std::chrono::milliseconds(eventPollMs));
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000224 waitTimer.async_wait([weakRef](const boost::system::error_code& ec) {
225 if (ec == boost::asio::error::operation_aborted)
226 {
227 return;
228 }
229 std::shared_ptr<PSUSubEvent> self = weakRef.lock();
230 if (self)
231 {
232 self->setupRead();
233 }
234 });
Cheng C Yang58b2b532019-05-31 00:19:45 +0800235}
236
Ed Tanous16966b52021-09-15 15:06:59 -0700237void PSUSubEvent::handleResponse(const boost::system::error_code& err,
238 size_t bytesTransferred)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800239{
Ed Tanous16966b52021-09-15 15:06:59 -0700240 if (err == boost::asio::error::operation_aborted)
241 {
242 return;
243 }
244
Yong Libf8b1da2020-04-15 16:32:50 +0800245 if ((err == boost::system::errc::bad_file_descriptor) ||
246 (err == boost::asio::error::misc_errors::not_found))
Cheng C Yang58b2b532019-05-31 00:19:45 +0800247 {
248 return;
249 }
Ed Tanous16966b52021-09-15 15:06:59 -0700250 if (!buffer)
251 {
252 std::cerr << "Buffer was invalid?";
253 return;
254 }
255 // null terminate the string so we don't walk off the end
256 std::array<char, 128>& bufferRef = *buffer;
257 bufferRef[bytesTransferred] = '\0';
258
Cheng C Yang58b2b532019-05-31 00:19:45 +0800259 if (!err)
260 {
261 std::string response;
262 try
263 {
Ed Tanous16966b52021-09-15 15:06:59 -0700264 int nvalue = std::stoi(bufferRef.data());
Josh Lehan833661a2020-03-04 17:35:41 -0800265 updateValue(nvalue);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800266 errCount = 0;
267 }
268 catch (const std::invalid_argument&)
269 {
270 errCount++;
271 }
272 }
273 else
274 {
275 errCount++;
276 }
277 if (errCount >= warnAfterErrorCount)
278 {
279 if (errCount == warnAfterErrorCount)
280 {
281 std::cerr << "Failure to read event at " << path << "\n";
282 }
283 updateValue(0);
284 errCount++;
285 }
Konstantin Aladyshevc7a1ae62021-04-30 08:50:43 +0000286 restartRead();
Cheng C Yang58b2b532019-05-31 00:19:45 +0800287}
288
289// Any of the sub events of one event is asserted, then the event will be
290// asserted. Only if none of the sub events are asserted, the event will be
291// deasserted.
292void PSUSubEvent::updateValue(const int& newValue)
293{
Josh Lehan833661a2020-03-04 17:35:41 -0800294 // Take no action if value already equal
295 // Same semantics as Sensor::updateValue(const double&)
296 if (newValue == value)
297 {
298 return;
299 }
300
Cheng C Yang58b2b532019-05-31 00:19:45 +0800301 if (newValue == 0)
302 {
Yong Li591b1e42019-12-19 17:46:31 +0800303 // log deassert only after all asserts are gone
Cheng C Yang58b2b532019-05-31 00:19:45 +0800304 if (!(*asserts).empty())
305 {
Yong Li591b1e42019-12-19 17:46:31 +0800306 auto found = (*asserts).find(path);
307 if (found == (*asserts).end())
308 {
309 return;
310 }
311 (*asserts).erase(path);
312
Cheng C Yang58b2b532019-05-31 00:19:45 +0800313 return;
314 }
Ed Tanous2049bd22022-07-09 07:20:26 -0700315 if (*assertState)
Cheng C Yang58b2b532019-05-31 00:19:45 +0800316 {
317 *assertState = false;
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800318 auto foundCombine = (*combineEvent).find(groupEventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800319 if (foundCombine == (*combineEvent).end())
Cheng C Yang58b2b532019-05-31 00:19:45 +0800320 {
321 return;
322 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800323 (*combineEvent).erase(groupEventName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800324 if (!deassertMessage.empty())
325 {
326 // Fan Failed has two args
Cheng C Yang9b53a622019-08-27 22:13:58 +0800327 if (deassertMessage == "OpenBMC.0.1.PowerSupplyFanRecovered")
328 {
Patrick Williams0c42f402021-08-27 16:05:45 -0500329 lg2::info("{EVENT} deassert", "EVENT", eventName,
330 "REDFISH_MESSAGE_ID", deassertMessage,
331 "REDFISH_MESSAGE_ARGS",
332 (psuName + ',' + fanName));
Cheng C Yang9b53a622019-08-27 22:13:58 +0800333 }
334 else
335 {
Patrick Williams0c42f402021-08-27 16:05:45 -0500336 lg2::info("{EVENT} deassert", "EVENT", eventName,
337 "REDFISH_MESSAGE_ID", deassertMessage,
338 "REDFISH_MESSAGE_ARGS", psuName);
Cheng C Yang9b53a622019-08-27 22:13:58 +0800339 }
340 }
341
Cheng C Yang58b2b532019-05-31 00:19:45 +0800342 if ((*combineEvent).empty())
343 {
344 eventInterface->set_property("functional", true);
345 }
346 }
347 }
348 else
349 {
Paul Fertser34533542021-07-20 08:29:09 +0000350 std::cerr << "PSUSubEvent asserted by " << path << "\n";
351
Ed Tanous2049bd22022-07-09 07:20:26 -0700352 if ((!*assertState) && ((*asserts).empty()))
Cheng C Yang58b2b532019-05-31 00:19:45 +0800353 {
354 *assertState = true;
Cheng C Yang9b53a622019-08-27 22:13:58 +0800355 if (!assertMessage.empty())
Cheng C Yang5665db22019-07-12 00:57:30 +0800356 {
357 // Fan Failed has two args
Cheng C Yang9b53a622019-08-27 22:13:58 +0800358 if (assertMessage == "OpenBMC.0.1.PowerSupplyFanFailed")
Cheng C Yang5665db22019-07-12 00:57:30 +0800359 {
Patrick Williams0c42f402021-08-27 16:05:45 -0500360 lg2::warning("{EVENT} assert", "EVENT", eventName,
361 "REDFISH_MESSAGE_ID", assertMessage,
362 "REDFISH_MESSAGE_ARGS",
363 (psuName + ',' + fanName));
Cheng C Yang5665db22019-07-12 00:57:30 +0800364 }
365 else
366 {
Patrick Williams0c42f402021-08-27 16:05:45 -0500367 lg2::warning("{EVENT} assert", "EVENT", eventName,
368 "REDFISH_MESSAGE_ID", assertMessage,
369 "REDFISH_MESSAGE_ARGS", psuName);
Cheng C Yang5665db22019-07-12 00:57:30 +0800370 }
371 }
Cheng C Yang58b2b532019-05-31 00:19:45 +0800372 if ((*combineEvent).empty())
373 {
374 eventInterface->set_property("functional", false);
375 }
Cheng C Yang202a1ff2020-01-09 09:34:22 +0800376 (*combineEvent).emplace(groupEventName);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800377 }
Yong Li591b1e42019-12-19 17:46:31 +0800378 (*asserts).emplace(path);
Cheng C Yang58b2b532019-05-31 00:19:45 +0800379 }
380 value = newValue;
381}