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 25 namespace phosphor 26 { 27 namespace fan 28 { 29 namespace control 30 { 31 32 using namespace phosphor::logging; 33 34 constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; 35 constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1"; 36 constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; 37 constexpr auto FAN_CONTROL_READY_TARGET = "obmc-fan-control-ready@0.target"; 38 39 constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"; 40 constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper"; 41 constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper"; 42 constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper"; 43 44 45 /** 46 * Get the current value of the D-Bus property under the specified path 47 * and interface. 48 * 49 * @param[in] bus - The D-Bus bus object 50 * @param[in] path - The D-Bus path 51 * @param[in] interface - The D-Bus interface 52 * @param[in] propertyName - The D-Bus property 53 * @param[out] value - The D-Bus property's value 54 */ 55 template <typename T> 56 void getProperty(sdbusplus::bus::bus& bus, 57 const std::string& path, 58 const std::string& interface, 59 const std::string& propertyName, 60 T& value) 61 { 62 sdbusplus::message::variant<T> property; 63 std::string service = phosphor::fan::util::getService(path, interface, bus); 64 65 auto method = bus.new_method_call(service.c_str(), 66 path.c_str(), 67 PROPERTY_INTERFACE, 68 "Get"); 69 70 method.append(interface, propertyName); 71 auto reply = bus.call(method); 72 73 if (reply.is_method_error()) 74 { 75 log<level::ERR>("Error in call response for retrieving property"); 76 elog<InternalFailure>(); 77 } 78 reply.read(property); 79 value = sdbusplus::message::variant_ns::get<T>(property); 80 } 81 82 83 /** 84 * Check if a condition is true. Conditions are used to determine 85 * which fan zone to use. 86 * 87 * @param[in] bus - The D-Bus bus object 88 * @param[in] condition - The condition to check if true 89 * @return result - True if the condition is true 90 */ 91 bool checkCondition(sdbusplus::bus::bus& bus, const auto& c) 92 { 93 auto& type = std::get<conditionTypePos>(c); 94 auto& properties = std::get<conditionPropertyListPos>(c); 95 96 for (auto& p : properties) 97 { 98 bool value = std::get<propertyValuePos>(p); 99 bool propertyValue; 100 101 // TODO openbmc/openbmc#1769: Support more types than just getProperty. 102 if (type.compare("getProperty") == 0) 103 { 104 getProperty(bus, 105 std::get<propertyPathPos>(p), 106 std::get<propertyInterfacePos>(p), 107 std::get<propertyNamePos>(p), 108 propertyValue); 109 110 if (value != propertyValue) 111 { 112 return false; 113 } 114 } 115 } 116 return true; 117 } 118 119 120 //Note: Future code will check 'mode' before starting control algorithm 121 Manager::Manager(sdbusplus::bus::bus& bus, 122 phosphor::fan::event::EventPtr& events, 123 Mode mode) : 124 _bus(bus) 125 { 126 //Create the appropriate Zone objects based on the 127 //actual system configuration. 128 129 //Find the 1 ZoneGroup that meets all of its conditions 130 for (auto& group : _zoneLayouts) 131 { 132 auto& conditions = std::get<conditionListPos>(group); 133 134 if (std::all_of(conditions.begin(), conditions.end(), 135 [&bus](const auto& condition) 136 { 137 return checkCondition(bus, condition); 138 })) 139 { 140 //Create a Zone object for each zone in this group 141 auto& zones = std::get<zoneListPos>(group); 142 143 for (auto& z : zones) 144 { 145 _zones.emplace(std::get<zoneNumPos>(z), 146 std::make_unique<Zone>(mode, _bus, events, z)); 147 } 148 149 break; 150 } 151 } 152 153 } 154 155 156 void Manager::doInit() 157 { 158 for (auto& z : _zones) 159 { 160 z.second->setFullSpeed(); 161 } 162 163 auto delay = _powerOnDelay; 164 while (delay > 0) 165 { 166 delay = sleep(delay); 167 } 168 169 startFanControlReadyTarget(); 170 } 171 172 173 void Manager::startFanControlReadyTarget() 174 { 175 auto method = _bus.new_method_call(SYSTEMD_SERVICE, 176 SYSTEMD_OBJ_PATH, 177 SYSTEMD_INTERFACE, 178 "StartUnit"); 179 180 method.append(FAN_CONTROL_READY_TARGET); 181 method.append("replace"); 182 183 auto response = _bus.call(method); 184 if (response.is_method_error()) 185 { 186 log<level::ERR>("Failed to start fan control ready target"); 187 elog<InternalFailure>(); 188 } 189 } 190 191 } // namespace control 192 } // namespace fan 193 } // namespace phosphor 194