blob: 94bfcf849d4a4c9f6132ead5383209d560af987a [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),
42 _name(std::get<fanNameField>(def)),
43 _deviation(std::get<fanDeviationField>(def)),
Matt Spinlerc39e8592017-09-28 13:13:08 -050044 _numSensorFailsForNonFunc(std::get<numSensorFailsForNonfuncField>(def)),
Matt Spinlerb0412d02020-10-12 16:53:52 -050045 _trustManager(trust),
46#ifdef MONITOR_USE_JSON
47 _monitorDelay(std::get<monitorStartDelayField>(def)),
48 _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 Spinler623635c2021-03-29 13:13:59 -050062 _fanMissingErrorDelay(std::get<fanMissingErrDelayField>(def)),
Matt Spinlera3584bd2021-03-29 15:48:30 -050063 _setFuncOnPresent(std::get<funcOnPresentField>(def))
Matt Spinlerabf8da32017-04-27 14:08:45 -050064{
Matthew Barth0a9fe162018-01-26 12:53:15 -060065 // Setup tach sensors for monitoring
66 auto& sensors = std::get<sensorListField>(def);
67 for (auto& s : sensors)
68 {
Matt Spinler4283c5d2021-03-01 15:56:00 -060069 _sensors.emplace_back(std::make_shared<TachSensor>(
70 mode, bus, *this, std::get<sensorNameField>(s),
71 std::get<hasTargetField>(s), std::get<funcDelay>(def),
Chau Ly27cc39f2022-09-20 08:16:56 +000072 std::get<targetInterfaceField>(s), std::get<targetPathField>(s),
73 std::get<factorField>(s), std::get<offsetField>(s),
74 std::get<methodField>(def), std::get<thresholdField>(s),
75 std::get<ignoreAboveMaxField>(s), std::get<timeoutField>(def),
Matt Spinlerfdfcc672021-06-01 14:51:06 -060076 std::get<nonfuncRotorErrDelayField>(def),
77 std::get<countIntervalField>(def), event));
Matthew Barth0a9fe162018-01-26 12:53:15 -060078
Matt Spinler4283c5d2021-03-01 15:56:00 -060079 _trustManager->registerSensor(_sensors.back());
Matthew Barth0a9fe162018-01-26 12:53:15 -060080 }
81
Mike Cappsce6820a2021-05-26 10:40:19 -040082 bool functionalState =
83 (_numSensorFailsForNonFunc == 0) ||
84 (countNonFunctionalSensors() < _numSensorFailsForNonFunc);
85
Mike Capps9ff48772021-07-19 14:49:43 -040086 if (updateInventory(functionalState) && !functionalState)
87 {
88 // the inventory update threw an exception, possibly because D-Bus
89 // wasn't ready. Try to update sensors back to functional to avoid a
90 // false-alarm. They will be updated again from subscribing to the
91 // properties-changed event
92
93 for (auto& sensor : _sensors)
94 sensor->setFunctional(true);
95 }
Mike Cappsce6820a2021-05-26 10:40:19 -040096
Matt Spinlerb0412d02020-10-12 16:53:52 -050097#ifndef MONITOR_USE_JSON
Matthew Barth0a9fe162018-01-26 12:53:15 -060098 // Check current tach state when entering monitor mode
Matthew Barth6ad28432017-08-22 11:18:19 -050099 if (mode != Mode::init)
100 {
Matt Spinlerb0412d02020-10-12 16:53:52 -0500101 _monitorReady = true;
102
Matthew Barth177fe982020-05-26 11:05:19 -0500103 // The TachSensors will now have already read the input
104 // and target values, so check them.
Matthew Barth6ad28432017-08-22 11:18:19 -0500105 tachChanged();
106 }
Matt Spinlerb0412d02020-10-12 16:53:52 -0500107#else
Matt Spinler7d135642021-02-04 12:44:17 -0600108 if (_system.isPowerOn())
109 {
110 _monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay));
111 }
Matt Spinlerb0412d02020-10-12 16:53:52 -0500112#endif
Matt Spinlerb63aa092020-10-14 09:45:11 -0500113
Matt Spinler27f6b682020-10-27 08:43:37 -0500114 if (_fanMissingErrorDelay)
115 {
116 _fanMissingErrorTimer = std::make_unique<
117 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>(
118 event, std::bind(&System::fanMissingErrorTimerExpired, &system,
119 std::ref(*this)));
Matt Spinler7d135642021-02-04 12:44:17 -0600120 }
Matt Spinler27f6b682020-10-27 08:43:37 -0500121
Matt Spinler7d135642021-02-04 12:44:17 -0600122 try
123 {
124 _present = util::SDBusPlus::getProperty<bool>(
125 util::INVENTORY_PATH + _name, util::INV_ITEM_IFACE, "Present");
126
127 if (!_present)
Matt Spinler27f6b682020-10-27 08:43:37 -0500128 {
Matt Spinlerac372972021-01-25 15:11:22 -0600129 getLogger().log(
130 fmt::format("On startup, fan {} is missing", _name));
Matt Spinler7d135642021-02-04 12:44:17 -0600131 if (_system.isPowerOn() && _fanMissingErrorTimer)
132 {
133 _fanMissingErrorTimer->restartOnce(
134 std::chrono::seconds{*_fanMissingErrorDelay});
135 }
136 }
137 }
138 catch (const util::DBusServiceError& e)
139 {
140 // This could happen on the first BMC boot if the presence
141 // detect app hasn't started yet and there isn't an inventory
142 // cache yet.
143 }
144}
145
Patrick Williamscb356d42022-07-22 19:26:53 -0500146void Fan::presenceIfaceAdded(sdbusplus::message_t& msg)
Matt Spinler7d135642021-02-04 12:44:17 -0600147{
148 sdbusplus::message::object_path path;
149 std::map<std::string, std::map<std::string, std::variant<bool>>> interfaces;
150
151 msg.read(path, interfaces);
152
153 auto properties = interfaces.find(util::INV_ITEM_IFACE);
154 if (properties == interfaces.end())
155 {
156 return;
157 }
158
159 auto property = properties->second.find("Present");
160 if (property == properties->second.end())
161 {
162 return;
163 }
164
165 _present = std::get<bool>(property->second);
166
167 if (!_present)
168 {
169 getLogger().log(fmt::format(
170 "New fan {} interface added and fan is not present", _name));
171 if (_system.isPowerOn() && _fanMissingErrorTimer)
172 {
Matt Spinler27f6b682020-10-27 08:43:37 -0500173 _fanMissingErrorTimer->restartOnce(
174 std::chrono::seconds{*_fanMissingErrorDelay});
175 }
176 }
Matt Spinler7d135642021-02-04 12:44:17 -0600177
178 _system.fanStatusChange(*this);
Matt Spinlerb0412d02020-10-12 16:53:52 -0500179}
180
181void Fan::startMonitor()
182{
183 _monitorReady = true;
184
Matt Spinler4283c5d2021-03-01 15:56:00 -0600185 std::for_each(_sensors.begin(), _sensors.end(), [this](auto& sensor) {
186 if (_present)
187 {
188 try
189 {
190 // Force a getProperty call to check if the tach sensor is
191 // on D-Bus. If it isn't, now set it to nonfunctional.
192 // This isn't done earlier so that code watching for
193 // nonfunctional tach sensors doesn't take actions before
194 // those sensors show up on D-Bus.
195 sensor->updateTachAndTarget();
196 tachChanged(*sensor);
197 }
198 catch (const util::DBusServiceError& e)
199 {
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500200 // The tach property still isn't on D-Bus. Ensure
201 // sensor is nonfunctional, but skip creating an
202 // error for it since it isn't a fan problem.
Matt Spinler4283c5d2021-03-01 15:56:00 -0600203 getLogger().log(fmt::format(
204 "Monitoring starting but {} sensor value not on D-Bus",
205 sensor->name()));
206
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500207 sensor->setFunctional(false, true);
Matt Spinler4283c5d2021-03-01 15:56:00 -0600208
209 if (_numSensorFailsForNonFunc)
210 {
211 if (_functional && (countNonFunctionalSensors() >=
212 _numSensorFailsForNonFunc))
213 {
214 updateInventory(false);
215 }
216 }
217
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500218 // At this point, don't start any power off actions due
219 // to missing sensors. Let something else handle that
220 // policy.
221 _system.fanStatusChange(*this, true);
Matt Spinler4283c5d2021-03-01 15:56:00 -0600222 }
223 }
224 });
Matt Spinlerabf8da32017-04-27 14:08:45 -0500225}
226
Matt Spinlerebaae612017-04-27 14:21:48 -0500227void Fan::tachChanged()
228{
Matt Spinlerb0412d02020-10-12 16:53:52 -0500229 if (_monitorReady)
Matt Spinlerebaae612017-04-27 14:21:48 -0500230 {
Matt Spinlerb0412d02020-10-12 16:53:52 -0500231 for (auto& s : _sensors)
232 {
233 tachChanged(*s);
234 }
Matt Spinlerebaae612017-04-27 14:21:48 -0500235 }
236}
237
Matt Spinlerebaae612017-04-27 14:21:48 -0500238void Fan::tachChanged(TachSensor& sensor)
239{
Matt Spinler7d135642021-02-04 12:44:17 -0600240 if (!_system.isPowerOn() || !_monitorReady)
241 {
242 return;
243 }
244
Matt Spinlerc39e8592017-09-28 13:13:08 -0500245 if (_trustManager->active())
246 {
247 if (!_trustManager->checkTrust(sensor))
248 {
249 return;
250 }
251 }
252
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600253 // If the error checking method is 'count', if a tach change leads
254 // to an out of range sensor the count timer will take over in calling
255 // process() until the sensor is healthy again.
256 if (!sensor.countTimerRunning())
Matt Spinler623635c2021-03-29 13:13:59 -0500257 {
258 process(sensor);
259 }
260}
261
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600262void Fan::countTimerExpired(TachSensor& sensor)
Matt Spinler623635c2021-03-29 13:13:59 -0500263{
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600264 if (_trustManager->active() && !_trustManager->checkTrust(sensor))
Matt Spinler623635c2021-03-29 13:13:59 -0500265 {
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600266 return;
Matt Spinler623635c2021-03-29 13:13:59 -0500267 }
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600268 process(sensor);
Matthew Barthfcb0dbc2021-02-10 14:23:39 -0600269}
270
271void Fan::process(TachSensor& sensor)
272{
Matthew Barth177fe982020-05-26 11:05:19 -0500273 // If this sensor is out of range at this moment, start
274 // its timer, at the end of which the inventory
275 // for the fan may get updated to not functional.
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500276
Matthew Barth177fe982020-05-26 11:05:19 -0500277 // If this sensor is OK, put everything back into a good state.
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500278
279 if (outOfRange(sensor))
280 {
Matthew Barthe11cbc62018-02-20 12:11:07 -0600281 if (sensor.functional())
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500282 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800283 switch (sensor.getMethod())
284 {
285 case MethodMode::timebased:
286 // Start nonfunctional timer if not already running
287 sensor.startTimer(TimerMode::nonfunc);
288 break;
289 case MethodMode::count:
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600290
291 if (!sensor.countTimerRunning())
292 {
293 sensor.startCountTimer();
294 }
Jolie Ku69f2f482020-10-21 09:59:43 +0800295 sensor.setCounter(true);
296 if (sensor.getCounter() >= sensor.getThreshold())
297 {
298 updateState(sensor);
299 }
300 break;
301 }
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500302 }
303 }
304 else
305 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800306 switch (sensor.getMethod())
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500307 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800308 case MethodMode::timebased:
309 if (sensor.functional())
310 {
Matthew Barth11b5d8f2021-01-28 14:04:09 -0600311 if (sensor.timerRunning())
312 {
313 sensor.stopTimer();
314 }
Jolie Ku69f2f482020-10-21 09:59:43 +0800315 }
316 else
317 {
318 // Start functional timer if not already running
319 sensor.startTimer(TimerMode::func);
320 }
321 break;
322 case MethodMode::count:
323 sensor.setCounter(false);
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600324 if (sensor.getCounter() == 0)
Jolie Ku69f2f482020-10-21 09:59:43 +0800325 {
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600326 if (!sensor.functional())
327 {
328 updateState(sensor);
329 }
330
331 sensor.stopCountTimer();
Jolie Ku69f2f482020-10-21 09:59:43 +0800332 }
333 break;
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500334 }
335 }
Matt Spinlerebaae612017-04-27 14:21:48 -0500336}
337
Matthew Barthf552ea52018-01-15 16:22:04 -0600338uint64_t Fan::findTargetSpeed()
Matt Spinlerabf8da32017-04-27 14:08:45 -0500339{
340 uint64_t target = 0;
Matthew Barth177fe982020-05-26 11:05:19 -0500341 // The sensor doesn't support a target,
342 // so get it from another sensor.
Matthew Barthf552ea52018-01-15 16:22:04 -0600343 auto s = std::find_if(_sensors.begin(), _sensors.end(),
Matthew Barth177fe982020-05-26 11:05:19 -0500344 [](const auto& s) { return s->hasTarget(); });
Matt Spinlerabf8da32017-04-27 14:08:45 -0500345
Matthew Barthf552ea52018-01-15 16:22:04 -0600346 if (s != _sensors.end())
Matt Spinlerabf8da32017-04-27 14:08:45 -0500347 {
Matthew Barthf552ea52018-01-15 16:22:04 -0600348 target = (*s)->getTarget();
Matt Spinlerabf8da32017-04-27 14:08:45 -0500349 }
350
351 return target;
352}
353
Mike Cappsce6820a2021-05-26 10:40:19 -0400354size_t Fan::countNonFunctionalSensors() const
Matt Spinlerabf8da32017-04-27 14:08:45 -0500355{
Matthew Barth7c23a042021-01-26 16:21:45 -0600356 return std::count_if(_sensors.begin(), _sensors.end(),
357 [](const auto& s) { return !s->functional(); });
Matt Spinlerabf8da32017-04-27 14:08:45 -0500358}
359
Matt Spinlerabf8da32017-04-27 14:08:45 -0500360bool Fan::outOfRange(const TachSensor& sensor)
361{
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400362 if (!sensor.hasOwner())
Matt Spinlerabf8da32017-04-27 14:08:45 -0500363 {
364 return true;
365 }
366
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400367 auto actual = static_cast<uint64_t>(sensor.getInput());
368 auto range = sensor.getRange(_deviation);
369
Matthew Barth8a8aa442021-11-19 14:13:13 -0600370 return ((actual < range.first) ||
371 (range.second && actual > range.second.value()));
Matt Spinlerabf8da32017-04-27 14:08:45 -0500372}
373
Jolie Ku69f2f482020-10-21 09:59:43 +0800374void Fan::updateState(TachSensor& sensor)
Matt Spinlera9406a72017-04-27 14:29:24 -0500375{
Matt Spinler7d135642021-02-04 12:44:17 -0600376 if (!_system.isPowerOn())
377 {
378 return;
379 }
380
Matthew Barth8a8aa442021-11-19 14:13:13 -0600381 auto range = sensor.getRange(_deviation);
382 std::string rangeMax = "NoMax";
383 if (range.second)
384 {
385 rangeMax = std::to_string(range.second.value());
386 }
387
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500388 // Skip starting the error timer if the sensor
389 // isn't on D-Bus as this isn't a fan hardware problem.
390 sensor.setFunctional(!sensor.functional(), !sensor.hasOwner());
391
392 getLogger().log(fmt::format(
393 "Setting tach sensor {} functional state to {}. "
394 "[target = {}, input = {}, allowed range = ({} - {}) "
395 "owned = {}]",
396 sensor.name(), sensor.functional(), sensor.getTarget(),
397 sensor.getInput(), range.first, rangeMax, sensor.hasOwner()));
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500398
399 // A zero value for _numSensorFailsForNonFunc means we aren't dealing
400 // with fan FRU functional status, only sensor functional status.
401 if (_numSensorFailsForNonFunc)
Matthew Barthe11cbc62018-02-20 12:11:07 -0600402 {
Matthew Barth7c23a042021-01-26 16:21:45 -0600403 auto numNonFuncSensors = countNonFunctionalSensors();
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500404 // If the fan was nonfunctional and enough sensors are now OK,
Matthew Barthcceffdd2021-05-20 12:17:21 -0500405 // the fan can be set to functional as long as `set_func_on_present` was
406 // not set
407 if (!_setFuncOnPresent && !_functional &&
408 !(numNonFuncSensors >= _numSensorFailsForNonFunc))
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500409 {
Matthew Barth7c23a042021-01-26 16:21:45 -0600410 getLogger().log(fmt::format("Setting fan {} to functional, number "
411 "of nonfunctional sensors = {}",
412 _name, numNonFuncSensors));
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500413 updateInventory(true);
414 }
Matt Spinlera9406a72017-04-27 14:29:24 -0500415
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500416 // If the fan is currently functional, but too many
417 // contained sensors are now nonfunctional, update
Matthew Barth7c23a042021-01-26 16:21:45 -0600418 // the fan to nonfunctional.
419 if (_functional && (numNonFuncSensors >= _numSensorFailsForNonFunc))
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500420 {
Matthew Barth7c23a042021-01-26 16:21:45 -0600421 getLogger().log(fmt::format("Setting fan {} to nonfunctional, "
422 "number of nonfunctional sensors = {}",
423 _name, numNonFuncSensors));
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500424 updateInventory(false);
425 }
Matt Spinlerb1e18512017-04-27 14:42:33 -0500426 }
Matt Spinlerb63aa092020-10-14 09:45:11 -0500427
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500428 // Skip the power off rule checks if the sensor isn't
429 // on D-Bus so a running system isn't shutdown.
430 _system.fanStatusChange(*this, !sensor.hasOwner());
Matt Spinlera9406a72017-04-27 14:29:24 -0500431}
432
Mike Capps9ff48772021-07-19 14:49:43 -0400433bool Fan::updateInventory(bool functional)
Matt Spinlerb1e18512017-04-27 14:42:33 -0500434{
Mike Capps9ff48772021-07-19 14:49:43 -0400435 bool dbusError = false;
436
437 try
Matt Spinlerb1e18512017-04-27 14:42:33 -0500438 {
Mike Capps9ff48772021-07-19 14:49:43 -0400439 auto objectMap =
440 util::getObjMap<bool>(_name, util::OPERATIONAL_STATUS_INTF,
441 util::FUNCTIONAL_PROPERTY, functional);
442
Mike Capps8af8a622022-02-04 16:13:33 -0500443 auto response = util::SDBusPlus::callMethod(
444 _bus, util::INVENTORY_SVC, util::INVENTORY_PATH,
445 util::INVENTORY_INTF, "Notify", objectMap);
Mike Capps9ff48772021-07-19 14:49:43 -0400446
447 if (response.is_method_error())
448 {
449 log<level::ERR>("Error in Notify call to update inventory");
450
451 dbusError = true;
452 }
453 }
454 catch (const util::DBusError& e)
455 {
456 dbusError = true;
457
458 getLogger().log(
459 fmt::format("D-Bus Exception reading/updating inventory : {}",
460 e.what()),
461 Logger::error);
Matt Spinlerb1e18512017-04-27 14:42:33 -0500462 }
463
Matthew Barth177fe982020-05-26 11:05:19 -0500464 // This will always track the current state of the inventory.
Matt Spinlerb1e18512017-04-27 14:42:33 -0500465 _functional = functional;
Mike Capps9ff48772021-07-19 14:49:43 -0400466
467 return dbusError;
Matt Spinlerb1e18512017-04-27 14:42:33 -0500468}
469
Patrick Williamscb356d42022-07-22 19:26:53 -0500470void Fan::presenceChanged(sdbusplus::message_t& msg)
Matt Spinlerb63aa092020-10-14 09:45:11 -0500471{
472 std::string interface;
473 std::map<std::string, std::variant<bool>> properties;
474
475 msg.read(interface, properties);
476
477 auto presentProp = properties.find("Present");
478 if (presentProp != properties.end())
479 {
480 _present = std::get<bool>(presentProp->second);
481
Matt Spinler27f6b682020-10-27 08:43:37 -0500482 getLogger().log(
Matt Spinlerac372972021-01-25 15:11:22 -0600483 fmt::format("Fan {} presence state change to {}", _name, _present));
Matt Spinler27f6b682020-10-27 08:43:37 -0500484
Matt Spinlera3584bd2021-03-29 15:48:30 -0500485 if (_present && _setFuncOnPresent)
486 {
487 updateInventory(true);
488 std::for_each(_sensors.begin(), _sensors.end(), [](auto& sensor) {
489 sensor->setFunctional(true);
490 sensor->resetMethod();
491 });
492 }
493
Matthew Barth43b4cde2022-02-15 16:30:11 -0600494 _system.fanStatusChange(*this);
495
Matt Spinler27f6b682020-10-27 08:43:37 -0500496 if (_fanMissingErrorDelay)
497 {
Matt Spinler7d135642021-02-04 12:44:17 -0600498 if (!_present && _system.isPowerOn())
Matt Spinler27f6b682020-10-27 08:43:37 -0500499 {
500 _fanMissingErrorTimer->restartOnce(
501 std::chrono::seconds{*_fanMissingErrorDelay});
502 }
Matt Spinler7d135642021-02-04 12:44:17 -0600503 else if (_present && _fanMissingErrorTimer->isEnabled())
Matt Spinler27f6b682020-10-27 08:43:37 -0500504 {
505 _fanMissingErrorTimer->setEnabled(false);
506 }
507 }
Matt Spinlerb63aa092020-10-14 09:45:11 -0500508 }
509}
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500510
511void Fan::sensorErrorTimerExpired(const TachSensor& sensor)
512{
Matt Spinler7d135642021-02-04 12:44:17 -0600513 if (_present && _system.isPowerOn())
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500514 {
515 _system.sensorErrorTimerExpired(*this, sensor);
516 }
517}
518
Mike Capps808d7fe2022-06-13 10:12:16 -0400519void Fan::powerStateChanged([[maybe_unused]] bool powerStateOn)
Matt Spinler7d135642021-02-04 12:44:17 -0600520{
521#ifdef MONITOR_USE_JSON
522 if (powerStateOn)
523 {
Matt Spinler7d135642021-02-04 12:44:17 -0600524 _monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay));
525
Matt Spinlerbb449c12021-06-14 11:45:28 -0600526 _numSensorsOnDBusAtPowerOn = 0;
527
528 std::for_each(_sensors.begin(), _sensors.end(), [this](auto& sensor) {
529 try
530 {
531 // Force a getProperty call. If sensor is on D-Bus,
532 // then make sure it's functional.
533 sensor->updateTachAndTarget();
534
535 _numSensorsOnDBusAtPowerOn++;
536
537 if (_present)
538 {
539 // If not functional, set it back to functional.
540 if (!sensor->functional())
541 {
542 sensor->setFunctional(true);
543 _system.fanStatusChange(*this, true);
544 }
545
546 // Set the counters back to zero
547 if (sensor->getMethod() == MethodMode::count)
548 {
549 sensor->resetMethod();
550 }
551 }
552 }
553 catch (const util::DBusError& e)
554 {
555 // Properties still aren't on D-Bus. Let startMonitor()
556 // deal with it, or maybe System::powerStateChanged() if
557 // there aren't any sensors at all on D-Bus.
558 getLogger().log(fmt::format(
559 "At power on, tach sensor {} value not on D-Bus",
560 sensor->name()));
561 }
562 });
563
Matt Spinler4283c5d2021-03-01 15:56:00 -0600564 if (_present)
565 {
Matt Spinler4283c5d2021-03-01 15:56:00 -0600566 // If configured to change functional state on the fan itself,
567 // Set it back to true now if necessary.
568 if (_numSensorFailsForNonFunc)
569 {
570 if (!_functional &&
571 (countNonFunctionalSensors() < _numSensorFailsForNonFunc))
572 {
573 updateInventory(true);
574 }
575 }
576 }
577 else
Matt Spinler7d135642021-02-04 12:44:17 -0600578 {
579 getLogger().log(
580 fmt::format("At power on, fan {} is missing", _name));
581
582 if (_fanMissingErrorTimer)
583 {
584 _fanMissingErrorTimer->restartOnce(
585 std::chrono::seconds{*_fanMissingErrorDelay});
586 }
587 }
588 }
589 else
590 {
591 _monitorReady = false;
592
593 if (_monitorTimer.isEnabled())
594 {
595 _monitorTimer.setEnabled(false);
596 }
597
598 if (_fanMissingErrorTimer && _fanMissingErrorTimer->isEnabled())
599 {
600 _fanMissingErrorTimer->setEnabled(false);
601 }
602
603 std::for_each(_sensors.begin(), _sensors.end(), [](auto& sensor) {
604 if (sensor->timerRunning())
605 {
606 sensor->stopTimer();
607 }
Matt Spinler623635c2021-03-29 13:13:59 -0500608
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600609 sensor->stopCountTimer();
610 });
Matt Spinler7d135642021-02-04 12:44:17 -0600611 }
612#endif
613}
614
Matthew Barth177fe982020-05-26 11:05:19 -0500615} // namespace monitor
616} // namespace fan
617} // namespace phosphor