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(
113             fanHealth.begin(), fanHealth.end(), [](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(
156             fanHealth.begin(), fanHealth.end(), 0,
157             [](int sum, const auto& fan) {
158                 const auto& tachs = std::get<sensorFuncHealthPos>(fan.second);
159                 auto nonFuncTachs =
160                     std::count_if(tachs.begin(), tachs.end(),
161                                   [](bool tach) { return !tach; });
162                 return sum + nonFuncTachs;
163             });
164 
165         return count >= _count;
166     }
167 };
168 
169 /**
170  * @class FanFRUsWithNonfuncRotorsCause
171  *
172  * This class provides a satisfied() method that checks for
173  * fans with nonfunctional fan rotors in the fan health map.
174  */
175 class FanFRUsWithNonfuncRotorsCause : public PowerOffCause
176 {
177   public:
178     FanFRUsWithNonfuncRotorsCause() = delete;
179     ~FanFRUsWithNonfuncRotorsCause() = default;
180     FanFRUsWithNonfuncRotorsCause(const FanFRUsWithNonfuncRotorsCause&) =
181         delete;
182     FanFRUsWithNonfuncRotorsCause&
183         operator=(const FanFRUsWithNonfuncRotorsCause&) = delete;
184     FanFRUsWithNonfuncRotorsCause(FanFRUsWithNonfuncRotorsCause&&) = delete;
185     FanFRUsWithNonfuncRotorsCause&
186         operator=(FanFRUsWithNonfuncRotorsCause&&) = delete;
187 
188     /**
189      * @brief Constructor
190      *
191      * @param[in] count - The minimum number of fan FRUs with
192      *                    nonfunctional rotors to need a power off.
193      */
FanFRUsWithNonfuncRotorsCause(size_t count)194     explicit FanFRUsWithNonfuncRotorsCause(size_t count) :
195         PowerOffCause(count, "Fans with Nonfunctional Rotors")
196     {}
197 
198     /**
199      * @brief Returns true if 'count' or more fan FRUs have
200      *        nonfunctional rotors.
201      *
202      * @param[in] fanHealth - The FanHealth map
203      */
satisfied(const FanHealth & fanHealth)204     bool satisfied(const FanHealth& fanHealth) override
205     {
206         size_t count = std::count_if(
207             fanHealth.begin(), fanHealth.end(), [](const auto& fan) {
208                 const auto& tachs = std::get<sensorFuncHealthPos>(fan.second);
209 
210                 return std::any_of(tachs.begin(), tachs.end(),
211                                    [](bool func) { return !func; });
212             });
213 
214         return count >= _count;
215     }
216 };
217 
218 } // namespace phosphor::fan::monitor
219