summaryrefslogtreecommitdiffstats
path: root/monitor/fan.hpp
blob: 3da75cf9a3a4c38271e61c32394f64d71719c111 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#pragma once

#include <sdbusplus/bus.hpp>
#include <tuple>
#include <vector>
#include "event.hpp"
#include "tach_sensor.hpp"
#include "types.hpp"

namespace phosphor
{
namespace fan
{
namespace monitor
{

/**
 * The mode fan monitor will run in:
 *   - init - only do the initialization steps
 *   - monitor - run normal monitoring algorithm
 */
enum class Mode
{
    init,
    monitor
};

/**
 * @class InvalidSensorError
 *
 * An exception type for sensors that don't exist or
 * are otherwise inaccessible.
 */
class InvalidSensorError : public std::exception {};

/**
 * @class Fan
 *
 * Represents a fan, which can contain 1 or more sensors which
 * loosely correspond to rotors.  See below.
 *
 * There is a sensor when hwmon exposes one, which means there is a
 * speed value to be read.  Sometimes there is a sensor per rotor,
 * and other times multiple rotors just use 1 sensor total where
 * the sensor reports the slowest speed of all of the rotors.
 *
 * A rotor's speed is set by writing the Target value of a sensor.
 * Sometimes each sensor in a fan supports having a Target, and other
 * times not all of them do.  A TachSensor object knows if it supports
 * the Target property.
 *
 * The strategy for monitoring fan speeds is as follows:
 *
 * Every time a Target (new speed written) or Input (actual speed read)
 * sensor changes, check if the input value is within some range of the target
 * value.  If it isn't, start a timer at the end of which the sensor will be
 * set to not functional.  If enough sensors in the fan are now nonfunctional,
 * set the whole fan to nonfunctional in the inventory.
 *
 * When sensor inputs come back within a specified range of the target,
 * stop its timer if running, make the sensor functional again if it wasn't,
 * and if enough sensors in the fan are now functional set the whole fan
 * back to functional in the inventory.
 */
class Fan
{
    using Property = std::string;
    using Value = sdbusplus::message::variant<bool>;
    using PropertyMap = std::map<Property, Value>;

    using Interface = std::string;
    using InterfaceMap = std::map<Interface, PropertyMap>;

    using Object = sdbusplus::message::object_path;
    using ObjectMap = std::map<Object, InterfaceMap>;

    public:

        Fan() = delete;
        Fan(const Fan&) = delete;
        Fan(Fan&&) = default;
        Fan& operator=(const Fan&) = delete;
        Fan& operator=(Fan&&) = default;
        ~Fan() = default;

        /**
         * @brief Constructor
         *
         * @param mode - mode of fan monitor
         * @param bus - the dbus object
         * @param events - pointer to sd_event object
         * @param def - the fan definition structure
         */
        Fan(Mode mode,
            sdbusplus::bus::bus& bus,
            phosphor::fan::event::EventPtr& events,
            const FanDefinition& def);

        /**
         * @brief Callback function for when an input sensor changes
         *
         * Starts a timer, where if it expires then the sensor
         * was out of range for too long and can be considered not functional.
         */
        void tachChanged(TachSensor& sensor);

        /**
         * @brief Calls tachChanged(sensor) on each sensor
         */
        void tachChanged();

        /**
         * @brief The callback function for the timer
         *
         * Sets the sensor to not functional.
         * If enough sensors are now not functional,
         * updates the functional status of the whole
         * fan in the inventory.
         *
         * @param[in] sensor - the sensor whose timer expired
         */
        void timerExpired(TachSensor& sensor);

    private:

        /**
         * @brief Returns the target speed of the sensor
         *
         * If the sensor itself doesn't have a target, it finds
         * the target speed from another sensor.
         *
         * @param[in] sensor - the sensor to get the target speed for
         */
        uint64_t getTargetSpeed(const TachSensor& sensor);

        /**
         * @brief Returns true if the sensor input is not within
         * some deviation of the target.
         *
         * @param[in] sensor - the sensor to check
         */
        bool outOfRange(const TachSensor& sensor);

        /**
         * @brief Returns true if too many sensors are nonfunctional
         *        as defined by _numSensorFailsForNonFunc
         */
        bool tooManySensorsNonfunctional();

        /**
         * @brief Updates the Functional property in the inventory
         *        for the fan based on the value passed in.
         *
         * @param[in] functional - If the Functional property should
         *                         be set to true or false.
         */
        void updateInventory(bool functional);

        /**
         * @brief Returns the object map to use when updating the inventory
         *
         * @param[in] functional - If the Functional property should
         *                         be set to true or false.
         */
        ObjectMap getObjectMap(bool functional);

        /**
         * @brief the dbus object
         */
        sdbusplus::bus::bus& _bus;

        /**
         * @brief The inventory name of the fan
         */
        const std::string _name;

        /**
         * @brief The percentage that the input speed must be below
         *        the target speed to be considered an error.
         *        Between 0 and 100.
         */
        const size_t _deviation;

        /**
         * The number of sensors that must be nonfunctional at the
         * same time in order for the fan to be set to nonfunctional
         * in the inventory.
         */
        const size_t _numSensorFailsForNonFunc;

        /**
         * @brief The current functional state of the fan
         */
        bool _functional = true;

        /**
         * The sensor objects for the fan
         */
        std::vector<std::unique_ptr<TachSensor>> _sensors;
};

}
}
}
OpenPOWER on IntegriCloud