blob: a421290cc0c977bc80f17248e525fe8701116391 [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),
43 _numSensorFailsForNonFunc(def.numSensorFailsForNonfunc),
Matt Spinlerb0412d02020-10-12 16:53:52 -050044 _trustManager(trust),
45#ifdef MONITOR_USE_JSON
Matt Spinler18fb12b2023-05-09 11:17:42 -050046 _monitorDelay(def.monitorStartDelay),
Matt Spinlerb0412d02020-10-12 16:53:52 -050047 _monitorTimer(event, std::bind(std::mem_fn(&Fan::startMonitor), this)),
48#endif
Matt Spinlerb63aa092020-10-14 09:45:11 -050049 _system(system),
50 _presenceMatch(bus,
51 rules::propertiesChanged(util::INVENTORY_PATH + _name,
52 util::INV_ITEM_IFACE),
53 std::bind(std::mem_fn(&Fan::presenceChanged), this,
Matt Spinler27f6b682020-10-27 08:43:37 -050054 std::placeholders::_1)),
Matt Spinler7d135642021-02-04 12:44:17 -060055 _presenceIfaceAddedMatch(
56 bus,
57 rules::interfacesAdded() +
58 rules::argNpath(0, util::INVENTORY_PATH + _name),
59 std::bind(std::mem_fn(&Fan::presenceIfaceAdded), this,
60 std::placeholders::_1)),
Matt Spinler18fb12b2023-05-09 11:17:42 -050061 _fanMissingErrorDelay(def.fanMissingErrDelay),
62 _setFuncOnPresent(def.funcOnPresent)
Matt Spinlerabf8da32017-04-27 14:08:45 -050063{
Matthew Barth0a9fe162018-01-26 12:53:15 -060064 // Setup tach sensors for monitoring
Matt Spinler18fb12b2023-05-09 11:17:42 -050065 for (const auto& s : def.sensorList)
Matthew Barth0a9fe162018-01-26 12:53:15 -060066 {
Matt Spinler4283c5d2021-03-01 15:56:00 -060067 _sensors.emplace_back(std::make_shared<TachSensor>(
Matt Spinler18fb12b2023-05-09 11:17:42 -050068 mode, bus, *this, s.name, s.hasTarget, def.funcDelay,
69 s.targetInterface, s.targetPath, s.factor, s.offset, def.method,
70 s.threshold, s.ignoreAboveMax, def.timeout,
71 def.nonfuncRotorErrDelay, def.countInterval, event));
Matthew Barth0a9fe162018-01-26 12:53:15 -060072
Matt Spinler4283c5d2021-03-01 15:56:00 -060073 _trustManager->registerSensor(_sensors.back());
Matthew Barth0a9fe162018-01-26 12:53:15 -060074 }
75
Mike Cappsce6820a2021-05-26 10:40:19 -040076 bool functionalState =
77 (_numSensorFailsForNonFunc == 0) ||
78 (countNonFunctionalSensors() < _numSensorFailsForNonFunc);
79
Mike Capps9ff48772021-07-19 14:49:43 -040080 if (updateInventory(functionalState) && !functionalState)
81 {
82 // the inventory update threw an exception, possibly because D-Bus
83 // wasn't ready. Try to update sensors back to functional to avoid a
84 // false-alarm. They will be updated again from subscribing to the
85 // properties-changed event
86
87 for (auto& sensor : _sensors)
88 sensor->setFunctional(true);
89 }
Mike Cappsce6820a2021-05-26 10:40:19 -040090
Matt Spinlerb0412d02020-10-12 16:53:52 -050091#ifndef MONITOR_USE_JSON
Matthew Barth0a9fe162018-01-26 12:53:15 -060092 // Check current tach state when entering monitor mode
Matthew Barth6ad28432017-08-22 11:18:19 -050093 if (mode != Mode::init)
94 {
Matt Spinlerb0412d02020-10-12 16:53:52 -050095 _monitorReady = true;
96
Matthew Barth177fe982020-05-26 11:05:19 -050097 // The TachSensors will now have already read the input
98 // and target values, so check them.
Matthew Barth6ad28432017-08-22 11:18:19 -050099 tachChanged();
100 }
Matt Spinlerb0412d02020-10-12 16:53:52 -0500101#else
Matt Spinler7d135642021-02-04 12:44:17 -0600102 if (_system.isPowerOn())
103 {
104 _monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay));
105 }
Matt Spinlerb0412d02020-10-12 16:53:52 -0500106#endif
Matt Spinlerb63aa092020-10-14 09:45:11 -0500107
Matt Spinler27f6b682020-10-27 08:43:37 -0500108 if (_fanMissingErrorDelay)
109 {
110 _fanMissingErrorTimer = std::make_unique<
111 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>(
112 event, std::bind(&System::fanMissingErrorTimerExpired, &system,
113 std::ref(*this)));
Matt Spinler7d135642021-02-04 12:44:17 -0600114 }
Matt Spinler27f6b682020-10-27 08:43:37 -0500115
Matt Spinler7d135642021-02-04 12:44:17 -0600116 try
117 {
118 _present = util::SDBusPlus::getProperty<bool>(
119 util::INVENTORY_PATH + _name, util::INV_ITEM_IFACE, "Present");
120
121 if (!_present)
Matt Spinler27f6b682020-10-27 08:43:37 -0500122 {
Matt Spinlerac372972021-01-25 15:11:22 -0600123 getLogger().log(
124 fmt::format("On startup, fan {} is missing", _name));
Matt Spinler7d135642021-02-04 12:44:17 -0600125 if (_system.isPowerOn() && _fanMissingErrorTimer)
126 {
127 _fanMissingErrorTimer->restartOnce(
128 std::chrono::seconds{*_fanMissingErrorDelay});
129 }
130 }
131 }
132 catch (const util::DBusServiceError& e)
133 {
134 // This could happen on the first BMC boot if the presence
135 // detect app hasn't started yet and there isn't an inventory
136 // cache yet.
137 }
138}
139
Patrick Williamscb356d42022-07-22 19:26:53 -0500140void Fan::presenceIfaceAdded(sdbusplus::message_t& msg)
Matt Spinler7d135642021-02-04 12:44:17 -0600141{
142 sdbusplus::message::object_path path;
143 std::map<std::string, std::map<std::string, std::variant<bool>>> interfaces;
144
145 msg.read(path, interfaces);
146
147 auto properties = interfaces.find(util::INV_ITEM_IFACE);
148 if (properties == interfaces.end())
149 {
150 return;
151 }
152
153 auto property = properties->second.find("Present");
154 if (property == properties->second.end())
155 {
156 return;
157 }
158
159 _present = std::get<bool>(property->second);
160
161 if (!_present)
162 {
163 getLogger().log(fmt::format(
164 "New fan {} interface added and fan is not present", _name));
165 if (_system.isPowerOn() && _fanMissingErrorTimer)
166 {
Matt Spinler27f6b682020-10-27 08:43:37 -0500167 _fanMissingErrorTimer->restartOnce(
168 std::chrono::seconds{*_fanMissingErrorDelay});
169 }
170 }
Matt Spinler7d135642021-02-04 12:44:17 -0600171
172 _system.fanStatusChange(*this);
Matt Spinlerb0412d02020-10-12 16:53:52 -0500173}
174
175void Fan::startMonitor()
176{
177 _monitorReady = true;
178
Matt Spinler4283c5d2021-03-01 15:56:00 -0600179 std::for_each(_sensors.begin(), _sensors.end(), [this](auto& sensor) {
180 if (_present)
181 {
182 try
183 {
184 // Force a getProperty call to check if the tach sensor is
185 // on D-Bus. If it isn't, now set it to nonfunctional.
186 // This isn't done earlier so that code watching for
187 // nonfunctional tach sensors doesn't take actions before
188 // those sensors show up on D-Bus.
189 sensor->updateTachAndTarget();
190 tachChanged(*sensor);
191 }
192 catch (const util::DBusServiceError& e)
193 {
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500194 // The tach property still isn't on D-Bus. Ensure
195 // sensor is nonfunctional, but skip creating an
196 // error for it since it isn't a fan problem.
Matt Spinler4283c5d2021-03-01 15:56:00 -0600197 getLogger().log(fmt::format(
198 "Monitoring starting but {} sensor value not on D-Bus",
199 sensor->name()));
200
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500201 sensor->setFunctional(false, true);
Matt Spinler4283c5d2021-03-01 15:56:00 -0600202
203 if (_numSensorFailsForNonFunc)
204 {
205 if (_functional && (countNonFunctionalSensors() >=
206 _numSensorFailsForNonFunc))
207 {
208 updateInventory(false);
209 }
210 }
211
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500212 // At this point, don't start any power off actions due
213 // to missing sensors. Let something else handle that
214 // policy.
215 _system.fanStatusChange(*this, true);
Matt Spinler4283c5d2021-03-01 15:56:00 -0600216 }
217 }
218 });
Matt Spinlerabf8da32017-04-27 14:08:45 -0500219}
220
Matt Spinlerebaae612017-04-27 14:21:48 -0500221void Fan::tachChanged()
222{
Matt Spinlerb0412d02020-10-12 16:53:52 -0500223 if (_monitorReady)
Matt Spinlerebaae612017-04-27 14:21:48 -0500224 {
Matt Spinlerb0412d02020-10-12 16:53:52 -0500225 for (auto& s : _sensors)
226 {
227 tachChanged(*s);
228 }
Matt Spinlerebaae612017-04-27 14:21:48 -0500229 }
230}
231
Matt Spinlerebaae612017-04-27 14:21:48 -0500232void Fan::tachChanged(TachSensor& sensor)
233{
Matt Spinler7d135642021-02-04 12:44:17 -0600234 if (!_system.isPowerOn() || !_monitorReady)
235 {
236 return;
237 }
238
Matt Spinlerc39e8592017-09-28 13:13:08 -0500239 if (_trustManager->active())
240 {
241 if (!_trustManager->checkTrust(sensor))
242 {
243 return;
244 }
245 }
246
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600247 // If the error checking method is 'count', if a tach change leads
248 // to an out of range sensor the count timer will take over in calling
249 // process() until the sensor is healthy again.
250 if (!sensor.countTimerRunning())
Matt Spinler623635c2021-03-29 13:13:59 -0500251 {
252 process(sensor);
253 }
254}
255
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600256void Fan::countTimerExpired(TachSensor& sensor)
Matt Spinler623635c2021-03-29 13:13:59 -0500257{
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600258 if (_trustManager->active() && !_trustManager->checkTrust(sensor))
Matt Spinler623635c2021-03-29 13:13:59 -0500259 {
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600260 return;
Matt Spinler623635c2021-03-29 13:13:59 -0500261 }
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600262 process(sensor);
Matthew Barthfcb0dbc2021-02-10 14:23:39 -0600263}
264
265void Fan::process(TachSensor& sensor)
266{
Matthew Barth177fe982020-05-26 11:05:19 -0500267 // If this sensor is out of range at this moment, start
268 // its timer, at the end of which the inventory
269 // for the fan may get updated to not functional.
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500270
Matthew Barth177fe982020-05-26 11:05:19 -0500271 // If this sensor is OK, put everything back into a good state.
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500272
273 if (outOfRange(sensor))
274 {
Matthew Barthe11cbc62018-02-20 12:11:07 -0600275 if (sensor.functional())
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500276 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800277 switch (sensor.getMethod())
278 {
279 case MethodMode::timebased:
280 // Start nonfunctional timer if not already running
281 sensor.startTimer(TimerMode::nonfunc);
282 break;
283 case MethodMode::count:
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600284
285 if (!sensor.countTimerRunning())
286 {
287 sensor.startCountTimer();
288 }
Jolie Ku69f2f482020-10-21 09:59:43 +0800289 sensor.setCounter(true);
290 if (sensor.getCounter() >= sensor.getThreshold())
291 {
292 updateState(sensor);
293 }
294 break;
295 }
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500296 }
297 }
298 else
299 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800300 switch (sensor.getMethod())
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500301 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800302 case MethodMode::timebased:
303 if (sensor.functional())
304 {
Matthew Barth11b5d8f2021-01-28 14:04:09 -0600305 if (sensor.timerRunning())
306 {
307 sensor.stopTimer();
308 }
Jolie Ku69f2f482020-10-21 09:59:43 +0800309 }
310 else
311 {
312 // Start functional timer if not already running
313 sensor.startTimer(TimerMode::func);
314 }
315 break;
316 case MethodMode::count:
317 sensor.setCounter(false);
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600318 if (sensor.getCounter() == 0)
Jolie Ku69f2f482020-10-21 09:59:43 +0800319 {
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600320 if (!sensor.functional())
321 {
322 updateState(sensor);
323 }
324
325 sensor.stopCountTimer();
Jolie Ku69f2f482020-10-21 09:59:43 +0800326 }
327 break;
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500328 }
329 }
Matt Spinlerebaae612017-04-27 14:21:48 -0500330}
331
Matthew Barthf552ea52018-01-15 16:22:04 -0600332uint64_t Fan::findTargetSpeed()
Matt Spinlerabf8da32017-04-27 14:08:45 -0500333{
334 uint64_t target = 0;
Matthew Barth177fe982020-05-26 11:05:19 -0500335 // The sensor doesn't support a target,
336 // so get it from another sensor.
Matthew Barthf552ea52018-01-15 16:22:04 -0600337 auto s = std::find_if(_sensors.begin(), _sensors.end(),
Matthew Barth177fe982020-05-26 11:05:19 -0500338 [](const auto& s) { return s->hasTarget(); });
Matt Spinlerabf8da32017-04-27 14:08:45 -0500339
Matthew Barthf552ea52018-01-15 16:22:04 -0600340 if (s != _sensors.end())
Matt Spinlerabf8da32017-04-27 14:08:45 -0500341 {
Matthew Barthf552ea52018-01-15 16:22:04 -0600342 target = (*s)->getTarget();
Matt Spinlerabf8da32017-04-27 14:08:45 -0500343 }
344
345 return target;
346}
347
Mike Cappsce6820a2021-05-26 10:40:19 -0400348size_t Fan::countNonFunctionalSensors() const
Matt Spinlerabf8da32017-04-27 14:08:45 -0500349{
Matthew Barth7c23a042021-01-26 16:21:45 -0600350 return std::count_if(_sensors.begin(), _sensors.end(),
351 [](const auto& s) { return !s->functional(); });
Matt Spinlerabf8da32017-04-27 14:08:45 -0500352}
353
Matt Spinlerabf8da32017-04-27 14:08:45 -0500354bool Fan::outOfRange(const TachSensor& sensor)
355{
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400356 if (!sensor.hasOwner())
Matt Spinlerabf8da32017-04-27 14:08:45 -0500357 {
358 return true;
359 }
360
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400361 auto actual = static_cast<uint64_t>(sensor.getInput());
362 auto range = sensor.getRange(_deviation);
363
Matthew Barth8a8aa442021-11-19 14:13:13 -0600364 return ((actual < range.first) ||
365 (range.second && actual > range.second.value()));
Matt Spinlerabf8da32017-04-27 14:08:45 -0500366}
367
Jolie Ku69f2f482020-10-21 09:59:43 +0800368void Fan::updateState(TachSensor& sensor)
Matt Spinlera9406a72017-04-27 14:29:24 -0500369{
Matt Spinler7d135642021-02-04 12:44:17 -0600370 if (!_system.isPowerOn())
371 {
372 return;
373 }
374
Matthew Barth8a8aa442021-11-19 14:13:13 -0600375 auto range = sensor.getRange(_deviation);
376 std::string rangeMax = "NoMax";
377 if (range.second)
378 {
379 rangeMax = std::to_string(range.second.value());
380 }
381
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500382 // Skip starting the error timer if the sensor
383 // isn't on D-Bus as this isn't a fan hardware problem.
384 sensor.setFunctional(!sensor.functional(), !sensor.hasOwner());
385
386 getLogger().log(fmt::format(
387 "Setting tach sensor {} functional state to {}. "
Matt Spinler466bd222023-01-25 16:15:52 -0600388 "[target = {}, actual = {}, allowed range = ({} - {}) "
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500389 "owned = {}]",
390 sensor.name(), sensor.functional(), sensor.getTarget(),
391 sensor.getInput(), range.first, rangeMax, sensor.hasOwner()));
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500392
393 // A zero value for _numSensorFailsForNonFunc means we aren't dealing
394 // with fan FRU functional status, only sensor functional status.
395 if (_numSensorFailsForNonFunc)
Matthew Barthe11cbc62018-02-20 12:11:07 -0600396 {
Matthew Barth7c23a042021-01-26 16:21:45 -0600397 auto numNonFuncSensors = countNonFunctionalSensors();
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500398 // If the fan was nonfunctional and enough sensors are now OK,
Matthew Barthcceffdd2021-05-20 12:17:21 -0500399 // the fan can be set to functional as long as `set_func_on_present` was
400 // not set
401 if (!_setFuncOnPresent && !_functional &&
402 !(numNonFuncSensors >= _numSensorFailsForNonFunc))
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500403 {
Matthew Barth7c23a042021-01-26 16:21:45 -0600404 getLogger().log(fmt::format("Setting fan {} to functional, number "
405 "of nonfunctional sensors = {}",
406 _name, numNonFuncSensors));
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500407 updateInventory(true);
408 }
Matt Spinlera9406a72017-04-27 14:29:24 -0500409
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500410 // If the fan is currently functional, but too many
411 // contained sensors are now nonfunctional, update
Matthew Barth7c23a042021-01-26 16:21:45 -0600412 // the fan to nonfunctional.
413 if (_functional && (numNonFuncSensors >= _numSensorFailsForNonFunc))
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500414 {
Matthew Barth7c23a042021-01-26 16:21:45 -0600415 getLogger().log(fmt::format("Setting fan {} to nonfunctional, "
416 "number of nonfunctional sensors = {}",
417 _name, numNonFuncSensors));
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500418 updateInventory(false);
419 }
Matt Spinlerb1e18512017-04-27 14:42:33 -0500420 }
Matt Spinlerb63aa092020-10-14 09:45:11 -0500421
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500422 // Skip the power off rule checks if the sensor isn't
423 // on D-Bus so a running system isn't shutdown.
424 _system.fanStatusChange(*this, !sensor.hasOwner());
Matt Spinlera9406a72017-04-27 14:29:24 -0500425}
426
Mike Capps9ff48772021-07-19 14:49:43 -0400427bool Fan::updateInventory(bool functional)
Matt Spinlerb1e18512017-04-27 14:42:33 -0500428{
Mike Capps9ff48772021-07-19 14:49:43 -0400429 bool dbusError = false;
430
431 try
Matt Spinlerb1e18512017-04-27 14:42:33 -0500432 {
Mike Capps9ff48772021-07-19 14:49:43 -0400433 auto objectMap =
434 util::getObjMap<bool>(_name, util::OPERATIONAL_STATUS_INTF,
435 util::FUNCTIONAL_PROPERTY, functional);
436
Mike Capps8af8a622022-02-04 16:13:33 -0500437 auto response = util::SDBusPlus::callMethod(
438 _bus, util::INVENTORY_SVC, util::INVENTORY_PATH,
439 util::INVENTORY_INTF, "Notify", objectMap);
Mike Capps9ff48772021-07-19 14:49:43 -0400440
441 if (response.is_method_error())
442 {
443 log<level::ERR>("Error in Notify call to update inventory");
444
445 dbusError = true;
446 }
447 }
448 catch (const util::DBusError& e)
449 {
450 dbusError = true;
451
452 getLogger().log(
453 fmt::format("D-Bus Exception reading/updating inventory : {}",
454 e.what()),
455 Logger::error);
Matt Spinlerb1e18512017-04-27 14:42:33 -0500456 }
457
Matthew Barth177fe982020-05-26 11:05:19 -0500458 // This will always track the current state of the inventory.
Matt Spinlerb1e18512017-04-27 14:42:33 -0500459 _functional = functional;
Mike Capps9ff48772021-07-19 14:49:43 -0400460
461 return dbusError;
Matt Spinlerb1e18512017-04-27 14:42:33 -0500462}
463
Patrick Williamscb356d42022-07-22 19:26:53 -0500464void Fan::presenceChanged(sdbusplus::message_t& msg)
Matt Spinlerb63aa092020-10-14 09:45:11 -0500465{
466 std::string interface;
467 std::map<std::string, std::variant<bool>> properties;
468
469 msg.read(interface, properties);
470
471 auto presentProp = properties.find("Present");
472 if (presentProp != properties.end())
473 {
474 _present = std::get<bool>(presentProp->second);
475
Matt Spinler27f6b682020-10-27 08:43:37 -0500476 getLogger().log(
Matt Spinlerac372972021-01-25 15:11:22 -0600477 fmt::format("Fan {} presence state change to {}", _name, _present));
Matt Spinler27f6b682020-10-27 08:43:37 -0500478
Matt Spinlera3584bd2021-03-29 15:48:30 -0500479 if (_present && _setFuncOnPresent)
480 {
481 updateInventory(true);
482 std::for_each(_sensors.begin(), _sensors.end(), [](auto& sensor) {
483 sensor->setFunctional(true);
484 sensor->resetMethod();
485 });
486 }
487
Matthew Barth43b4cde2022-02-15 16:30:11 -0600488 _system.fanStatusChange(*this);
489
Matt Spinler27f6b682020-10-27 08:43:37 -0500490 if (_fanMissingErrorDelay)
491 {
Matt Spinler7d135642021-02-04 12:44:17 -0600492 if (!_present && _system.isPowerOn())
Matt Spinler27f6b682020-10-27 08:43:37 -0500493 {
494 _fanMissingErrorTimer->restartOnce(
495 std::chrono::seconds{*_fanMissingErrorDelay});
496 }
Matt Spinler7d135642021-02-04 12:44:17 -0600497 else if (_present && _fanMissingErrorTimer->isEnabled())
Matt Spinler27f6b682020-10-27 08:43:37 -0500498 {
499 _fanMissingErrorTimer->setEnabled(false);
500 }
501 }
Matt Spinlerb63aa092020-10-14 09:45:11 -0500502 }
503}
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500504
505void Fan::sensorErrorTimerExpired(const TachSensor& sensor)
506{
Matt Spinler7d135642021-02-04 12:44:17 -0600507 if (_present && _system.isPowerOn())
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500508 {
509 _system.sensorErrorTimerExpired(*this, sensor);
510 }
511}
512
Mike Capps808d7fe2022-06-13 10:12:16 -0400513void Fan::powerStateChanged([[maybe_unused]] bool powerStateOn)
Matt Spinler7d135642021-02-04 12:44:17 -0600514{
515#ifdef MONITOR_USE_JSON
516 if (powerStateOn)
517 {
Matt Spinler7d135642021-02-04 12:44:17 -0600518 _monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay));
519
Matt Spinlerbb449c12021-06-14 11:45:28 -0600520 _numSensorsOnDBusAtPowerOn = 0;
521
522 std::for_each(_sensors.begin(), _sensors.end(), [this](auto& sensor) {
523 try
524 {
525 // Force a getProperty call. If sensor is on D-Bus,
526 // then make sure it's functional.
527 sensor->updateTachAndTarget();
528
529 _numSensorsOnDBusAtPowerOn++;
530
531 if (_present)
532 {
533 // If not functional, set it back to functional.
534 if (!sensor->functional())
535 {
536 sensor->setFunctional(true);
537 _system.fanStatusChange(*this, true);
538 }
539
540 // Set the counters back to zero
541 if (sensor->getMethod() == MethodMode::count)
542 {
543 sensor->resetMethod();
544 }
545 }
546 }
547 catch (const util::DBusError& e)
548 {
549 // Properties still aren't on D-Bus. Let startMonitor()
550 // deal with it, or maybe System::powerStateChanged() if
551 // there aren't any sensors at all on D-Bus.
552 getLogger().log(fmt::format(
553 "At power on, tach sensor {} value not on D-Bus",
554 sensor->name()));
555 }
556 });
557
Matt Spinler4283c5d2021-03-01 15:56:00 -0600558 if (_present)
559 {
Matt Spinler4283c5d2021-03-01 15:56:00 -0600560 // If configured to change functional state on the fan itself,
561 // Set it back to true now if necessary.
562 if (_numSensorFailsForNonFunc)
563 {
564 if (!_functional &&
565 (countNonFunctionalSensors() < _numSensorFailsForNonFunc))
566 {
567 updateInventory(true);
568 }
569 }
570 }
571 else
Matt Spinler7d135642021-02-04 12:44:17 -0600572 {
573 getLogger().log(
574 fmt::format("At power on, fan {} is missing", _name));
575
576 if (_fanMissingErrorTimer)
577 {
578 _fanMissingErrorTimer->restartOnce(
579 std::chrono::seconds{*_fanMissingErrorDelay});
580 }
581 }
582 }
583 else
584 {
585 _monitorReady = false;
586
587 if (_monitorTimer.isEnabled())
588 {
589 _monitorTimer.setEnabled(false);
590 }
591
592 if (_fanMissingErrorTimer && _fanMissingErrorTimer->isEnabled())
593 {
594 _fanMissingErrorTimer->setEnabled(false);
595 }
596
597 std::for_each(_sensors.begin(), _sensors.end(), [](auto& sensor) {
598 if (sensor->timerRunning())
599 {
600 sensor->stopTimer();
601 }
Matt Spinler623635c2021-03-29 13:13:59 -0500602
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600603 sensor->stopCountTimer();
604 });
Matt Spinler7d135642021-02-04 12:44:17 -0600605 }
606#endif
607}
608
Matthew Barth177fe982020-05-26 11:05:19 -0500609} // namespace monitor
610} // namespace fan
611} // namespace phosphor