blob: d1101b9a4e6f650de34385612e150039053bcc9d [file] [log] [blame]
Matt Spinlerabf8da32017-04-27 14:08:45 -05001/**
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 <algorithm>
17#include <phosphor-logging/log.hpp>
18#include "fan.hpp"
19#include "types.hpp"
20
21namespace phosphor
22{
23namespace fan
24{
25namespace monitor
26{
27
28using namespace phosphor::logging;
Matt Spinlera4c8f1f2017-04-27 14:38:38 -050029using TimerType = phosphor::fan::util::Timer::TimerType;
Matt Spinlerabf8da32017-04-27 14:08:45 -050030
31Fan::Fan(sdbusplus::bus::bus& bus,
32 std::shared_ptr<sd_event>& events,
33 const FanDefinition& def) :
34 _bus(bus),
35 _name(std::get<fanNameField>(def)),
36 _deviation(std::get<fanDeviationField>(def)),
37 _numSensorFailsForNonFunc(std::get<numSensorFailsForNonfuncField>(def))
38{
39 auto& sensors = std::get<sensorListField>(def);
40
41 for (auto& s : sensors)
42 {
43 _sensors.emplace_back(
44 std::make_unique<TachSensor>(bus,
45 *this,
46 std::get<sensorNameField>(s),
47 std::get<hasTargetField>(s),
Matt Spinlera9406a72017-04-27 14:29:24 -050048 std::get<timeoutField>(def),
49 events));
Matt Spinlerabf8da32017-04-27 14:08:45 -050050 }
Matt Spinlera4c8f1f2017-04-27 14:38:38 -050051
52 //The TachSensors will now have already read the input
53 //and target values, so check them.
54 tachChanged();
Matt Spinlerabf8da32017-04-27 14:08:45 -050055}
56
57
Matt Spinlerebaae612017-04-27 14:21:48 -050058void Fan::tachChanged()
59{
60 for (auto& s : _sensors)
61 {
62 tachChanged(*s);
63 }
64}
65
66
67void Fan::tachChanged(TachSensor& sensor)
68{
Matt Spinlera4c8f1f2017-04-27 14:38:38 -050069 auto& timer = sensor.getTimer();
70 auto running = timer.running();
71
72 //If this sensor is out of range at this moment, start
73 //its timer, at the end of which the inventory
74 //for the fan may get updated to not functional.
75
76 //If this sensor is OK, put everything back into a good state.
77
78 if (outOfRange(sensor))
79 {
80 if (sensor.functional() && !running)
81 {
82 timer.start(sensor.getTimeout(), TimerType::oneshot);
83 }
84 }
85 else
86 {
87 if (!sensor.functional())
88 {
89 sensor.setFunctional(true);
90 }
91
92 if (running)
93 {
94 timer.stop();
95 }
96
97 //If the fan was nonfunctional and enough sensors are now OK,
98 //the fan can go back to functional
99 if (!_functional && !tooManySensorsNonfunctional())
100 {
101 log<level::INFO>("Setting a fan back to functional",
102 entry("FAN=%s", _name.c_str()));
103
104 //TODO: actually update inventory
105 }
106 }
Matt Spinlerebaae612017-04-27 14:21:48 -0500107}
108
109
Matt Spinlerabf8da32017-04-27 14:08:45 -0500110uint64_t Fan::getTargetSpeed(const TachSensor& sensor)
111{
112 uint64_t target = 0;
113
114 if (sensor.hasTarget())
115 {
116 target = sensor.getTarget();
117 }
118 else
119 {
120 //The sensor doesn't support a target,
121 //so get it from another sensor.
122 auto s = std::find_if(_sensors.begin(), _sensors.end(),
123 [](const auto& s)
124 {
125 return s->hasTarget();
126 });
127
128 if (s != _sensors.end())
129 {
130 target = (*s)->getTarget();
131 }
132 }
133
134 return target;
135}
136
137
138bool Fan::tooManySensorsNonfunctional()
139{
140 size_t numFailed = std::count_if(_sensors.begin(), _sensors.end(),
141 [](const auto& s)
142 {
143 return !s->functional();
144 });
145
146 return (numFailed >= _numSensorFailsForNonFunc);
147}
148
149
150bool Fan::outOfRange(const TachSensor& sensor)
151{
152 auto actual = static_cast<uint64_t>(sensor.getInput());
153 auto target = getTargetSpeed(sensor);
154
155 uint64_t min = target * (100 - _deviation) / 100;
156 uint64_t max = target * (100 + _deviation) / 100;
157
158 if ((actual < min) || (actual > max))
159 {
160 return true;
161 }
162
163 return false;
164}
165
166
Matt Spinlera9406a72017-04-27 14:29:24 -0500167void Fan::timerExpired(TachSensor& sensor)
168{
169 sensor.setFunctional(false);
170
171 //If the fan is currently functional, but too many
172 //contained sensors are now nonfunctional, update
173 //the whole fan nonfunctional.
174 //TODO
175}
176
Matt Spinlerabf8da32017-04-27 14:08:45 -0500177}
178}
179}