blob: 650261596fb39d05d6801b102f66f410c73f5784 [file] [log] [blame]
Matthew Barthc95c5272020-06-15 19:51:13 -05001/**
2 * Copyright © 2020 IBM 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 */
Matthew Barthc95c5272020-06-15 19:51:13 -050016#include "system.hpp"
17
18#include "fan.hpp"
19#include "fan_defs.hpp"
20#include "tach_sensor.hpp"
21#include "trust_manager.hpp"
22#include "types.hpp"
23#ifdef MONITOR_USE_JSON
24#include "json_parser.hpp"
25#endif
26
Matt Spinlerf13b42e2020-10-26 15:29:49 -050027#include "fan_error.hpp"
28
Matthew Barthc95c5272020-06-15 19:51:13 -050029#include <nlohmann/json.hpp>
Matthew Barthd06905c2020-06-12 08:13:06 -050030#include <phosphor-logging/log.hpp>
Matthew Barthc95c5272020-06-15 19:51:13 -050031#include <sdbusplus/bus.hpp>
32#include <sdeventplus/event.hpp>
Matthew Barthd06905c2020-06-12 08:13:06 -050033#include <sdeventplus/source/signal.hpp>
Matthew Barthc95c5272020-06-15 19:51:13 -050034
35namespace phosphor::fan::monitor
36{
37
38using json = nlohmann::json;
Matt Spinlerf13b42e2020-10-26 15:29:49 -050039using Severity = sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level;
40
Matthew Barthd06905c2020-06-12 08:13:06 -050041using namespace phosphor::logging;
Matthew Barthc95c5272020-06-15 19:51:13 -050042
43System::System(Mode mode, sdbusplus::bus::bus& bus,
44 const sdeventplus::Event& event) :
45 _mode(mode),
46 _bus(bus), _event(event)
47{
Matt Spinlere892e392020-10-14 13:21:31 -050048 _powerState = std::make_unique<PGoodState>(
49 bus, std::bind(std::mem_fn(&System::powerStateChanged), this,
50 std::placeholders::_1));
51
Matthew Barthc95c5272020-06-15 19:51:13 -050052 json jsonObj = json::object();
53#ifdef MONITOR_USE_JSON
54 jsonObj = getJsonObj(bus);
55#endif
56 // Retrieve and set trust groups within the trust manager
Matthew Barthd06905c2020-06-12 08:13:06 -050057 setTrustMgr(getTrustGroups(jsonObj));
Matthew Barthc95c5272020-06-15 19:51:13 -050058 // Retrieve fan definitions and create fan objects to be monitored
Matthew Barthd06905c2020-06-12 08:13:06 -050059 setFans(getFanDefinitions(jsonObj));
Matt Spinlere892e392020-10-14 13:21:31 -050060 setFaultConfig(jsonObj);
Matthew Barthd06905c2020-06-12 08:13:06 -050061 log<level::INFO>("Configuration loaded");
Matt Spinlere892e392020-10-14 13:21:31 -050062
63 // Since this doesn't run at standby yet, powerStateChanged
64 // will never be called so for now treat start up as the
65 // pgood. When this does run at standby, the 'atPgood'
66 // rules won't need to be checked here.
67 if (_powerState->isPowerOn())
68 {
69 std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
70 [this](auto& rule) {
71 rule->check(PowerRuleState::atPgood, _fanHealth);
72 });
73 // Runtime rules still need to be checked since fans may already
74 // be missing that could trigger a runtime rule.
75 std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
76 [this](auto& rule) {
77 rule->check(PowerRuleState::runtime, _fanHealth);
78 });
79 }
Matthew Barthd06905c2020-06-12 08:13:06 -050080}
81
82void System::sighupHandler(sdeventplus::source::Signal&,
83 const struct signalfd_siginfo*)
84{
85 try
Matthew Barthc95c5272020-06-15 19:51:13 -050086 {
Matthew Barthd06905c2020-06-12 08:13:06 -050087 json jsonObj = json::object();
88#ifdef MONITOR_USE_JSON
89 jsonObj = getJsonObj(_bus);
90#endif
91 auto trustGrps = getTrustGroups(jsonObj);
92 auto fanDefs = getFanDefinitions(jsonObj);
93 // Set configured trust groups
94 setTrustMgr(trustGrps);
95 // Clear/set configured fan definitions
96 _fans.clear();
Matt Spinlerb63aa092020-10-14 09:45:11 -050097 _fanHealth.clear();
Matthew Barthd06905c2020-06-12 08:13:06 -050098 setFans(fanDefs);
Matt Spinlere892e392020-10-14 13:21:31 -050099 setFaultConfig(jsonObj);
Matthew Barthd06905c2020-06-12 08:13:06 -0500100 log<level::INFO>("Configuration reloaded successfully");
Matt Spinlere892e392020-10-14 13:21:31 -0500101
102 if (_powerState->isPowerOn())
103 {
104 std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
105 [this](auto& rule) {
106 rule->check(PowerRuleState::runtime, _fanHealth);
107 });
108 }
Matthew Barthd06905c2020-06-12 08:13:06 -0500109 }
110 catch (std::runtime_error& re)
111 {
112 log<level::ERR>("Error reloading config, no config changes made",
113 entry("LOAD_ERROR=%s", re.what()));
Matthew Barthc95c5272020-06-15 19:51:13 -0500114 }
115}
116
117const std::vector<CreateGroupFunction>
118 System::getTrustGroups(const json& jsonObj)
119{
120#ifdef MONITOR_USE_JSON
121 return getTrustGrps(jsonObj);
122#else
123 return trustGroups;
124#endif
125}
126
Matthew Barthd06905c2020-06-12 08:13:06 -0500127void System::setTrustMgr(const std::vector<CreateGroupFunction>& groupFuncs)
128{
129 _trust = std::make_unique<trust::Manager>(groupFuncs);
130}
131
Matthew Barthc95c5272020-06-15 19:51:13 -0500132const std::vector<FanDefinition> System::getFanDefinitions(const json& jsonObj)
133{
134#ifdef MONITOR_USE_JSON
135 return getFanDefs(jsonObj);
136#else
137 return fanDefinitions;
138#endif
139}
140
Matthew Barthd06905c2020-06-12 08:13:06 -0500141void System::setFans(const std::vector<FanDefinition>& fanDefs)
142{
143 for (const auto& fanDef : fanDefs)
144 {
145 // Check if a condition exists on the fan
146 auto condition = std::get<conditionField>(fanDef);
147 if (condition)
148 {
149 // Condition exists, skip adding fan if it fails
150 if (!(*condition)(_bus))
151 {
152 continue;
153 }
154 }
155 _fans.emplace_back(
Matt Spinlerb0412d02020-10-12 16:53:52 -0500156 std::make_unique<Fan>(_mode, _bus, _event, _trust, fanDef, *this));
Matt Spinlerb63aa092020-10-14 09:45:11 -0500157
158 updateFanHealth(*(_fans.back()));
Matthew Barthd06905c2020-06-12 08:13:06 -0500159 }
160}
161
Matt Spinlerb63aa092020-10-14 09:45:11 -0500162void System::updateFanHealth(const Fan& fan)
163{
164 std::vector<bool> sensorStatus;
165 for (const auto& sensor : fan.sensors())
166 {
167 sensorStatus.push_back(sensor->functional());
168 }
169
170 _fanHealth[fan.getName()] =
171 std::make_tuple(fan.present(), std::move(sensorStatus));
172}
173
174void System::fanStatusChange(const Fan& fan)
175{
176 updateFanHealth(fan);
Matt Spinlere892e392020-10-14 13:21:31 -0500177
178 if (_powerState->isPowerOn())
179 {
180 std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
181 [this](auto& rule) {
182 rule->check(PowerRuleState::runtime, _fanHealth);
183 });
184 }
185}
186
187void System::setFaultConfig(const json& jsonObj)
188{
189#ifdef MONITOR_USE_JSON
190 std::shared_ptr<PowerInterfaceBase> powerInterface =
191 std::make_shared<PowerInterface>();
192
193 _powerOffRules = getPowerOffRules(jsonObj, powerInterface);
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500194
195 _numNonfuncSensorsBeforeError = getNumNonfuncRotorsBeforeError(jsonObj);
Matt Spinlere892e392020-10-14 13:21:31 -0500196#endif
197}
198
199void System::powerStateChanged(bool powerStateOn)
200{
201 if (powerStateOn)
202 {
203 std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
204 [this](auto& rule) {
205 rule->check(PowerRuleState::atPgood, _fanHealth);
206 });
207 std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
208 [this](auto& rule) {
209 rule->check(PowerRuleState::runtime, _fanHealth);
210 });
211 }
212 else
213 {
214 // Cancel any in-progress power off actions
215 std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
216 [this](auto& rule) { rule->cancel(); });
217 }
Matt Spinlerb63aa092020-10-14 09:45:11 -0500218}
219
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500220void System::sensorErrorTimerExpired(const Fan& fan, const TachSensor& sensor)
221{
222 std::string fanPath{util::INVENTORY_PATH + fan.getName()};
223
224 getLogger().log(
225 fmt::format("Creating event log for faulted fan {} sensor {}", fanPath,
226 sensor.name()),
227 Logger::error);
228
229 // In order to know if the event log should have a severity of error or
230 // informational, count the number of existing nonfunctional sensors and
231 // compare it to _numNonfuncSensorsBeforeError.
232 size_t nonfuncSensors = 0;
233 for (const auto& fan : _fans)
234 {
235 for (const auto& s : fan->sensors())
236 {
237 // Don't count nonfunctional sensors that still have their
238 // error timer running as nonfunctional since they haven't
239 // had event logs created for those errors yet.
240 if (!s->functional() && !s->errorTimerRunning())
241 {
242 nonfuncSensors++;
243 }
244 }
245 }
246
247 Severity severity = Severity::Error;
248 if (nonfuncSensors < _numNonfuncSensorsBeforeError)
249 {
250 severity = Severity::Informational;
251 }
252
253 auto error =
254 std::make_unique<FanError>("xyz.openbmc_project.Fan.Error.Fault",
255 fanPath, sensor.name(), severity);
256
257 auto sensorData = captureSensorData();
258 error->commit(sensorData);
259
260 // TODO: save error so it can be committed again on a power off
261}
262
Matt Spinler27f6b682020-10-27 08:43:37 -0500263void System::fanMissingErrorTimerExpired(const Fan& fan)
264{
265 std::string fanPath{util::INVENTORY_PATH + fan.getName()};
266
267 getLogger().log(
268 fmt::format("Creating event log for missing fan {}", fanPath),
269 Logger::error);
270
271 auto error = std::make_unique<FanError>(
272 "xyz.openbmc_project.Fan.Error.Missing", fanPath, "", Severity::Error);
273
274 auto sensorData = captureSensorData();
275 error->commit(sensorData);
276
277 // TODO: save error so it can be committed again on a power off
278}
279
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500280json System::captureSensorData()
281{
282 json data;
283
284 for (const auto& fan : _fans)
285 {
286 for (const auto& sensor : fan->sensors())
287 {
288 json values;
289 values["present"] = fan->present();
290 values["functional"] = sensor->functional();
291 values["tach"] = sensor->getInput();
292 if (sensor->hasTarget())
293 {
294 values["target"] = sensor->getTarget();
295 }
296
297 data["sensors"][sensor->name()] = values;
298 }
299 }
300
301 return data;
302}
303
Matthew Barthc95c5272020-06-15 19:51:13 -0500304} // namespace phosphor::fan::monitor