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