blob: 2c29cb39b87f4d6621906e4cab0a148412f26b2e [file] [log] [blame]
Matt Spinlerabf8da32017-04-27 14:08:45 -05001/**
Mike Capps7b34ee02022-05-04 14:16:12 -04002 * Copyright © 2022 IBM Corporation
Matt Spinlerabf8da32017-04-27 14:08:45 -05003 *
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 */
Matt Spinlerabf8da32017-04-27 14:08:45 -050016#include "fan.hpp"
Matthew Barth177fe982020-05-26 11:05:19 -050017
Matt Spinlerae1f8ef2020-10-14 16:15:51 -050018#include "logging.hpp"
Matthew Barth177fe982020-05-26 11:05:19 -050019#include "sdbusplus.hpp"
Matt Spinlerb0412d02020-10-12 16:53:52 -050020#include "system.hpp"
Matt Spinlerabf8da32017-04-27 14:08:45 -050021#include "types.hpp"
Matt Spinlerb1e18512017-04-27 14:42:33 -050022#include "utility.hpp"
Matthew Barth177fe982020-05-26 11:05:19 -050023
Jay Meyera7aed012020-10-06 14:32:22 -050024#include <fmt/format.h>
25
Matthew Barth177fe982020-05-26 11:05:19 -050026#include <phosphor-logging/log.hpp>
27
Matt Spinlerabf8da32017-04-27 14:08:45 -050028namespace phosphor
29{
30namespace fan
31{
32namespace monitor
33{
34
35using namespace phosphor::logging;
Matt Spinlerb0412d02020-10-12 16:53:52 -050036using namespace sdbusplus::bus::match;
Matt Spinlerabf8da32017-04-27 14:08:45 -050037
Patrick Williamscb356d42022-07-22 19:26:53 -050038Fan::Fan(Mode mode, sdbusplus::bus_t& bus, const sdeventplus::Event& event,
Matt Spinlerb0412d02020-10-12 16:53:52 -050039 std::unique_ptr<trust::Manager>& trust, const FanDefinition& def,
40 System& system) :
Matt Spinlerabf8da32017-04-27 14:08:45 -050041 _bus(bus),
Matt Spinler18fb12b2023-05-09 11:17:42 -050042 _name(def.name), _deviation(def.deviation),
Matt Spinlerf724c162023-05-10 11:14:37 -050043 _upperDeviation(def.upperDeviation),
Matt Spinler18fb12b2023-05-09 11:17:42 -050044 _numSensorFailsForNonFunc(def.numSensorFailsForNonfunc),
Matt Spinlerb0412d02020-10-12 16:53:52 -050045 _trustManager(trust),
46#ifdef MONITOR_USE_JSON
Matt Spinler18fb12b2023-05-09 11:17:42 -050047 _monitorDelay(def.monitorStartDelay),
Matt Spinlerb0412d02020-10-12 16:53:52 -050048 _monitorTimer(event, std::bind(std::mem_fn(&Fan::startMonitor), this)),
49#endif
Matt Spinlerb63aa092020-10-14 09:45:11 -050050 _system(system),
51 _presenceMatch(bus,
52 rules::propertiesChanged(util::INVENTORY_PATH + _name,
53 util::INV_ITEM_IFACE),
54 std::bind(std::mem_fn(&Fan::presenceChanged), this,
Matt Spinler27f6b682020-10-27 08:43:37 -050055 std::placeholders::_1)),
Matt Spinler7d135642021-02-04 12:44:17 -060056 _presenceIfaceAddedMatch(
57 bus,
58 rules::interfacesAdded() +
59 rules::argNpath(0, util::INVENTORY_PATH + _name),
60 std::bind(std::mem_fn(&Fan::presenceIfaceAdded), this,
61 std::placeholders::_1)),
Matt Spinler18fb12b2023-05-09 11:17:42 -050062 _fanMissingErrorDelay(def.fanMissingErrDelay),
63 _setFuncOnPresent(def.funcOnPresent)
Matt Spinlerabf8da32017-04-27 14:08:45 -050064{
Matthew Barth0a9fe162018-01-26 12:53:15 -060065 // Setup tach sensors for monitoring
Matt Spinler18fb12b2023-05-09 11:17:42 -050066 for (const auto& s : def.sensorList)
Matthew Barth0a9fe162018-01-26 12:53:15 -060067 {
Matt Spinler4283c5d2021-03-01 15:56:00 -060068 _sensors.emplace_back(std::make_shared<TachSensor>(
Matt Spinler18fb12b2023-05-09 11:17:42 -050069 mode, bus, *this, s.name, s.hasTarget, def.funcDelay,
70 s.targetInterface, s.targetPath, s.factor, s.offset, def.method,
71 s.threshold, s.ignoreAboveMax, def.timeout,
72 def.nonfuncRotorErrDelay, def.countInterval, event));
Matthew Barth0a9fe162018-01-26 12:53:15 -060073
Matt Spinler4283c5d2021-03-01 15:56:00 -060074 _trustManager->registerSensor(_sensors.back());
Matthew Barth0a9fe162018-01-26 12:53:15 -060075 }
76
Mike Cappsce6820a2021-05-26 10:40:19 -040077 bool functionalState =
78 (_numSensorFailsForNonFunc == 0) ||
79 (countNonFunctionalSensors() < _numSensorFailsForNonFunc);
80
Mike Capps9ff48772021-07-19 14:49:43 -040081 if (updateInventory(functionalState) && !functionalState)
82 {
83 // the inventory update threw an exception, possibly because D-Bus
84 // wasn't ready. Try to update sensors back to functional to avoid a
85 // false-alarm. They will be updated again from subscribing to the
86 // properties-changed event
87
88 for (auto& sensor : _sensors)
89 sensor->setFunctional(true);
90 }
Mike Cappsce6820a2021-05-26 10:40:19 -040091
Matt Spinlerb0412d02020-10-12 16:53:52 -050092#ifndef MONITOR_USE_JSON
Matthew Barth0a9fe162018-01-26 12:53:15 -060093 // Check current tach state when entering monitor mode
Matthew Barth6ad28432017-08-22 11:18:19 -050094 if (mode != Mode::init)
95 {
Matt Spinlerb0412d02020-10-12 16:53:52 -050096 _monitorReady = true;
97
Matthew Barth177fe982020-05-26 11:05:19 -050098 // The TachSensors will now have already read the input
99 // and target values, so check them.
Matthew Barth6ad28432017-08-22 11:18:19 -0500100 tachChanged();
101 }
Matt Spinlerb0412d02020-10-12 16:53:52 -0500102#else
Matt Spinler7d135642021-02-04 12:44:17 -0600103 if (_system.isPowerOn())
104 {
105 _monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay));
106 }
Matt Spinlerb0412d02020-10-12 16:53:52 -0500107#endif
Matt Spinlerb63aa092020-10-14 09:45:11 -0500108
Matt Spinler27f6b682020-10-27 08:43:37 -0500109 if (_fanMissingErrorDelay)
110 {
111 _fanMissingErrorTimer = std::make_unique<
112 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>(
113 event, std::bind(&System::fanMissingErrorTimerExpired, &system,
114 std::ref(*this)));
Matt Spinler7d135642021-02-04 12:44:17 -0600115 }
Matt Spinler27f6b682020-10-27 08:43:37 -0500116
Matt Spinler7d135642021-02-04 12:44:17 -0600117 try
118 {
119 _present = util::SDBusPlus::getProperty<bool>(
120 util::INVENTORY_PATH + _name, util::INV_ITEM_IFACE, "Present");
121
122 if (!_present)
Matt Spinler27f6b682020-10-27 08:43:37 -0500123 {
Matt Spinlerac372972021-01-25 15:11:22 -0600124 getLogger().log(
125 fmt::format("On startup, fan {} is missing", _name));
Matt Spinler7d135642021-02-04 12:44:17 -0600126 if (_system.isPowerOn() && _fanMissingErrorTimer)
127 {
128 _fanMissingErrorTimer->restartOnce(
129 std::chrono::seconds{*_fanMissingErrorDelay});
130 }
131 }
132 }
133 catch (const util::DBusServiceError& e)
134 {
135 // This could happen on the first BMC boot if the presence
136 // detect app hasn't started yet and there isn't an inventory
137 // cache yet.
138 }
139}
140
Patrick Williamscb356d42022-07-22 19:26:53 -0500141void Fan::presenceIfaceAdded(sdbusplus::message_t& msg)
Matt Spinler7d135642021-02-04 12:44:17 -0600142{
143 sdbusplus::message::object_path path;
144 std::map<std::string, std::map<std::string, std::variant<bool>>> interfaces;
145
146 msg.read(path, interfaces);
147
148 auto properties = interfaces.find(util::INV_ITEM_IFACE);
149 if (properties == interfaces.end())
150 {
151 return;
152 }
153
154 auto property = properties->second.find("Present");
155 if (property == properties->second.end())
156 {
157 return;
158 }
159
160 _present = std::get<bool>(property->second);
161
162 if (!_present)
163 {
164 getLogger().log(fmt::format(
165 "New fan {} interface added and fan is not present", _name));
166 if (_system.isPowerOn() && _fanMissingErrorTimer)
167 {
Matt Spinler27f6b682020-10-27 08:43:37 -0500168 _fanMissingErrorTimer->restartOnce(
169 std::chrono::seconds{*_fanMissingErrorDelay});
170 }
171 }
Matt Spinler7d135642021-02-04 12:44:17 -0600172
173 _system.fanStatusChange(*this);
Matt Spinlerb0412d02020-10-12 16:53:52 -0500174}
175
176void Fan::startMonitor()
177{
178 _monitorReady = true;
179
Matt Spinler4283c5d2021-03-01 15:56:00 -0600180 std::for_each(_sensors.begin(), _sensors.end(), [this](auto& sensor) {
181 if (_present)
182 {
183 try
184 {
185 // Force a getProperty call to check if the tach sensor is
186 // on D-Bus. If it isn't, now set it to nonfunctional.
187 // This isn't done earlier so that code watching for
188 // nonfunctional tach sensors doesn't take actions before
189 // those sensors show up on D-Bus.
190 sensor->updateTachAndTarget();
191 tachChanged(*sensor);
192 }
193 catch (const util::DBusServiceError& e)
194 {
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500195 // The tach property still isn't on D-Bus. Ensure
196 // sensor is nonfunctional, but skip creating an
197 // error for it since it isn't a fan problem.
Matt Spinler4283c5d2021-03-01 15:56:00 -0600198 getLogger().log(fmt::format(
199 "Monitoring starting but {} sensor value not on D-Bus",
200 sensor->name()));
201
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500202 sensor->setFunctional(false, true);
Matt Spinler4283c5d2021-03-01 15:56:00 -0600203
204 if (_numSensorFailsForNonFunc)
205 {
206 if (_functional && (countNonFunctionalSensors() >=
207 _numSensorFailsForNonFunc))
208 {
209 updateInventory(false);
210 }
211 }
212
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500213 // At this point, don't start any power off actions due
214 // to missing sensors. Let something else handle that
215 // policy.
216 _system.fanStatusChange(*this, true);
Matt Spinler4283c5d2021-03-01 15:56:00 -0600217 }
218 }
219 });
Matt Spinlerabf8da32017-04-27 14:08:45 -0500220}
221
Matt Spinlerebaae612017-04-27 14:21:48 -0500222void Fan::tachChanged()
223{
Matt Spinlerb0412d02020-10-12 16:53:52 -0500224 if (_monitorReady)
Matt Spinlerebaae612017-04-27 14:21:48 -0500225 {
Matt Spinlerb0412d02020-10-12 16:53:52 -0500226 for (auto& s : _sensors)
227 {
228 tachChanged(*s);
229 }
Matt Spinlerebaae612017-04-27 14:21:48 -0500230 }
231}
232
Matt Spinlerebaae612017-04-27 14:21:48 -0500233void Fan::tachChanged(TachSensor& sensor)
234{
Matt Spinler7d135642021-02-04 12:44:17 -0600235 if (!_system.isPowerOn() || !_monitorReady)
236 {
237 return;
238 }
239
Matt Spinlerc39e8592017-09-28 13:13:08 -0500240 if (_trustManager->active())
241 {
242 if (!_trustManager->checkTrust(sensor))
243 {
244 return;
245 }
246 }
247
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600248 // If the error checking method is 'count', if a tach change leads
249 // to an out of range sensor the count timer will take over in calling
250 // process() until the sensor is healthy again.
251 if (!sensor.countTimerRunning())
Matt Spinler623635c2021-03-29 13:13:59 -0500252 {
253 process(sensor);
254 }
255}
256
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600257void Fan::countTimerExpired(TachSensor& sensor)
Matt Spinler623635c2021-03-29 13:13:59 -0500258{
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600259 if (_trustManager->active() && !_trustManager->checkTrust(sensor))
Matt Spinler623635c2021-03-29 13:13:59 -0500260 {
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600261 return;
Matt Spinler623635c2021-03-29 13:13:59 -0500262 }
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600263 process(sensor);
Matthew Barthfcb0dbc2021-02-10 14:23:39 -0600264}
265
266void Fan::process(TachSensor& sensor)
267{
Matthew Barth177fe982020-05-26 11:05:19 -0500268 // If this sensor is out of range at this moment, start
269 // its timer, at the end of which the inventory
270 // for the fan may get updated to not functional.
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500271
Matthew Barth177fe982020-05-26 11:05:19 -0500272 // If this sensor is OK, put everything back into a good state.
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500273
274 if (outOfRange(sensor))
275 {
Matthew Barthe11cbc62018-02-20 12:11:07 -0600276 if (sensor.functional())
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500277 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800278 switch (sensor.getMethod())
279 {
280 case MethodMode::timebased:
281 // Start nonfunctional timer if not already running
282 sensor.startTimer(TimerMode::nonfunc);
283 break;
284 case MethodMode::count:
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600285
286 if (!sensor.countTimerRunning())
287 {
288 sensor.startCountTimer();
289 }
Jolie Ku69f2f482020-10-21 09:59:43 +0800290 sensor.setCounter(true);
291 if (sensor.getCounter() >= sensor.getThreshold())
292 {
293 updateState(sensor);
294 }
295 break;
296 }
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500297 }
298 }
299 else
300 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800301 switch (sensor.getMethod())
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500302 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800303 case MethodMode::timebased:
304 if (sensor.functional())
305 {
Matthew Barth11b5d8f2021-01-28 14:04:09 -0600306 if (sensor.timerRunning())
307 {
308 sensor.stopTimer();
309 }
Jolie Ku69f2f482020-10-21 09:59:43 +0800310 }
311 else
312 {
313 // Start functional timer if not already running
314 sensor.startTimer(TimerMode::func);
315 }
316 break;
317 case MethodMode::count:
318 sensor.setCounter(false);
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600319 if (sensor.getCounter() == 0)
Jolie Ku69f2f482020-10-21 09:59:43 +0800320 {
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600321 if (!sensor.functional())
322 {
323 updateState(sensor);
324 }
325
326 sensor.stopCountTimer();
Jolie Ku69f2f482020-10-21 09:59:43 +0800327 }
328 break;
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500329 }
330 }
Matt Spinlerebaae612017-04-27 14:21:48 -0500331}
332
Matthew Barthf552ea52018-01-15 16:22:04 -0600333uint64_t Fan::findTargetSpeed()
Matt Spinlerabf8da32017-04-27 14:08:45 -0500334{
335 uint64_t target = 0;
Matthew Barth177fe982020-05-26 11:05:19 -0500336 // The sensor doesn't support a target,
337 // so get it from another sensor.
Matthew Barthf552ea52018-01-15 16:22:04 -0600338 auto s = std::find_if(_sensors.begin(), _sensors.end(),
Matthew Barth177fe982020-05-26 11:05:19 -0500339 [](const auto& s) { return s->hasTarget(); });
Matt Spinlerabf8da32017-04-27 14:08:45 -0500340
Matthew Barthf552ea52018-01-15 16:22:04 -0600341 if (s != _sensors.end())
Matt Spinlerabf8da32017-04-27 14:08:45 -0500342 {
Matthew Barthf552ea52018-01-15 16:22:04 -0600343 target = (*s)->getTarget();
Matt Spinlerabf8da32017-04-27 14:08:45 -0500344 }
345
346 return target;
347}
348
Mike Cappsce6820a2021-05-26 10:40:19 -0400349size_t Fan::countNonFunctionalSensors() const
Matt Spinlerabf8da32017-04-27 14:08:45 -0500350{
Matthew Barth7c23a042021-01-26 16:21:45 -0600351 return std::count_if(_sensors.begin(), _sensors.end(),
352 [](const auto& s) { return !s->functional(); });
Matt Spinlerabf8da32017-04-27 14:08:45 -0500353}
354
Matt Spinlerabf8da32017-04-27 14:08:45 -0500355bool Fan::outOfRange(const TachSensor& sensor)
356{
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400357 if (!sensor.hasOwner())
Matt Spinlerabf8da32017-04-27 14:08:45 -0500358 {
359 return true;
360 }
361
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400362 auto actual = static_cast<uint64_t>(sensor.getInput());
Matt Spinlerf724c162023-05-10 11:14:37 -0500363 auto range = sensor.getRange(_deviation, _upperDeviation);
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400364
Matthew Barth8a8aa442021-11-19 14:13:13 -0600365 return ((actual < range.first) ||
366 (range.second && actual > range.second.value()));
Matt Spinlerabf8da32017-04-27 14:08:45 -0500367}
368
Jolie Ku69f2f482020-10-21 09:59:43 +0800369void Fan::updateState(TachSensor& sensor)
Matt Spinlera9406a72017-04-27 14:29:24 -0500370{
Matt Spinler7d135642021-02-04 12:44:17 -0600371 if (!_system.isPowerOn())
372 {
373 return;
374 }
375
Matt Spinlerf724c162023-05-10 11:14:37 -0500376 auto range = sensor.getRange(_deviation, _upperDeviation);
Matthew Barth8a8aa442021-11-19 14:13:13 -0600377 std::string rangeMax = "NoMax";
378 if (range.second)
379 {
380 rangeMax = std::to_string(range.second.value());
381 }
382
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500383 // Skip starting the error timer if the sensor
384 // isn't on D-Bus as this isn't a fan hardware problem.
385 sensor.setFunctional(!sensor.functional(), !sensor.hasOwner());
386
387 getLogger().log(fmt::format(
388 "Setting tach sensor {} functional state to {}. "
Matt Spinler466bd222023-01-25 16:15:52 -0600389 "[target = {}, actual = {}, allowed range = ({} - {}) "
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500390 "owned = {}]",
391 sensor.name(), sensor.functional(), sensor.getTarget(),
392 sensor.getInput(), range.first, rangeMax, sensor.hasOwner()));
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500393
394 // A zero value for _numSensorFailsForNonFunc means we aren't dealing
395 // with fan FRU functional status, only sensor functional status.
396 if (_numSensorFailsForNonFunc)
Matthew Barthe11cbc62018-02-20 12:11:07 -0600397 {
Matthew Barth7c23a042021-01-26 16:21:45 -0600398 auto numNonFuncSensors = countNonFunctionalSensors();
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500399 // If the fan was nonfunctional and enough sensors are now OK,
Matthew Barthcceffdd2021-05-20 12:17:21 -0500400 // the fan can be set to functional as long as `set_func_on_present` was
401 // not set
402 if (!_setFuncOnPresent && !_functional &&
403 !(numNonFuncSensors >= _numSensorFailsForNonFunc))
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500404 {
Matthew Barth7c23a042021-01-26 16:21:45 -0600405 getLogger().log(fmt::format("Setting fan {} to functional, number "
406 "of nonfunctional sensors = {}",
407 _name, numNonFuncSensors));
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500408 updateInventory(true);
409 }
Matt Spinlera9406a72017-04-27 14:29:24 -0500410
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500411 // If the fan is currently functional, but too many
412 // contained sensors are now nonfunctional, update
Matthew Barth7c23a042021-01-26 16:21:45 -0600413 // the fan to nonfunctional.
414 if (_functional && (numNonFuncSensors >= _numSensorFailsForNonFunc))
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500415 {
Matthew Barth7c23a042021-01-26 16:21:45 -0600416 getLogger().log(fmt::format("Setting fan {} to nonfunctional, "
417 "number of nonfunctional sensors = {}",
418 _name, numNonFuncSensors));
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500419 updateInventory(false);
420 }
Matt Spinlerb1e18512017-04-27 14:42:33 -0500421 }
Matt Spinlerb63aa092020-10-14 09:45:11 -0500422
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500423 // Skip the power off rule checks if the sensor isn't
424 // on D-Bus so a running system isn't shutdown.
425 _system.fanStatusChange(*this, !sensor.hasOwner());
Matt Spinlera9406a72017-04-27 14:29:24 -0500426}
427
Mike Capps9ff48772021-07-19 14:49:43 -0400428bool Fan::updateInventory(bool functional)
Matt Spinlerb1e18512017-04-27 14:42:33 -0500429{
Mike Capps9ff48772021-07-19 14:49:43 -0400430 bool dbusError = false;
431
432 try
Matt Spinlerb1e18512017-04-27 14:42:33 -0500433 {
Mike Capps9ff48772021-07-19 14:49:43 -0400434 auto objectMap =
435 util::getObjMap<bool>(_name, util::OPERATIONAL_STATUS_INTF,
436 util::FUNCTIONAL_PROPERTY, functional);
437
Mike Capps8af8a622022-02-04 16:13:33 -0500438 auto response = util::SDBusPlus::callMethod(
439 _bus, util::INVENTORY_SVC, util::INVENTORY_PATH,
440 util::INVENTORY_INTF, "Notify", objectMap);
Mike Capps9ff48772021-07-19 14:49:43 -0400441
442 if (response.is_method_error())
443 {
444 log<level::ERR>("Error in Notify call to update inventory");
445
446 dbusError = true;
447 }
448 }
449 catch (const util::DBusError& e)
450 {
451 dbusError = true;
452
453 getLogger().log(
454 fmt::format("D-Bus Exception reading/updating inventory : {}",
455 e.what()),
456 Logger::error);
Matt Spinlerb1e18512017-04-27 14:42:33 -0500457 }
458
Matthew Barth177fe982020-05-26 11:05:19 -0500459 // This will always track the current state of the inventory.
Matt Spinlerb1e18512017-04-27 14:42:33 -0500460 _functional = functional;
Mike Capps9ff48772021-07-19 14:49:43 -0400461
462 return dbusError;
Matt Spinlerb1e18512017-04-27 14:42:33 -0500463}
464
Patrick Williamscb356d42022-07-22 19:26:53 -0500465void Fan::presenceChanged(sdbusplus::message_t& msg)
Matt Spinlerb63aa092020-10-14 09:45:11 -0500466{
467 std::string interface;
468 std::map<std::string, std::variant<bool>> properties;
469
470 msg.read(interface, properties);
471
472 auto presentProp = properties.find("Present");
473 if (presentProp != properties.end())
474 {
475 _present = std::get<bool>(presentProp->second);
476
Matt Spinler27f6b682020-10-27 08:43:37 -0500477 getLogger().log(
Matt Spinlerac372972021-01-25 15:11:22 -0600478 fmt::format("Fan {} presence state change to {}", _name, _present));
Matt Spinler27f6b682020-10-27 08:43:37 -0500479
Matt Spinlera3584bd2021-03-29 15:48:30 -0500480 if (_present && _setFuncOnPresent)
481 {
482 updateInventory(true);
483 std::for_each(_sensors.begin(), _sensors.end(), [](auto& sensor) {
484 sensor->setFunctional(true);
485 sensor->resetMethod();
486 });
487 }
488
Matthew Barth43b4cde2022-02-15 16:30:11 -0600489 _system.fanStatusChange(*this);
490
Matt Spinler27f6b682020-10-27 08:43:37 -0500491 if (_fanMissingErrorDelay)
492 {
Matt Spinler7d135642021-02-04 12:44:17 -0600493 if (!_present && _system.isPowerOn())
Matt Spinler27f6b682020-10-27 08:43:37 -0500494 {
495 _fanMissingErrorTimer->restartOnce(
496 std::chrono::seconds{*_fanMissingErrorDelay});
497 }
Matt Spinler7d135642021-02-04 12:44:17 -0600498 else if (_present && _fanMissingErrorTimer->isEnabled())
Matt Spinler27f6b682020-10-27 08:43:37 -0500499 {
500 _fanMissingErrorTimer->setEnabled(false);
501 }
502 }
Matt Spinlerb63aa092020-10-14 09:45:11 -0500503 }
504}
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500505
506void Fan::sensorErrorTimerExpired(const TachSensor& sensor)
507{
Matt Spinler7d135642021-02-04 12:44:17 -0600508 if (_present && _system.isPowerOn())
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500509 {
510 _system.sensorErrorTimerExpired(*this, sensor);
511 }
512}
513
Mike Capps808d7fe2022-06-13 10:12:16 -0400514void Fan::powerStateChanged([[maybe_unused]] bool powerStateOn)
Matt Spinler7d135642021-02-04 12:44:17 -0600515{
516#ifdef MONITOR_USE_JSON
517 if (powerStateOn)
518 {
Matt Spinler7d135642021-02-04 12:44:17 -0600519 _monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay));
520
Matt Spinlerbb449c12021-06-14 11:45:28 -0600521 _numSensorsOnDBusAtPowerOn = 0;
522
523 std::for_each(_sensors.begin(), _sensors.end(), [this](auto& sensor) {
524 try
525 {
526 // Force a getProperty call. If sensor is on D-Bus,
527 // then make sure it's functional.
528 sensor->updateTachAndTarget();
529
530 _numSensorsOnDBusAtPowerOn++;
531
532 if (_present)
533 {
534 // If not functional, set it back to functional.
535 if (!sensor->functional())
536 {
537 sensor->setFunctional(true);
538 _system.fanStatusChange(*this, true);
539 }
540
541 // Set the counters back to zero
542 if (sensor->getMethod() == MethodMode::count)
543 {
544 sensor->resetMethod();
545 }
546 }
547 }
548 catch (const util::DBusError& e)
549 {
550 // Properties still aren't on D-Bus. Let startMonitor()
551 // deal with it, or maybe System::powerStateChanged() if
552 // there aren't any sensors at all on D-Bus.
553 getLogger().log(fmt::format(
554 "At power on, tach sensor {} value not on D-Bus",
555 sensor->name()));
556 }
557 });
558
Matt Spinler4283c5d2021-03-01 15:56:00 -0600559 if (_present)
560 {
Matt Spinler4283c5d2021-03-01 15:56:00 -0600561 // If configured to change functional state on the fan itself,
562 // Set it back to true now if necessary.
563 if (_numSensorFailsForNonFunc)
564 {
565 if (!_functional &&
566 (countNonFunctionalSensors() < _numSensorFailsForNonFunc))
567 {
568 updateInventory(true);
569 }
570 }
571 }
572 else
Matt Spinler7d135642021-02-04 12:44:17 -0600573 {
574 getLogger().log(
575 fmt::format("At power on, fan {} is missing", _name));
576
577 if (_fanMissingErrorTimer)
578 {
579 _fanMissingErrorTimer->restartOnce(
580 std::chrono::seconds{*_fanMissingErrorDelay});
581 }
582 }
583 }
584 else
585 {
586 _monitorReady = false;
587
588 if (_monitorTimer.isEnabled())
589 {
590 _monitorTimer.setEnabled(false);
591 }
592
593 if (_fanMissingErrorTimer && _fanMissingErrorTimer->isEnabled())
594 {
595 _fanMissingErrorTimer->setEnabled(false);
596 }
597
598 std::for_each(_sensors.begin(), _sensors.end(), [](auto& sensor) {
599 if (sensor->timerRunning())
600 {
601 sensor->stopTimer();
602 }
Matt Spinler623635c2021-03-29 13:13:59 -0500603
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600604 sensor->stopCountTimer();
605 });
Matt Spinler7d135642021-02-04 12:44:17 -0600606 }
607#endif
608}
609
Matthew Barth177fe982020-05-26 11:05:19 -0500610} // namespace monitor
611} // namespace fan
612} // namespace phosphor