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