1 #pragma once
2 
3 #include "types.hpp"
4 
5 #include <algorithm>
6 #include <vector>
7 
8 namespace phosphor::fan::monitor
9 {
10 
11 /**
12  * @class PowerOffCause
13  *
14  * This abstract class provides a satisfied() pure virtual method
15  * that is called to know if the system should be powered off due
16  * to fan health.  Each type of class that is derived from this
17  * one provides different behavior, for example one may count
18  * missing fans, and another may count nonfunctional fans.
19  */
20 class PowerOffCause
21 {
22   public:
23     PowerOffCause() = delete;
24     virtual ~PowerOffCause() = default;
25     PowerOffCause(const PowerOffCause&) = delete;
26     PowerOffCause& operator=(const PowerOffCause&) = delete;
27     PowerOffCause(PowerOffCause&&) = delete;
28     PowerOffCause& operator=(PowerOffCause&&) = delete;
29 
30     /**
31      * @brief Constructor
32      *
33      * @param[in] count - The number of items that is compared
34      *                    against in the derived class.
35      * @param[in] name - The name of the cause. Used for tracing.
36      */
PowerOffCause(size_t count,const std::string & name)37     PowerOffCause(size_t count, const std::string& name) :
38         _count(count), _name(std::to_string(count) + " " + name)
39     {}
40 
41     /**
42      * @brief Pure virtual that says if the system should be powered
43      *        off based on the fan health.
44      *
45      * @param[in] fanHealth - The FanHealth map
46      *
47      * @return bool - If system should be powered off
48      */
49     virtual bool satisfied(const FanHealth& fanHealth) = 0;
50 
51     /**
52      * @brief Returns the name of the cause.
53      *
54      * For example:  "3 Missing Fans"
55      *
56      * @return std::string - The name
57      */
name() const58     const std::string& name() const
59     {
60         return _name;
61     }
62 
63   protected:
64     /**
65      * @brief The number of fan health items that the derived
66      *        class uses to compare to the fan health status.
67      *        For example, a 3 for 3 missing fans.
68      */
69     const size_t _count;
70 
71     /**
72      * @brief The cause name
73      */
74     const std::string _name;
75 };
76 
77 /**
78  * @class MissingFanFRUCause
79  *
80  * This class provides a satisfied() method that checks for
81  * missing fans in the fan health map.
82  *
83  */
84 class MissingFanFRUCause : public PowerOffCause
85 {
86   public:
87     MissingFanFRUCause() = delete;
88     ~MissingFanFRUCause() = default;
89     MissingFanFRUCause(const MissingFanFRUCause&) = delete;
90     MissingFanFRUCause& operator=(const MissingFanFRUCause&) = delete;
91     MissingFanFRUCause(MissingFanFRUCause&&) = delete;
92     MissingFanFRUCause& operator=(MissingFanFRUCause&&) = delete;
93 
94     /**
95      * @brief Constructor
96      *
97      * @param[in] count - The minimum number of fans that must be
98      *                    missing to need a power off.
99      */
MissingFanFRUCause(size_t count)100     explicit MissingFanFRUCause(size_t count) :
101         PowerOffCause(count, "Missing Fan FRUs")
102     {}
103 
104     /**
105      * @brief Returns true if 'count' or more fans are missing
106      *        to require a power off.
107      *
108      * @param[in] fanHealth - The FanHealth map
109      */
satisfied(const FanHealth & fanHealth)110     bool satisfied(const FanHealth& fanHealth) override
111     {
112         size_t count = std::count_if(fanHealth.begin(), fanHealth.end(),
113                                      [](const auto& fan) {
114             return !std::get<presentHealthPos>(fan.second);
115         });
116 
117         return count >= _count;
118     }
119 };
120 
121 /**
122  * @class NonfuncFanRotorCause
123  *
124  * This class provides a satisfied() method that checks for
125  * nonfunctional fan rotors in the fan health map.
126  */
127 class NonfuncFanRotorCause : public PowerOffCause
128 {
129   public:
130     NonfuncFanRotorCause() = delete;
131     ~NonfuncFanRotorCause() = default;
132     NonfuncFanRotorCause(const NonfuncFanRotorCause&) = delete;
133     NonfuncFanRotorCause& operator=(const NonfuncFanRotorCause&) = delete;
134     NonfuncFanRotorCause(NonfuncFanRotorCause&&) = delete;
135     NonfuncFanRotorCause& operator=(NonfuncFanRotorCause&&) = delete;
136 
137     /**
138      * @brief Constructor
139      *
140      * @param[in] count - The minimum number of rotors that must be
141      *                    nonfunctional to need a power off.
142      */
NonfuncFanRotorCause(size_t count)143     explicit NonfuncFanRotorCause(size_t count) :
144         PowerOffCause(count, "Nonfunctional Fan Rotors")
145     {}
146 
147     /**
148      * @brief Returns true if 'count' or more rotors are nonfunctional
149      *        to require a power off.
150      *
151      * @param[in] fanHealth - The FanHealth map
152      */
satisfied(const FanHealth & fanHealth)153     bool satisfied(const FanHealth& fanHealth) override
154     {
155         size_t count = std::accumulate(fanHealth.begin(), fanHealth.end(), 0,
156                                        [](int sum, const auto& fan) {
157             const auto& tachs = std::get<sensorFuncHealthPos>(fan.second);
158             auto nonFuncTachs = std::count_if(tachs.begin(), tachs.end(),
159                                               [](bool tach) { return !tach; });
160             return sum + nonFuncTachs;
161         });
162 
163         return count >= _count;
164     }
165 };
166 
167 /**
168  * @class FanFRUsWithNonfuncRotorsCause
169  *
170  * This class provides a satisfied() method that checks for
171  * fans with nonfunctional fan rotors in the fan health map.
172  */
173 class FanFRUsWithNonfuncRotorsCause : public PowerOffCause
174 {
175   public:
176     FanFRUsWithNonfuncRotorsCause() = delete;
177     ~FanFRUsWithNonfuncRotorsCause() = default;
178     FanFRUsWithNonfuncRotorsCause(const FanFRUsWithNonfuncRotorsCause&) =
179         delete;
180     FanFRUsWithNonfuncRotorsCause&
181         operator=(const FanFRUsWithNonfuncRotorsCause&) = delete;
182     FanFRUsWithNonfuncRotorsCause(FanFRUsWithNonfuncRotorsCause&&) = delete;
183     FanFRUsWithNonfuncRotorsCause&
184         operator=(FanFRUsWithNonfuncRotorsCause&&) = delete;
185 
186     /**
187      * @brief Constructor
188      *
189      * @param[in] count - The minimum number of fan FRUs with
190      *                    nonfunctional rotors to need a power off.
191      */
FanFRUsWithNonfuncRotorsCause(size_t count)192     explicit FanFRUsWithNonfuncRotorsCause(size_t count) :
193         PowerOffCause(count, "Fans with Nonfunctional Rotors")
194     {}
195 
196     /**
197      * @brief Returns true if 'count' or more fan FRUs have
198      *        nonfunctional rotors.
199      *
200      * @param[in] fanHealth - The FanHealth map
201      */
satisfied(const FanHealth & fanHealth)202     bool satisfied(const FanHealth& fanHealth) override
203     {
204         size_t count = std::count_if(fanHealth.begin(), fanHealth.end(),
205                                      [](const auto& fan) {
206             const auto& tachs = std::get<sensorFuncHealthPos>(fan.second);
207 
208             return std::any_of(tachs.begin(), tachs.end(),
209                                [](bool func) { return !func; });
210         });
211 
212         return count >= _count;
213     }
214 };
215 
216 } // namespace phosphor::fan::monitor
217