xref: /openbmc/phosphor-fan-presence/monitor/power_off_cause.hpp (revision dfddd648cb81b27492afead4e2346f5fcd1397cb)
100237439SMatt Spinler #pragma once
200237439SMatt Spinler 
300237439SMatt Spinler #include "types.hpp"
400237439SMatt Spinler 
500237439SMatt Spinler #include <algorithm>
600237439SMatt Spinler #include <vector>
700237439SMatt Spinler 
800237439SMatt Spinler namespace phosphor::fan::monitor
900237439SMatt Spinler {
1000237439SMatt Spinler 
1100237439SMatt Spinler /**
1200237439SMatt Spinler  * @class PowerOffCause
1300237439SMatt Spinler  *
1400237439SMatt Spinler  * This abstract class provides a satisfied() pure virtual method
1500237439SMatt Spinler  * that is called to know if the system should be powered off due
1600237439SMatt Spinler  * to fan health.  Each type of class that is derived from this
1700237439SMatt Spinler  * one provides different behavior, for example one may count
1800237439SMatt Spinler  * missing fans, and another may count nonfunctional fans.
1900237439SMatt Spinler  */
2000237439SMatt Spinler class PowerOffCause
2100237439SMatt Spinler {
2200237439SMatt Spinler   public:
2300237439SMatt Spinler     PowerOffCause() = delete;
2400237439SMatt Spinler     virtual ~PowerOffCause() = default;
2500237439SMatt Spinler     PowerOffCause(const PowerOffCause&) = delete;
2600237439SMatt Spinler     PowerOffCause& operator=(const PowerOffCause&) = delete;
2700237439SMatt Spinler     PowerOffCause(PowerOffCause&&) = delete;
2800237439SMatt Spinler     PowerOffCause& operator=(PowerOffCause&&) = delete;
2900237439SMatt Spinler 
3000237439SMatt Spinler     /**
3100237439SMatt Spinler      * @brief Constructor
3200237439SMatt Spinler      *
3300237439SMatt Spinler      * @param[in] count - The number of items that is compared
3400237439SMatt Spinler      *                    against in the derived class.
3500237439SMatt Spinler      * @param[in] name - The name of the cause. Used for tracing.
3600237439SMatt Spinler      */
PowerOffCause(size_t count,const std::string & name)3700237439SMatt Spinler     PowerOffCause(size_t count, const std::string& name) :
3800237439SMatt Spinler         _count(count), _name(std::to_string(count) + " " + name)
3900237439SMatt Spinler     {}
4000237439SMatt Spinler 
4100237439SMatt Spinler     /**
4200237439SMatt Spinler      * @brief Pure virtual that says if the system should be powered
4300237439SMatt Spinler      *        off based on the fan health.
4400237439SMatt Spinler      *
4500237439SMatt Spinler      * @param[in] fanHealth - The FanHealth map
4600237439SMatt Spinler      *
4700237439SMatt Spinler      * @return bool - If system should be powered off
4800237439SMatt Spinler      */
4900237439SMatt Spinler     virtual bool satisfied(const FanHealth& fanHealth) = 0;
5000237439SMatt Spinler 
5100237439SMatt Spinler     /**
5200237439SMatt Spinler      * @brief Returns the name of the cause.
5300237439SMatt Spinler      *
5400237439SMatt Spinler      * For example:  "3 Missing Fans"
5500237439SMatt Spinler      *
5600237439SMatt Spinler      * @return std::string - The name
5700237439SMatt Spinler      */
name() const5800237439SMatt Spinler     const std::string& name() const
5900237439SMatt Spinler     {
6000237439SMatt Spinler         return _name;
6100237439SMatt Spinler     }
6200237439SMatt Spinler 
6300237439SMatt Spinler   protected:
6400237439SMatt Spinler     /**
6500237439SMatt Spinler      * @brief The number of fan health items that the derived
6600237439SMatt Spinler      *        class uses to compare to the fan health status.
6700237439SMatt Spinler      *        For example, a 3 for 3 missing fans.
6800237439SMatt Spinler      */
6900237439SMatt Spinler     const size_t _count;
7000237439SMatt Spinler 
7100237439SMatt Spinler     /**
7200237439SMatt Spinler      * @brief The cause name
7300237439SMatt Spinler      */
7400237439SMatt Spinler     const std::string _name;
7500237439SMatt Spinler };
7600237439SMatt Spinler 
7700237439SMatt Spinler /**
7800237439SMatt Spinler  * @class MissingFanFRUCause
7900237439SMatt Spinler  *
8000237439SMatt Spinler  * This class provides a satisfied() method that checks for
8100237439SMatt Spinler  * missing fans in the fan health map.
8200237439SMatt Spinler  *
8300237439SMatt Spinler  */
8400237439SMatt Spinler class MissingFanFRUCause : public PowerOffCause
8500237439SMatt Spinler {
8600237439SMatt Spinler   public:
8700237439SMatt Spinler     MissingFanFRUCause() = delete;
8800237439SMatt Spinler     ~MissingFanFRUCause() = default;
8900237439SMatt Spinler     MissingFanFRUCause(const MissingFanFRUCause&) = delete;
9000237439SMatt Spinler     MissingFanFRUCause& operator=(const MissingFanFRUCause&) = delete;
9100237439SMatt Spinler     MissingFanFRUCause(MissingFanFRUCause&&) = delete;
9200237439SMatt Spinler     MissingFanFRUCause& operator=(MissingFanFRUCause&&) = delete;
9300237439SMatt Spinler 
9400237439SMatt Spinler     /**
9500237439SMatt Spinler      * @brief Constructor
9600237439SMatt Spinler      *
9700237439SMatt Spinler      * @param[in] count - The minimum number of fans that must be
9800237439SMatt Spinler      *                    missing to need a power off.
9900237439SMatt Spinler      */
MissingFanFRUCause(size_t count)10000237439SMatt Spinler     explicit MissingFanFRUCause(size_t count) :
10100237439SMatt Spinler         PowerOffCause(count, "Missing Fan FRUs")
10200237439SMatt Spinler     {}
10300237439SMatt Spinler 
10400237439SMatt Spinler     /**
10500237439SMatt Spinler      * @brief Returns true if 'count' or more fans are missing
10600237439SMatt Spinler      *        to require a power off.
10700237439SMatt Spinler      *
10800237439SMatt Spinler      * @param[in] fanHealth - The FanHealth map
10900237439SMatt Spinler      */
satisfied(const FanHealth & fanHealth)11000237439SMatt Spinler     bool satisfied(const FanHealth& fanHealth) override
11100237439SMatt Spinler     {
112*dfddd648SPatrick Williams         size_t count = std::count_if(
113*dfddd648SPatrick Williams             fanHealth.begin(), fanHealth.end(), [](const auto& fan) {
11400237439SMatt Spinler                 return !std::get<presentHealthPos>(fan.second);
11500237439SMatt Spinler             });
11600237439SMatt Spinler 
11700237439SMatt Spinler         return count >= _count;
11800237439SMatt Spinler     }
11900237439SMatt Spinler };
12000237439SMatt Spinler 
12100237439SMatt Spinler /**
12200237439SMatt Spinler  * @class NonfuncFanRotorCause
12300237439SMatt Spinler  *
12400237439SMatt Spinler  * This class provides a satisfied() method that checks for
12500237439SMatt Spinler  * nonfunctional fan rotors in the fan health map.
12600237439SMatt Spinler  */
12700237439SMatt Spinler class NonfuncFanRotorCause : public PowerOffCause
12800237439SMatt Spinler {
12900237439SMatt Spinler   public:
13000237439SMatt Spinler     NonfuncFanRotorCause() = delete;
13100237439SMatt Spinler     ~NonfuncFanRotorCause() = default;
13200237439SMatt Spinler     NonfuncFanRotorCause(const NonfuncFanRotorCause&) = delete;
13300237439SMatt Spinler     NonfuncFanRotorCause& operator=(const NonfuncFanRotorCause&) = delete;
13400237439SMatt Spinler     NonfuncFanRotorCause(NonfuncFanRotorCause&&) = delete;
13500237439SMatt Spinler     NonfuncFanRotorCause& operator=(NonfuncFanRotorCause&&) = delete;
13600237439SMatt Spinler 
13700237439SMatt Spinler     /**
13800237439SMatt Spinler      * @brief Constructor
13900237439SMatt Spinler      *
14000237439SMatt Spinler      * @param[in] count - The minimum number of rotors that must be
1414c62fc77SMatt Spinler      *                    nonfunctional to need a power off.
14200237439SMatt Spinler      */
NonfuncFanRotorCause(size_t count)14300237439SMatt Spinler     explicit NonfuncFanRotorCause(size_t count) :
14400237439SMatt Spinler         PowerOffCause(count, "Nonfunctional Fan Rotors")
14500237439SMatt Spinler     {}
14600237439SMatt Spinler 
14700237439SMatt Spinler     /**
14800237439SMatt Spinler      * @brief Returns true if 'count' or more rotors are nonfunctional
14900237439SMatt Spinler      *        to require a power off.
15000237439SMatt Spinler      *
15100237439SMatt Spinler      * @param[in] fanHealth - The FanHealth map
15200237439SMatt Spinler      */
satisfied(const FanHealth & fanHealth)15300237439SMatt Spinler     bool satisfied(const FanHealth& fanHealth) override
15400237439SMatt Spinler     {
155*dfddd648SPatrick Williams         size_t count = std::accumulate(
156*dfddd648SPatrick Williams             fanHealth.begin(), fanHealth.end(), 0,
15700237439SMatt Spinler             [](int sum, const auto& fan) {
15800237439SMatt Spinler                 const auto& tachs = std::get<sensorFuncHealthPos>(fan.second);
159*dfddd648SPatrick Williams                 auto nonFuncTachs =
160*dfddd648SPatrick Williams                     std::count_if(tachs.begin(), tachs.end(),
16100237439SMatt Spinler                                   [](bool tach) { return !tach; });
16200237439SMatt Spinler                 return sum + nonFuncTachs;
16300237439SMatt Spinler             });
16400237439SMatt Spinler 
16500237439SMatt Spinler         return count >= _count;
16600237439SMatt Spinler     }
16700237439SMatt Spinler };
16800237439SMatt Spinler 
1694c62fc77SMatt Spinler /**
1704c62fc77SMatt Spinler  * @class FanFRUsWithNonfuncRotorsCause
1714c62fc77SMatt Spinler  *
1724c62fc77SMatt Spinler  * This class provides a satisfied() method that checks for
1734c62fc77SMatt Spinler  * fans with nonfunctional fan rotors in the fan health map.
1744c62fc77SMatt Spinler  */
1754c62fc77SMatt Spinler class FanFRUsWithNonfuncRotorsCause : public PowerOffCause
1764c62fc77SMatt Spinler {
1774c62fc77SMatt Spinler   public:
1784c62fc77SMatt Spinler     FanFRUsWithNonfuncRotorsCause() = delete;
1794c62fc77SMatt Spinler     ~FanFRUsWithNonfuncRotorsCause() = default;
1804c62fc77SMatt Spinler     FanFRUsWithNonfuncRotorsCause(const FanFRUsWithNonfuncRotorsCause&) =
1814c62fc77SMatt Spinler         delete;
1824c62fc77SMatt Spinler     FanFRUsWithNonfuncRotorsCause&
1834c62fc77SMatt Spinler         operator=(const FanFRUsWithNonfuncRotorsCause&) = delete;
1844c62fc77SMatt Spinler     FanFRUsWithNonfuncRotorsCause(FanFRUsWithNonfuncRotorsCause&&) = delete;
1854c62fc77SMatt Spinler     FanFRUsWithNonfuncRotorsCause&
1864c62fc77SMatt Spinler         operator=(FanFRUsWithNonfuncRotorsCause&&) = delete;
1874c62fc77SMatt Spinler 
1884c62fc77SMatt Spinler     /**
1894c62fc77SMatt Spinler      * @brief Constructor
1904c62fc77SMatt Spinler      *
1914c62fc77SMatt Spinler      * @param[in] count - The minimum number of fan FRUs with
1924c62fc77SMatt Spinler      *                    nonfunctional rotors to need a power off.
1934c62fc77SMatt Spinler      */
FanFRUsWithNonfuncRotorsCause(size_t count)1944c62fc77SMatt Spinler     explicit FanFRUsWithNonfuncRotorsCause(size_t count) :
1954c62fc77SMatt Spinler         PowerOffCause(count, "Fans with Nonfunctional Rotors")
1964c62fc77SMatt Spinler     {}
1974c62fc77SMatt Spinler 
1984c62fc77SMatt Spinler     /**
1994c62fc77SMatt Spinler      * @brief Returns true if 'count' or more fan FRUs have
2004c62fc77SMatt Spinler      *        nonfunctional rotors.
2014c62fc77SMatt Spinler      *
2024c62fc77SMatt Spinler      * @param[in] fanHealth - The FanHealth map
2034c62fc77SMatt Spinler      */
satisfied(const FanHealth & fanHealth)2044c62fc77SMatt Spinler     bool satisfied(const FanHealth& fanHealth) override
2054c62fc77SMatt Spinler     {
206*dfddd648SPatrick Williams         size_t count = std::count_if(
207*dfddd648SPatrick Williams             fanHealth.begin(), fanHealth.end(), [](const auto& fan) {
2084c62fc77SMatt Spinler                 const auto& tachs = std::get<sensorFuncHealthPos>(fan.second);
2094c62fc77SMatt Spinler 
2104c62fc77SMatt Spinler                 return std::any_of(tachs.begin(), tachs.end(),
2114c62fc77SMatt Spinler                                    [](bool func) { return !func; });
2124c62fc77SMatt Spinler             });
2134c62fc77SMatt Spinler 
2144c62fc77SMatt Spinler         return count >= _count;
2154c62fc77SMatt Spinler     }
2164c62fc77SMatt Spinler };
2174c62fc77SMatt Spinler 
21800237439SMatt Spinler } // namespace phosphor::fan::monitor
219