1 /**
2  * Copyright © 2017 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "fan.hpp"
17 
18 #include "logging.hpp"
19 #include "sdbusplus.hpp"
20 #include "system.hpp"
21 #include "types.hpp"
22 #include "utility.hpp"
23 
24 #include <fmt/format.h>
25 
26 #include <phosphor-logging/log.hpp>
27 
28 #include <algorithm>
29 
30 namespace phosphor
31 {
32 namespace fan
33 {
34 namespace monitor
35 {
36 
37 using namespace phosphor::logging;
38 using namespace sdbusplus::bus::match;
39 
40 Fan::Fan(Mode mode, sdbusplus::bus::bus& bus, const sdeventplus::Event& event,
41          std::unique_ptr<trust::Manager>& trust, const FanDefinition& def,
42          System& system) :
43     _bus(bus),
44     _name(std::get<fanNameField>(def)),
45     _deviation(std::get<fanDeviationField>(def)),
46     _numSensorFailsForNonFunc(std::get<numSensorFailsForNonfuncField>(def)),
47     _trustManager(trust),
48 #ifdef MONITOR_USE_JSON
49     _monitorDelay(std::get<monitorStartDelayField>(def)),
50     _monitorTimer(event, std::bind(std::mem_fn(&Fan::startMonitor), this)),
51 #endif
52     _system(system),
53     _presenceMatch(bus,
54                    rules::propertiesChanged(util::INVENTORY_PATH + _name,
55                                             util::INV_ITEM_IFACE),
56                    std::bind(std::mem_fn(&Fan::presenceChanged), this,
57                              std::placeholders::_1)),
58     _presenceIfaceAddedMatch(
59         bus,
60         rules::interfacesAdded() +
61             rules::argNpath(0, util::INVENTORY_PATH + _name),
62         std::bind(std::mem_fn(&Fan::presenceIfaceAdded), this,
63                   std::placeholders::_1)),
64     _fanMissingErrorDelay(std::get<fanMissingErrDelayField>(def))
65 {
66     // Start from a known state of functional (even if
67     // _numSensorFailsForNonFunc is 0)
68     updateInventory(true);
69 
70     // Setup tach sensors for monitoring
71     auto& sensors = std::get<sensorListField>(def);
72     for (auto& s : sensors)
73     {
74         try
75         {
76             _sensors.emplace_back(std::make_shared<TachSensor>(
77                 mode, bus, *this, std::get<sensorNameField>(s),
78                 std::get<hasTargetField>(s), std::get<funcDelay>(def),
79                 std::get<targetInterfaceField>(s), std::get<factorField>(s),
80                 std::get<offsetField>(s), std::get<methodField>(def),
81                 std::get<thresholdField>(s), std::get<timeoutField>(def),
82                 std::get<nonfuncRotorErrDelayField>(def), event));
83 
84             _trustManager->registerSensor(_sensors.back());
85         }
86         catch (InvalidSensorError& e)
87         {
88             // Count the number of failed tach sensors, though if
89             // _numSensorFailsForNonFunc is zero that means the fan should not
90             // be set to nonfunctional.
91             if (_numSensorFailsForNonFunc &&
92                 (++_numFailedSensor >= _numSensorFailsForNonFunc))
93             {
94                 // Mark associated fan as nonfunctional
95                 updateInventory(false);
96             }
97         }
98     }
99 
100 #ifndef MONITOR_USE_JSON
101     // Check current tach state when entering monitor mode
102     if (mode != Mode::init)
103     {
104         _monitorReady = true;
105 
106         // The TachSensors will now have already read the input
107         // and target values, so check them.
108         tachChanged();
109     }
110 #else
111     if (_system.isPowerOn())
112     {
113         _monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay));
114     }
115 #endif
116 
117     if (_fanMissingErrorDelay)
118     {
119         _fanMissingErrorTimer = std::make_unique<
120             sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>(
121             event, std::bind(&System::fanMissingErrorTimerExpired, &system,
122                              std::ref(*this)));
123     }
124 
125     try
126     {
127         _present = util::SDBusPlus::getProperty<bool>(
128             util::INVENTORY_PATH + _name, util::INV_ITEM_IFACE, "Present");
129 
130         if (!_present)
131         {
132             getLogger().log(
133                 fmt::format("On startup, fan {} is missing", _name));
134             if (_system.isPowerOn() && _fanMissingErrorTimer)
135             {
136                 _fanMissingErrorTimer->restartOnce(
137                     std::chrono::seconds{*_fanMissingErrorDelay});
138             }
139         }
140     }
141     catch (const util::DBusServiceError& e)
142     {
143         // This could happen on the first BMC boot if the presence
144         // detect app hasn't started yet and there isn't an inventory
145         // cache yet.
146     }
147 }
148 
149 void Fan::presenceIfaceAdded(sdbusplus::message::message& msg)
150 {
151     sdbusplus::message::object_path path;
152     std::map<std::string, std::map<std::string, std::variant<bool>>> interfaces;
153 
154     msg.read(path, interfaces);
155 
156     auto properties = interfaces.find(util::INV_ITEM_IFACE);
157     if (properties == interfaces.end())
158     {
159         return;
160     }
161 
162     auto property = properties->second.find("Present");
163     if (property == properties->second.end())
164     {
165         return;
166     }
167 
168     _present = std::get<bool>(property->second);
169 
170     if (!_present)
171     {
172         getLogger().log(fmt::format(
173             "New fan {} interface added and fan is not present", _name));
174         if (_system.isPowerOn() && _fanMissingErrorTimer)
175         {
176             _fanMissingErrorTimer->restartOnce(
177                 std::chrono::seconds{*_fanMissingErrorDelay});
178         }
179     }
180 
181     _system.fanStatusChange(*this);
182 }
183 
184 void Fan::startMonitor()
185 {
186     _monitorReady = true;
187 
188     tachChanged();
189 }
190 
191 void Fan::tachChanged()
192 {
193     if (_monitorReady)
194     {
195         for (auto& s : _sensors)
196         {
197             tachChanged(*s);
198         }
199     }
200 }
201 
202 void Fan::tachChanged(TachSensor& sensor)
203 {
204     if (!_system.isPowerOn() || !_monitorReady)
205     {
206         return;
207     }
208 
209     if (_trustManager->active())
210     {
211         if (!_trustManager->checkTrust(sensor))
212         {
213             return;
214         }
215     }
216 
217     process(sensor);
218 }
219 
220 void Fan::process(TachSensor& sensor)
221 {
222     // If this sensor is out of range at this moment, start
223     // its timer, at the end of which the inventory
224     // for the fan may get updated to not functional.
225 
226     // If this sensor is OK, put everything back into a good state.
227 
228     if (outOfRange(sensor))
229     {
230         if (sensor.functional())
231         {
232             switch (sensor.getMethod())
233             {
234                 case MethodMode::timebased:
235                     // Start nonfunctional timer if not already running
236                     sensor.startTimer(TimerMode::nonfunc);
237                     break;
238                 case MethodMode::count:
239                     sensor.setCounter(true);
240                     if (sensor.getCounter() >= sensor.getThreshold())
241                     {
242                         updateState(sensor);
243                     }
244                     break;
245             }
246         }
247     }
248     else
249     {
250         switch (sensor.getMethod())
251         {
252             case MethodMode::timebased:
253                 if (sensor.functional())
254                 {
255                     if (sensor.timerRunning())
256                     {
257                         sensor.stopTimer();
258                     }
259                 }
260                 else
261                 {
262                     // Start functional timer if not already running
263                     sensor.startTimer(TimerMode::func);
264                 }
265                 break;
266             case MethodMode::count:
267                 sensor.setCounter(false);
268                 if (!sensor.functional() && sensor.getCounter() == 0)
269                 {
270                     updateState(sensor);
271                 }
272                 break;
273         }
274     }
275 }
276 
277 uint64_t Fan::findTargetSpeed()
278 {
279     uint64_t target = 0;
280     // The sensor doesn't support a target,
281     // so get it from another sensor.
282     auto s = std::find_if(_sensors.begin(), _sensors.end(),
283                           [](const auto& s) { return s->hasTarget(); });
284 
285     if (s != _sensors.end())
286     {
287         target = (*s)->getTarget();
288     }
289 
290     return target;
291 }
292 
293 size_t Fan::countNonFunctionalSensors()
294 {
295     return std::count_if(_sensors.begin(), _sensors.end(),
296                          [](const auto& s) { return !s->functional(); });
297 }
298 
299 bool Fan::outOfRange(const TachSensor& sensor)
300 {
301     auto actual = static_cast<uint64_t>(sensor.getInput());
302     auto range = sensor.getRange(_deviation);
303 
304     if ((actual < range.first) || (actual > range.second))
305     {
306         return true;
307     }
308 
309     return false;
310 }
311 
312 void Fan::updateState(TachSensor& sensor)
313 {
314     auto range = sensor.getRange(_deviation);
315 
316     if (!_system.isPowerOn())
317     {
318         return;
319     }
320 
321     sensor.setFunctional(!sensor.functional());
322     getLogger().log(
323         fmt::format("Setting tach sensor {} functional state to {}. "
324                     "[target = {}, input = {}, allowed range = ({} - {})]",
325                     sensor.name(), sensor.functional(), sensor.getTarget(),
326                     sensor.getInput(), range.first, range.second));
327 
328     // A zero value for _numSensorFailsForNonFunc means we aren't dealing
329     // with fan FRU functional status, only sensor functional status.
330     if (_numSensorFailsForNonFunc)
331     {
332         auto numNonFuncSensors = countNonFunctionalSensors();
333         // If the fan was nonfunctional and enough sensors are now OK,
334         // the fan can be set to functional
335         if (!_functional && !(numNonFuncSensors >= _numSensorFailsForNonFunc))
336         {
337             getLogger().log(fmt::format("Setting fan {} to functional, number "
338                                         "of nonfunctional sensors = {}",
339                                         _name, numNonFuncSensors));
340             updateInventory(true);
341         }
342 
343         // If the fan is currently functional, but too many
344         // contained sensors are now nonfunctional, update
345         // the fan to nonfunctional.
346         if (_functional && (numNonFuncSensors >= _numSensorFailsForNonFunc))
347         {
348             getLogger().log(fmt::format("Setting fan {} to nonfunctional, "
349                                         "number of nonfunctional sensors = {}",
350                                         _name, numNonFuncSensors));
351             updateInventory(false);
352         }
353     }
354 
355     _system.fanStatusChange(*this);
356 }
357 
358 void Fan::updateInventory(bool functional)
359 {
360     auto objectMap =
361         util::getObjMap<bool>(_name, util::OPERATIONAL_STATUS_INTF,
362                               util::FUNCTIONAL_PROPERTY, functional);
363     auto response = util::SDBusPlus::lookupAndCallMethod(
364         _bus, util::INVENTORY_PATH, util::INVENTORY_INTF, "Notify", objectMap);
365     if (response.is_method_error())
366     {
367         log<level::ERR>("Error in Notify call to update inventory");
368         return;
369     }
370 
371     // This will always track the current state of the inventory.
372     _functional = functional;
373 }
374 
375 void Fan::presenceChanged(sdbusplus::message::message& msg)
376 {
377     std::string interface;
378     std::map<std::string, std::variant<bool>> properties;
379 
380     msg.read(interface, properties);
381 
382     auto presentProp = properties.find("Present");
383     if (presentProp != properties.end())
384     {
385         _present = std::get<bool>(presentProp->second);
386 
387         getLogger().log(
388             fmt::format("Fan {} presence state change to {}", _name, _present));
389 
390         _system.fanStatusChange(*this);
391 
392         if (_fanMissingErrorDelay)
393         {
394             if (!_present && _system.isPowerOn())
395             {
396                 _fanMissingErrorTimer->restartOnce(
397                     std::chrono::seconds{*_fanMissingErrorDelay});
398             }
399             else if (_present && _fanMissingErrorTimer->isEnabled())
400             {
401                 _fanMissingErrorTimer->setEnabled(false);
402             }
403         }
404     }
405 }
406 
407 void Fan::sensorErrorTimerExpired(const TachSensor& sensor)
408 {
409     if (_present && _system.isPowerOn())
410     {
411         _system.sensorErrorTimerExpired(*this, sensor);
412     }
413 }
414 
415 void Fan::powerStateChanged(bool powerStateOn)
416 {
417 #ifdef MONITOR_USE_JSON
418     if (powerStateOn)
419     {
420         // set all fans back to functional to start with
421         std::for_each(_sensors.begin(), _sensors.end(),
422                       [](auto& sensor) { sensor->setFunctional(true); });
423 
424         _monitorTimer.restartOnce(std::chrono::seconds(_monitorDelay));
425 
426         if (!_present)
427         {
428             getLogger().log(
429                 fmt::format("At power on, fan {} is missing", _name));
430 
431             if (_fanMissingErrorTimer)
432             {
433                 _fanMissingErrorTimer->restartOnce(
434                     std::chrono::seconds{*_fanMissingErrorDelay});
435             }
436         }
437     }
438     else
439     {
440         _monitorReady = false;
441 
442         if (_monitorTimer.isEnabled())
443         {
444             _monitorTimer.setEnabled(false);
445         }
446 
447         if (_fanMissingErrorTimer && _fanMissingErrorTimer->isEnabled())
448         {
449             _fanMissingErrorTimer->setEnabled(false);
450         }
451 
452         std::for_each(_sensors.begin(), _sensors.end(), [](auto& sensor) {
453             if (sensor->timerRunning())
454             {
455                 sensor->stopTimer();
456             }
457         });
458     }
459 #endif
460 }
461 
462 } // namespace monitor
463 } // namespace fan
464 } // namespace phosphor
465