1 /**
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 <phosphor-logging/elog.hpp>
19 #include <phosphor-logging/elog-errors.hpp>
20 #include <xyz/openbmc_project/Common/error.hpp>
21 #include <unistd.h>
22 #include "manager.hpp"
23 #include "utility.hpp"
24 #include "sdbusplus.hpp"
25 
26 namespace phosphor
27 {
28 namespace fan
29 {
30 namespace control
31 {
32 
33 using namespace phosphor::logging;
34 
35 constexpr auto SYSTEMD_SERVICE   = "org.freedesktop.systemd1";
36 constexpr auto SYSTEMD_OBJ_PATH  = "/org/freedesktop/systemd1";
37 constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
38 constexpr auto FAN_CONTROL_READY_TARGET = "obmc-fan-control-ready@0.target";
39 
40 /**
41  * Check if a condition is true. Conditions are used to determine
42  * which fan zone to use.
43  *
44  * @param[in] bus       - The D-Bus bus object
45  * @param[in] condition - The condition to check if true
46  * @return result       - True if the condition is true
47  */
48 bool checkCondition(sdbusplus::bus::bus& bus, const auto& c)
49 {
50     auto& type = std::get<conditionTypePos>(c);
51     auto& properties = std::get<conditionPropertyListPos>(c);
52 
53     for (auto& p : properties)
54     {
55         auto value = std::get<propertyValuePos>(p);
56 
57         // TODO openbmc/openbmc#1769: Support more types than just getProperty.
58         if (type.compare("getProperty") == 0)
59         {
60             auto propertyValue = util::SDBusPlus::getProperty<decltype(value)>(
61                     bus,
62                     std::get<propertyPathPos>(p),
63                     std::get<propertyInterfacePos>(p),
64                     std::get<propertyNamePos>(p));
65 
66             if (value != propertyValue)
67             {
68                 return false;
69             }
70         }
71     }
72     return true;
73 }
74 
75 
76 //Note: Future code will check 'mode' before starting control algorithm
77 Manager::Manager(sdbusplus::bus::bus& bus,
78                  const sdeventplus::Event& event,
79                  Mode mode) :
80     _bus(bus)
81 {
82     //Create the appropriate Zone objects based on the
83     //actual system configuration.
84 
85     //Find the 1 ZoneGroup that meets all of its conditions
86     for (auto& group : _zoneLayouts)
87     {
88         auto& conditions = std::get<conditionListPos>(group);
89 
90         if (std::all_of(conditions.begin(), conditions.end(),
91                         [&bus](const auto& condition)
92         {
93             return checkCondition(bus, condition);
94         }))
95         {
96             //Create a Zone object for each zone in this group
97             auto& zones = std::get<zoneListPos>(group);
98 
99             for (auto& z : zones)
100             {
101                 _zones.emplace(std::get<zoneNumPos>(z),
102                                std::make_unique<Zone>(mode, _bus, event, z));
103             }
104 
105             break;
106         }
107     }
108 
109 }
110 
111 
112 void Manager::doInit()
113 {
114     for (auto& z : _zones)
115     {
116         z.second->setFullSpeed();
117     }
118 
119     auto delay = _powerOnDelay;
120     while (delay > 0)
121     {
122         delay = sleep(delay);
123     }
124 
125     util::SDBusPlus::callMethod(
126             _bus,
127             SYSTEMD_SERVICE,
128             SYSTEMD_OBJ_PATH,
129             SYSTEMD_INTERFACE,
130             "StartUnit",
131             FAN_CONTROL_READY_TARGET,
132             "replace");
133 }
134 
135 } // namespace control
136 } // namespace fan
137 } // namespace phosphor
138