blob: f2f562c7392ebe83942d83b3af1a32fd828cf7cc [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
Anwaar Hadia00f6832025-03-27 15:03:11 +000024#include <phosphor-logging/lg2.hpp>
Matthew Barth177fe982020-05-26 11:05:19 -050025
Patrick Williamsfbf47032023-07-17 12:27:34 -050026#include <format>
27
Matt Spinlerabf8da32017-04-27 14:08:45 -050028namespace phosphor
29{
30namespace fan
31{
32namespace monitor
33{
34
Matt Spinlerb0412d02020-10-12 16:53:52 -050035using namespace sdbusplus::bus::match;
Matt Spinlerabf8da32017-04-27 14:08:45 -050036
Patrick Williamscb356d42022-07-22 19:26:53 -050037Fan::Fan(Mode mode, sdbusplus::bus_t& bus, const sdeventplus::Event& event,
Matt Spinlerb0412d02020-10-12 16:53:52 -050038 std::unique_ptr<trust::Manager>& trust, const FanDefinition& def,
39 System& system) :
Patrick Williamsdfddd642024-08-16 15:21:51 -040040 _bus(bus), _name(def.name), _deviation(def.deviation),
Matt Spinlerf724c162023-05-10 11:14:37 -050041 _upperDeviation(def.upperDeviation),
Matt Spinler18fb12b2023-05-09 11:17:42 -050042 _numSensorFailsForNonFunc(def.numSensorFailsForNonfunc),
Matt Spinlerb0412d02020-10-12 16:53:52 -050043 _trustManager(trust),
44#ifdef MONITOR_USE_JSON
Matt Spinler18fb12b2023-05-09 11:17:42 -050045 _monitorDelay(def.monitorStartDelay),
Matt Spinlerb0412d02020-10-12 16:53:52 -050046 _monitorTimer(event, std::bind(std::mem_fn(&Fan::startMonitor), this)),
47#endif
Matt Spinlerb63aa092020-10-14 09:45:11 -050048 _system(system),
49 _presenceMatch(bus,
50 rules::propertiesChanged(util::INVENTORY_PATH + _name,
51 util::INV_ITEM_IFACE),
52 std::bind(std::mem_fn(&Fan::presenceChanged), this,
Matt Spinler27f6b682020-10-27 08:43:37 -050053 std::placeholders::_1)),
Matt Spinler7d135642021-02-04 12:44:17 -060054 _presenceIfaceAddedMatch(
55 bus,
56 rules::interfacesAdded() +
57 rules::argNpath(0, util::INVENTORY_PATH + _name),
58 std::bind(std::mem_fn(&Fan::presenceIfaceAdded), this,
59 std::placeholders::_1)),
Matt Spinler18fb12b2023-05-09 11:17:42 -050060 _fanMissingErrorDelay(def.fanMissingErrDelay),
61 _setFuncOnPresent(def.funcOnPresent)
Matt Spinlerabf8da32017-04-27 14:08:45 -050062{
Matthew Barth0a9fe162018-01-26 12:53:15 -060063 // Setup tach sensors for monitoring
Matt Spinler18fb12b2023-05-09 11:17:42 -050064 for (const auto& s : def.sensorList)
Matthew Barth0a9fe162018-01-26 12:53:15 -060065 {
Matt Spinler4283c5d2021-03-01 15:56:00 -060066 _sensors.emplace_back(std::make_shared<TachSensor>(
Matt Spinler18fb12b2023-05-09 11:17:42 -050067 mode, bus, *this, s.name, s.hasTarget, def.funcDelay,
68 s.targetInterface, s.targetPath, s.factor, s.offset, def.method,
69 s.threshold, s.ignoreAboveMax, def.timeout,
70 def.nonfuncRotorErrDelay, def.countInterval, event));
Matthew Barth0a9fe162018-01-26 12:53:15 -060071
Matt Spinler4283c5d2021-03-01 15:56:00 -060072 _trustManager->registerSensor(_sensors.back());
Matthew Barth0a9fe162018-01-26 12:53:15 -060073 }
74
Mike Cappsce6820a2021-05-26 10:40:19 -040075 bool functionalState =
76 (_numSensorFailsForNonFunc == 0) ||
77 (countNonFunctionalSensors() < _numSensorFailsForNonFunc);
78
Mike Capps9ff48772021-07-19 14:49:43 -040079 if (updateInventory(functionalState) && !functionalState)
80 {
81 // the inventory update threw an exception, possibly because D-Bus
82 // wasn't ready. Try to update sensors back to functional to avoid a
83 // false-alarm. They will be updated again from subscribing to the
84 // properties-changed event
85
86 for (auto& sensor : _sensors)
87 sensor->setFunctional(true);
88 }
Mike Cappsce6820a2021-05-26 10:40:19 -040089
Matt Spinlerb0412d02020-10-12 16:53:52 -050090#ifndef MONITOR_USE_JSON
Matthew Barth0a9fe162018-01-26 12:53:15 -060091 // Check current tach state when entering monitor mode
Matthew Barth6ad28432017-08-22 11:18:19 -050092 if (mode != Mode::init)
93 {
Matt Spinlerb0412d02020-10-12 16:53:52 -050094 _monitorReady = true;
95
Matthew Barth177fe982020-05-26 11:05:19 -050096 // The TachSensors will now have already read the input
97 // and target values, so check them.
Matthew Barth6ad28432017-08-22 11:18:19 -050098 tachChanged();
99 }
Matt Spinlerb0412d02020-10-12 16:53:52 -0500100#else
Matt Spinler7d135642021-02-04 12:44:17 -0600101 if (_system.isPowerOn())
102 {
103 _monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay));
104 }
Matt Spinlerb0412d02020-10-12 16:53:52 -0500105#endif
Matt Spinlerb63aa092020-10-14 09:45:11 -0500106
Matt Spinler27f6b682020-10-27 08:43:37 -0500107 if (_fanMissingErrorDelay)
108 {
109 _fanMissingErrorTimer = std::make_unique<
110 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>(
111 event, std::bind(&System::fanMissingErrorTimerExpired, &system,
112 std::ref(*this)));
Matt Spinler7d135642021-02-04 12:44:17 -0600113 }
Matt Spinler27f6b682020-10-27 08:43:37 -0500114
Matt Spinler7d135642021-02-04 12:44:17 -0600115 try
116 {
117 _present = util::SDBusPlus::getProperty<bool>(
118 util::INVENTORY_PATH + _name, util::INV_ITEM_IFACE, "Present");
119
120 if (!_present)
Matt Spinler27f6b682020-10-27 08:43:37 -0500121 {
Matt Spinlerac372972021-01-25 15:11:22 -0600122 getLogger().log(
Patrick Williamsfbf47032023-07-17 12:27:34 -0500123 std::format("On startup, fan {} is missing", _name));
Matt Spinler7d135642021-02-04 12:44:17 -0600124 if (_system.isPowerOn() && _fanMissingErrorTimer)
125 {
126 _fanMissingErrorTimer->restartOnce(
127 std::chrono::seconds{*_fanMissingErrorDelay});
128 }
129 }
130 }
131 catch (const util::DBusServiceError& e)
132 {
133 // This could happen on the first BMC boot if the presence
134 // detect app hasn't started yet and there isn't an inventory
135 // cache yet.
136 }
137}
138
Patrick Williamscb356d42022-07-22 19:26:53 -0500139void Fan::presenceIfaceAdded(sdbusplus::message_t& msg)
Matt Spinler7d135642021-02-04 12:44:17 -0600140{
141 sdbusplus::message::object_path path;
142 std::map<std::string, std::map<std::string, std::variant<bool>>> interfaces;
143
144 msg.read(path, interfaces);
145
146 auto properties = interfaces.find(util::INV_ITEM_IFACE);
147 if (properties == interfaces.end())
148 {
149 return;
150 }
151
152 auto property = properties->second.find("Present");
153 if (property == properties->second.end())
154 {
155 return;
156 }
157
158 _present = std::get<bool>(property->second);
159
160 if (!_present)
161 {
Patrick Williamsfbf47032023-07-17 12:27:34 -0500162 getLogger().log(std::format(
Matt Spinler7d135642021-02-04 12:44:17 -0600163 "New fan {} interface added and fan is not present", _name));
164 if (_system.isPowerOn() && _fanMissingErrorTimer)
165 {
Matt Spinler27f6b682020-10-27 08:43:37 -0500166 _fanMissingErrorTimer->restartOnce(
167 std::chrono::seconds{*_fanMissingErrorDelay});
168 }
169 }
Matt Spinler7d135642021-02-04 12:44:17 -0600170
171 _system.fanStatusChange(*this);
Matt Spinlerb0412d02020-10-12 16:53:52 -0500172}
173
174void Fan::startMonitor()
175{
176 _monitorReady = true;
177
Matt Spinler4283c5d2021-03-01 15:56:00 -0600178 std::for_each(_sensors.begin(), _sensors.end(), [this](auto& sensor) {
Matt Spinler3494a572023-11-28 12:45:32 -0600179 try
Matt Spinler4283c5d2021-03-01 15:56:00 -0600180 {
Matt Spinler3494a572023-11-28 12:45:32 -0600181 // Force a getProperty call to check if the tach sensor is
182 // on D-Bus. If it isn't, now set it to nonfunctional.
183 // This isn't done earlier so that code watching for
184 // nonfunctional tach sensors doesn't take actions before
185 // those sensors show up on D-Bus.
186 sensor->updateTachAndTarget();
187 tachChanged(*sensor);
188 }
189 catch (const util::DBusServiceError& e)
190 {
191 // The tach property still isn't on D-Bus. Ensure
192 // sensor is nonfunctional, but skip creating an
193 // error for it since it isn't a fan problem.
194 getLogger().log(std::format(
195 "Monitoring starting but {} sensor value not on D-Bus",
196 sensor->name()));
Matt Spinler4283c5d2021-03-01 15:56:00 -0600197
Matt Spinler3494a572023-11-28 12:45:32 -0600198 sensor->setFunctional(false, true);
Matt Spinler4283c5d2021-03-01 15:56:00 -0600199
Matt Spinler3494a572023-11-28 12:45:32 -0600200 if (_numSensorFailsForNonFunc)
201 {
202 if (_functional &&
203 (countNonFunctionalSensors() >= _numSensorFailsForNonFunc))
Matt Spinler4283c5d2021-03-01 15:56:00 -0600204 {
Matt Spinler3494a572023-11-28 12:45:32 -0600205 updateInventory(false);
Matt Spinler4283c5d2021-03-01 15:56:00 -0600206 }
Matt Spinler4283c5d2021-03-01 15:56:00 -0600207 }
Matt Spinler3494a572023-11-28 12:45:32 -0600208
209 // At this point, don't start any power off actions due
210 // to missing sensors. Let something else handle that
211 // policy.
212 _system.fanStatusChange(*this, true);
Matt Spinler4283c5d2021-03-01 15:56:00 -0600213 }
214 });
Matt Spinlerabf8da32017-04-27 14:08:45 -0500215}
216
Matt Spinlerebaae612017-04-27 14:21:48 -0500217void Fan::tachChanged()
218{
Matt Spinlerb0412d02020-10-12 16:53:52 -0500219 if (_monitorReady)
Matt Spinlerebaae612017-04-27 14:21:48 -0500220 {
Matt Spinlerb0412d02020-10-12 16:53:52 -0500221 for (auto& s : _sensors)
222 {
223 tachChanged(*s);
224 }
Matt Spinlerebaae612017-04-27 14:21:48 -0500225 }
226}
227
Matt Spinlerebaae612017-04-27 14:21:48 -0500228void Fan::tachChanged(TachSensor& sensor)
229{
Matt Spinler7d135642021-02-04 12:44:17 -0600230 if (!_system.isPowerOn() || !_monitorReady)
231 {
232 return;
233 }
234
Matt Spinlerc39e8592017-09-28 13:13:08 -0500235 if (_trustManager->active())
236 {
237 if (!_trustManager->checkTrust(sensor))
238 {
239 return;
240 }
241 }
242
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600243 // If the error checking method is 'count', if a tach change leads
244 // to an out of range sensor the count timer will take over in calling
245 // process() until the sensor is healthy again.
246 if (!sensor.countTimerRunning())
Matt Spinler623635c2021-03-29 13:13:59 -0500247 {
248 process(sensor);
249 }
250}
251
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600252void Fan::countTimerExpired(TachSensor& sensor)
Matt Spinler623635c2021-03-29 13:13:59 -0500253{
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600254 if (_trustManager->active() && !_trustManager->checkTrust(sensor))
Matt Spinler623635c2021-03-29 13:13:59 -0500255 {
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600256 return;
Matt Spinler623635c2021-03-29 13:13:59 -0500257 }
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600258 process(sensor);
Matthew Barthfcb0dbc2021-02-10 14:23:39 -0600259}
260
261void Fan::process(TachSensor& sensor)
262{
Matthew Barth177fe982020-05-26 11:05:19 -0500263 // If this sensor is out of range at this moment, start
264 // its timer, at the end of which the inventory
265 // for the fan may get updated to not functional.
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500266
Matthew Barth177fe982020-05-26 11:05:19 -0500267 // If this sensor is OK, put everything back into a good state.
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500268
269 if (outOfRange(sensor))
270 {
Matthew Barthe11cbc62018-02-20 12:11:07 -0600271 if (sensor.functional())
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500272 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800273 switch (sensor.getMethod())
274 {
275 case MethodMode::timebased:
276 // Start nonfunctional timer if not already running
277 sensor.startTimer(TimerMode::nonfunc);
278 break;
279 case MethodMode::count:
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600280
281 if (!sensor.countTimerRunning())
282 {
283 sensor.startCountTimer();
284 }
Jolie Ku69f2f482020-10-21 09:59:43 +0800285 sensor.setCounter(true);
286 if (sensor.getCounter() >= sensor.getThreshold())
287 {
288 updateState(sensor);
289 }
290 break;
291 }
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500292 }
293 }
294 else
295 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800296 switch (sensor.getMethod())
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500297 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800298 case MethodMode::timebased:
299 if (sensor.functional())
300 {
Matthew Barth11b5d8f2021-01-28 14:04:09 -0600301 if (sensor.timerRunning())
302 {
303 sensor.stopTimer();
304 }
Jolie Ku69f2f482020-10-21 09:59:43 +0800305 }
306 else
307 {
308 // Start functional timer if not already running
309 sensor.startTimer(TimerMode::func);
310 }
311 break;
312 case MethodMode::count:
313 sensor.setCounter(false);
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600314 if (sensor.getCounter() == 0)
Jolie Ku69f2f482020-10-21 09:59:43 +0800315 {
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600316 if (!sensor.functional())
317 {
318 updateState(sensor);
319 }
320
321 sensor.stopCountTimer();
Jolie Ku69f2f482020-10-21 09:59:43 +0800322 }
323 break;
Matt Spinlera4c8f1f2017-04-27 14:38:38 -0500324 }
325 }
Matt Spinlerebaae612017-04-27 14:21:48 -0500326}
327
Matthew Barthf552ea52018-01-15 16:22:04 -0600328uint64_t Fan::findTargetSpeed()
Matt Spinlerabf8da32017-04-27 14:08:45 -0500329{
330 uint64_t target = 0;
Matthew Barth177fe982020-05-26 11:05:19 -0500331 // The sensor doesn't support a target,
332 // so get it from another sensor.
Patrick Williamsdfddd642024-08-16 15:21:51 -0400333 auto s = std::find_if(_sensors.begin(), _sensors.end(), [](const auto& s) {
334 return s->hasTarget();
335 });
Matt Spinlerabf8da32017-04-27 14:08:45 -0500336
Matthew Barthf552ea52018-01-15 16:22:04 -0600337 if (s != _sensors.end())
Matt Spinlerabf8da32017-04-27 14:08:45 -0500338 {
Matthew Barthf552ea52018-01-15 16:22:04 -0600339 target = (*s)->getTarget();
Matt Spinlerabf8da32017-04-27 14:08:45 -0500340 }
341
342 return target;
343}
344
Mike Cappsce6820a2021-05-26 10:40:19 -0400345size_t Fan::countNonFunctionalSensors() const
Matt Spinlerabf8da32017-04-27 14:08:45 -0500346{
Patrick Williamsdfddd642024-08-16 15:21:51 -0400347 return std::count_if(_sensors.begin(), _sensors.end(), [](const auto& s) {
348 return !s->functional();
349 });
Matt Spinlerabf8da32017-04-27 14:08:45 -0500350}
351
Matt Spinlerabf8da32017-04-27 14:08:45 -0500352bool Fan::outOfRange(const TachSensor& sensor)
353{
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400354 if (!sensor.hasOwner())
Matt Spinlerabf8da32017-04-27 14:08:45 -0500355 {
356 return true;
357 }
358
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400359 auto actual = static_cast<uint64_t>(sensor.getInput());
Matt Spinlerf724c162023-05-10 11:14:37 -0500360 auto range = sensor.getRange(_deviation, _upperDeviation);
Mike Cappsfdcd5db2021-05-20 12:47:10 -0400361
Matthew Barth8a8aa442021-11-19 14:13:13 -0600362 return ((actual < range.first) ||
363 (range.second && actual > range.second.value()));
Matt Spinlerabf8da32017-04-27 14:08:45 -0500364}
365
Jolie Ku69f2f482020-10-21 09:59:43 +0800366void Fan::updateState(TachSensor& sensor)
Matt Spinlera9406a72017-04-27 14:29:24 -0500367{
Matt Spinler7d135642021-02-04 12:44:17 -0600368 if (!_system.isPowerOn())
369 {
370 return;
371 }
372
Matt Spinlerf724c162023-05-10 11:14:37 -0500373 auto range = sensor.getRange(_deviation, _upperDeviation);
Matthew Barth8a8aa442021-11-19 14:13:13 -0600374 std::string rangeMax = "NoMax";
375 if (range.second)
376 {
377 rangeMax = std::to_string(range.second.value());
378 }
379
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500380 // Skip starting the error timer if the sensor
381 // isn't on D-Bus as this isn't a fan hardware problem.
382 sensor.setFunctional(!sensor.functional(), !sensor.hasOwner());
383
Patrick Williamsfbf47032023-07-17 12:27:34 -0500384 getLogger().log(std::format(
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500385 "Setting tach sensor {} functional state to {}. "
Matt Spinler466bd222023-01-25 16:15:52 -0600386 "[target = {}, actual = {}, allowed range = ({} - {}) "
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500387 "owned = {}]",
388 sensor.name(), sensor.functional(), sensor.getTarget(),
389 sensor.getInput(), range.first, rangeMax, sensor.hasOwner()));
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500390
391 // A zero value for _numSensorFailsForNonFunc means we aren't dealing
392 // with fan FRU functional status, only sensor functional status.
393 if (_numSensorFailsForNonFunc)
Matthew Barthe11cbc62018-02-20 12:11:07 -0600394 {
Matthew Barth7c23a042021-01-26 16:21:45 -0600395 auto numNonFuncSensors = countNonFunctionalSensors();
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500396 // If the fan was nonfunctional and enough sensors are now OK,
Matthew Barthcceffdd2021-05-20 12:17:21 -0500397 // the fan can be set to functional as long as `set_func_on_present` was
398 // not set
399 if (!_setFuncOnPresent && !_functional &&
400 !(numNonFuncSensors >= _numSensorFailsForNonFunc))
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500401 {
Patrick Williamsfbf47032023-07-17 12:27:34 -0500402 getLogger().log(std::format("Setting fan {} to functional, number "
Matthew Barth7c23a042021-01-26 16:21:45 -0600403 "of nonfunctional sensors = {}",
404 _name, numNonFuncSensors));
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500405 updateInventory(true);
406 }
Matt Spinlera9406a72017-04-27 14:29:24 -0500407
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500408 // If the fan is currently functional, but too many
409 // contained sensors are now nonfunctional, update
Matthew Barth7c23a042021-01-26 16:21:45 -0600410 // the fan to nonfunctional.
411 if (_functional && (numNonFuncSensors >= _numSensorFailsForNonFunc))
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500412 {
Patrick Williamsfbf47032023-07-17 12:27:34 -0500413 getLogger().log(std::format("Setting fan {} to nonfunctional, "
Matthew Barth7c23a042021-01-26 16:21:45 -0600414 "number of nonfunctional sensors = {}",
415 _name, numNonFuncSensors));
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500416 updateInventory(false);
417 }
Matt Spinlerb1e18512017-04-27 14:42:33 -0500418 }
Matt Spinlerb63aa092020-10-14 09:45:11 -0500419
Matt Spinlerae01b5f2022-07-06 16:49:04 -0500420 // Skip the power off rule checks if the sensor isn't
421 // on D-Bus so a running system isn't shutdown.
422 _system.fanStatusChange(*this, !sensor.hasOwner());
Matt Spinlera9406a72017-04-27 14:29:24 -0500423}
424
Mike Capps9ff48772021-07-19 14:49:43 -0400425bool Fan::updateInventory(bool functional)
Matt Spinlerb1e18512017-04-27 14:42:33 -0500426{
Mike Capps9ff48772021-07-19 14:49:43 -0400427 bool dbusError = false;
428
429 try
Matt Spinlerb1e18512017-04-27 14:42:33 -0500430 {
Mike Capps9ff48772021-07-19 14:49:43 -0400431 auto objectMap =
432 util::getObjMap<bool>(_name, util::OPERATIONAL_STATUS_INTF,
433 util::FUNCTIONAL_PROPERTY, functional);
434
Mike Capps8af8a622022-02-04 16:13:33 -0500435 auto response = util::SDBusPlus::callMethod(
436 _bus, util::INVENTORY_SVC, util::INVENTORY_PATH,
437 util::INVENTORY_INTF, "Notify", objectMap);
Mike Capps9ff48772021-07-19 14:49:43 -0400438
439 if (response.is_method_error())
440 {
Anwaar Hadia00f6832025-03-27 15:03:11 +0000441 lg2::error("Error in Notify call to update inventory");
Mike Capps9ff48772021-07-19 14:49:43 -0400442
443 dbusError = true;
444 }
445 }
446 catch (const util::DBusError& e)
447 {
448 dbusError = true;
449
450 getLogger().log(
Patrick Williamsfbf47032023-07-17 12:27:34 -0500451 std::format("D-Bus Exception reading/updating inventory : {}",
Mike Capps9ff48772021-07-19 14:49:43 -0400452 e.what()),
453 Logger::error);
Matt Spinlerb1e18512017-04-27 14:42:33 -0500454 }
455
Matthew Barth177fe982020-05-26 11:05:19 -0500456 // This will always track the current state of the inventory.
Matt Spinlerb1e18512017-04-27 14:42:33 -0500457 _functional = functional;
Mike Capps9ff48772021-07-19 14:49:43 -0400458
459 return dbusError;
Matt Spinlerb1e18512017-04-27 14:42:33 -0500460}
461
Patrick Williamscb356d42022-07-22 19:26:53 -0500462void Fan::presenceChanged(sdbusplus::message_t& msg)
Matt Spinlerb63aa092020-10-14 09:45:11 -0500463{
464 std::string interface;
465 std::map<std::string, std::variant<bool>> properties;
466
467 msg.read(interface, properties);
468
469 auto presentProp = properties.find("Present");
470 if (presentProp != properties.end())
471 {
472 _present = std::get<bool>(presentProp->second);
473
Matt Spinler27f6b682020-10-27 08:43:37 -0500474 getLogger().log(
Patrick Williamsfbf47032023-07-17 12:27:34 -0500475 std::format("Fan {} presence state change to {}", _name, _present));
Matt Spinler27f6b682020-10-27 08:43:37 -0500476
Matt Spinlera3584bd2021-03-29 15:48:30 -0500477 if (_present && _setFuncOnPresent)
478 {
479 updateInventory(true);
480 std::for_each(_sensors.begin(), _sensors.end(), [](auto& sensor) {
481 sensor->setFunctional(true);
482 sensor->resetMethod();
483 });
484 }
485
Matthew Barth43b4cde2022-02-15 16:30:11 -0600486 _system.fanStatusChange(*this);
487
Matt Spinler27f6b682020-10-27 08:43:37 -0500488 if (_fanMissingErrorDelay)
489 {
Matt Spinler7d135642021-02-04 12:44:17 -0600490 if (!_present && _system.isPowerOn())
Matt Spinler27f6b682020-10-27 08:43:37 -0500491 {
492 _fanMissingErrorTimer->restartOnce(
493 std::chrono::seconds{*_fanMissingErrorDelay});
494 }
Matt Spinler7d135642021-02-04 12:44:17 -0600495 else if (_present && _fanMissingErrorTimer->isEnabled())
Matt Spinler27f6b682020-10-27 08:43:37 -0500496 {
497 _fanMissingErrorTimer->setEnabled(false);
498 }
499 }
Matt Spinlerb63aa092020-10-14 09:45:11 -0500500 }
501}
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500502
503void Fan::sensorErrorTimerExpired(const TachSensor& sensor)
504{
Matt Spinler7d135642021-02-04 12:44:17 -0600505 if (_present && _system.isPowerOn())
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500506 {
507 _system.sensorErrorTimerExpired(*this, sensor);
508 }
509}
510
Mike Capps808d7fe2022-06-13 10:12:16 -0400511void Fan::powerStateChanged([[maybe_unused]] bool powerStateOn)
Matt Spinler7d135642021-02-04 12:44:17 -0600512{
513#ifdef MONITOR_USE_JSON
514 if (powerStateOn)
515 {
Matt Spinler7d135642021-02-04 12:44:17 -0600516 _monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay));
517
Matt Spinlerbb449c12021-06-14 11:45:28 -0600518 _numSensorsOnDBusAtPowerOn = 0;
519
520 std::for_each(_sensors.begin(), _sensors.end(), [this](auto& sensor) {
521 try
522 {
523 // Force a getProperty call. If sensor is on D-Bus,
524 // then make sure it's functional.
525 sensor->updateTachAndTarget();
526
527 _numSensorsOnDBusAtPowerOn++;
528
529 if (_present)
530 {
531 // If not functional, set it back to functional.
532 if (!sensor->functional())
533 {
534 sensor->setFunctional(true);
535 _system.fanStatusChange(*this, true);
536 }
537
538 // Set the counters back to zero
539 if (sensor->getMethod() == MethodMode::count)
540 {
541 sensor->resetMethod();
542 }
543 }
544 }
545 catch (const util::DBusError& e)
546 {
547 // Properties still aren't on D-Bus. Let startMonitor()
548 // deal with it, or maybe System::powerStateChanged() if
549 // there aren't any sensors at all on D-Bus.
Patrick Williamsfbf47032023-07-17 12:27:34 -0500550 getLogger().log(std::format(
Matt Spinlerbb449c12021-06-14 11:45:28 -0600551 "At power on, tach sensor {} value not on D-Bus",
552 sensor->name()));
553 }
554 });
555
Matt Spinler4283c5d2021-03-01 15:56:00 -0600556 if (_present)
557 {
Matt Spinler4283c5d2021-03-01 15:56:00 -0600558 // If configured to change functional state on the fan itself,
559 // Set it back to true now if necessary.
560 if (_numSensorFailsForNonFunc)
561 {
562 if (!_functional &&
563 (countNonFunctionalSensors() < _numSensorFailsForNonFunc))
564 {
565 updateInventory(true);
566 }
567 }
568 }
569 else
Matt Spinler7d135642021-02-04 12:44:17 -0600570 {
571 getLogger().log(
Patrick Williamsfbf47032023-07-17 12:27:34 -0500572 std::format("At power on, fan {} is missing", _name));
Matt Spinler7d135642021-02-04 12:44:17 -0600573
574 if (_fanMissingErrorTimer)
575 {
576 _fanMissingErrorTimer->restartOnce(
577 std::chrono::seconds{*_fanMissingErrorDelay});
578 }
579 }
580 }
581 else
582 {
583 _monitorReady = false;
584
585 if (_monitorTimer.isEnabled())
586 {
587 _monitorTimer.setEnabled(false);
588 }
589
590 if (_fanMissingErrorTimer && _fanMissingErrorTimer->isEnabled())
591 {
592 _fanMissingErrorTimer->setEnabled(false);
593 }
594
595 std::for_each(_sensors.begin(), _sensors.end(), [](auto& sensor) {
596 if (sensor->timerRunning())
597 {
598 sensor->stopTimer();
599 }
Matt Spinler623635c2021-03-29 13:13:59 -0500600
Matt Spinlerfdfcc672021-06-01 14:51:06 -0600601 sensor->stopCountTimer();
602 });
Matt Spinler7d135642021-02-04 12:44:17 -0600603 }
604#endif
605}
606
Matthew Barth177fe982020-05-26 11:05:19 -0500607} // namespace monitor
608} // namespace fan
609} // namespace phosphor