1e10416ecSMatt Spinler /** 2e10416ecSMatt Spinler * Copyright © 2017 IBM Corporation 3e10416ecSMatt Spinler * 4e10416ecSMatt Spinler * Licensed under the Apache License, Version 2.0 (the "License"); 5e10416ecSMatt Spinler * you may not use this file except in compliance with the License. 6e10416ecSMatt Spinler * You may obtain a copy of the License at 7e10416ecSMatt Spinler * 8e10416ecSMatt Spinler * http://www.apache.org/licenses/LICENSE-2.0 9e10416ecSMatt Spinler * 10e10416ecSMatt Spinler * Unless required by applicable law or agreed to in writing, software 11e10416ecSMatt Spinler * distributed under the License is distributed on an "AS IS" BASIS, 12e10416ecSMatt Spinler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e10416ecSMatt Spinler * See the License for the specific language governing permissions and 14e10416ecSMatt Spinler * limitations under the License. 15e10416ecSMatt Spinler */ 1657352a31SMatt Spinler #include <algorithm> 17ee7f6428SMatt Spinler #include <phosphor-logging/log.hpp> 18ee7f6428SMatt Spinler #include <unistd.h> 19e10416ecSMatt Spinler #include "manager.hpp" 20*f96b01e2SGunnar Mills #include "utility.hpp" 21e10416ecSMatt Spinler 22e10416ecSMatt Spinler namespace phosphor 23e10416ecSMatt Spinler { 24e10416ecSMatt Spinler namespace fan 25e10416ecSMatt Spinler { 26e10416ecSMatt Spinler namespace control 27e10416ecSMatt Spinler { 28e10416ecSMatt Spinler 29ee7f6428SMatt Spinler using namespace phosphor::logging; 30ee7f6428SMatt Spinler 31ee7f6428SMatt Spinler constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; 32ee7f6428SMatt Spinler constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1"; 33ee7f6428SMatt Spinler constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; 34ee7f6428SMatt Spinler constexpr auto FAN_CONTROL_READY_TARGET = "obmc-fan-control-ready@0.target"; 35ee7f6428SMatt Spinler 36*f96b01e2SGunnar Mills constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"; 37*f96b01e2SGunnar Mills constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper"; 38*f96b01e2SGunnar Mills constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper"; 39*f96b01e2SGunnar Mills constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper"; 40*f96b01e2SGunnar Mills 41*f96b01e2SGunnar Mills 42*f96b01e2SGunnar Mills /** 43*f96b01e2SGunnar Mills * Get the current value of the D-Bus property under the specified path 44*f96b01e2SGunnar Mills * and interface. 45*f96b01e2SGunnar Mills * 46*f96b01e2SGunnar Mills * @param[in] bus - The D-Bus bus object 47*f96b01e2SGunnar Mills * @param[in] path - The D-Bus path 48*f96b01e2SGunnar Mills * @param[in] interface - The D-Bus interface 49*f96b01e2SGunnar Mills * @param[in] propertyName - The D-Bus property 50*f96b01e2SGunnar Mills * @param[out] value - The D-Bus property's value 51*f96b01e2SGunnar Mills */ 52*f96b01e2SGunnar Mills template <typename T> 53*f96b01e2SGunnar Mills void getProperty(sdbusplus::bus::bus& bus, 54*f96b01e2SGunnar Mills const std::string& path, 55*f96b01e2SGunnar Mills const std::string& interface, 56*f96b01e2SGunnar Mills const std::string& propertyName, 57*f96b01e2SGunnar Mills T& value) 58*f96b01e2SGunnar Mills { 59*f96b01e2SGunnar Mills sdbusplus::message::variant<T> property; 60*f96b01e2SGunnar Mills std::string service = phosphor::fan::util::getService(path, interface, bus); 61*f96b01e2SGunnar Mills 62*f96b01e2SGunnar Mills auto method = bus.new_method_call(service.c_str(), 63*f96b01e2SGunnar Mills path.c_str(), 64*f96b01e2SGunnar Mills PROPERTY_INTERFACE, 65*f96b01e2SGunnar Mills "Get"); 66*f96b01e2SGunnar Mills 67*f96b01e2SGunnar Mills method.append(interface, propertyName); 68*f96b01e2SGunnar Mills auto reply = bus.call(method); 69*f96b01e2SGunnar Mills 70*f96b01e2SGunnar Mills if (reply.is_method_error()) 71*f96b01e2SGunnar Mills { 72*f96b01e2SGunnar Mills throw std::runtime_error( 73*f96b01e2SGunnar Mills "Error in call response for retrieving property"); 74*f96b01e2SGunnar Mills } 75*f96b01e2SGunnar Mills reply.read(property); 76*f96b01e2SGunnar Mills value = sdbusplus::message::variant_ns::get<T>(property); 77*f96b01e2SGunnar Mills } 78*f96b01e2SGunnar Mills 79*f96b01e2SGunnar Mills 80*f96b01e2SGunnar Mills /** 81*f96b01e2SGunnar Mills * Check if a condition is true. Conditions are used to determine 82*f96b01e2SGunnar Mills * which fan zone to use. 83*f96b01e2SGunnar Mills * 84*f96b01e2SGunnar Mills * @param[in] bus - The D-Bus bus object 85*f96b01e2SGunnar Mills * @param[in] condition - The condition to check if true 86*f96b01e2SGunnar Mills * @return result - True if the condition is true 87*f96b01e2SGunnar Mills */ 88*f96b01e2SGunnar Mills bool checkCondition(sdbusplus::bus::bus& bus, const auto& c) 89*f96b01e2SGunnar Mills { 90*f96b01e2SGunnar Mills auto& type = std::get<conditionTypePos>(c); 91*f96b01e2SGunnar Mills auto& properties = std::get<conditionPropertyListPos>(c); 92*f96b01e2SGunnar Mills 93*f96b01e2SGunnar Mills for (auto& p : properties) 94*f96b01e2SGunnar Mills { 95*f96b01e2SGunnar Mills bool value = std::get<propertyValuePos>(p); 96*f96b01e2SGunnar Mills bool propertyValue; 97*f96b01e2SGunnar Mills 98*f96b01e2SGunnar Mills // TODO openbmc/openbmc#1769: Support more types than just getProperty. 99*f96b01e2SGunnar Mills if (type.compare("getProperty") == 0) 100*f96b01e2SGunnar Mills { 101*f96b01e2SGunnar Mills getProperty(bus, 102*f96b01e2SGunnar Mills std::get<propertyPathPos>(p), 103*f96b01e2SGunnar Mills std::get<propertyInterfacePos>(p), 104*f96b01e2SGunnar Mills std::get<propertyNamePos>(p), 105*f96b01e2SGunnar Mills propertyValue); 106*f96b01e2SGunnar Mills 107*f96b01e2SGunnar Mills if (value != propertyValue) 108*f96b01e2SGunnar Mills { 109*f96b01e2SGunnar Mills return false; 110*f96b01e2SGunnar Mills } 111*f96b01e2SGunnar Mills } 112*f96b01e2SGunnar Mills } 113*f96b01e2SGunnar Mills return true; 114*f96b01e2SGunnar Mills } 115*f96b01e2SGunnar Mills 116*f96b01e2SGunnar Mills 117ee7f6428SMatt Spinler //Note: Future code will check 'mode' before starting control algorithm 118ee7f6428SMatt Spinler Manager::Manager(sdbusplus::bus::bus& bus, 119ee7f6428SMatt Spinler Mode mode) : 120e10416ecSMatt Spinler _bus(bus) 121e10416ecSMatt Spinler { 12257352a31SMatt Spinler //Create the appropriate Zone objects based on the 12357352a31SMatt Spinler //actual system configuration. 12457352a31SMatt Spinler 12557352a31SMatt Spinler //Find the 1 ZoneGroup that meets all of its conditions 12657352a31SMatt Spinler for (auto& group : _zoneLayouts) 12757352a31SMatt Spinler { 12857352a31SMatt Spinler auto& conditions = std::get<conditionListPos>(group); 12957352a31SMatt Spinler 13057352a31SMatt Spinler if (std::all_of(conditions.begin(), conditions.end(), 131*f96b01e2SGunnar Mills [&bus](const auto& condition) 13257352a31SMatt Spinler { 133*f96b01e2SGunnar Mills return checkCondition(bus, condition); 13457352a31SMatt Spinler })) 13557352a31SMatt Spinler { 13657352a31SMatt Spinler //Create a Zone object for each zone in this group 13757352a31SMatt Spinler auto& zones = std::get<zoneListPos>(group); 13857352a31SMatt Spinler 13957352a31SMatt Spinler for (auto& z : zones) 14057352a31SMatt Spinler { 14157352a31SMatt Spinler _zones.emplace(std::get<zoneNumPos>(z), 14214184131SMatthew Barth std::make_unique<Zone>(mode, _bus, z)); 14357352a31SMatt Spinler } 14457352a31SMatt Spinler 14557352a31SMatt Spinler break; 14657352a31SMatt Spinler } 14757352a31SMatt Spinler } 14857352a31SMatt Spinler 149ee7f6428SMatt Spinler } 150ee7f6428SMatt Spinler 151ee7f6428SMatt Spinler 152ee7f6428SMatt Spinler void Manager::doInit() 153ee7f6428SMatt Spinler { 15457352a31SMatt Spinler for (auto& z : _zones) 15557352a31SMatt Spinler { 15657352a31SMatt Spinler z.second->setFullSpeed(); 15757352a31SMatt Spinler } 158ee7f6428SMatt Spinler 159ee7f6428SMatt Spinler auto delay = _powerOnDelay; 160ee7f6428SMatt Spinler while (delay > 0) 161ee7f6428SMatt Spinler { 162ee7f6428SMatt Spinler delay = sleep(delay); 163e10416ecSMatt Spinler } 164e10416ecSMatt Spinler 165ee7f6428SMatt Spinler startFanControlReadyTarget(); 166ee7f6428SMatt Spinler } 167ee7f6428SMatt Spinler 168ee7f6428SMatt Spinler 169ee7f6428SMatt Spinler void Manager::startFanControlReadyTarget() 170ee7f6428SMatt Spinler { 171ee7f6428SMatt Spinler auto method = _bus.new_method_call(SYSTEMD_SERVICE, 172ee7f6428SMatt Spinler SYSTEMD_OBJ_PATH, 173ee7f6428SMatt Spinler SYSTEMD_INTERFACE, 174ee7f6428SMatt Spinler "StartUnit"); 175ee7f6428SMatt Spinler 176ee7f6428SMatt Spinler method.append(FAN_CONTROL_READY_TARGET); 177ee7f6428SMatt Spinler method.append("replace"); 178ee7f6428SMatt Spinler 179ee7f6428SMatt Spinler auto response = _bus.call(method); 180ee7f6428SMatt Spinler if (response.is_method_error()) 181ee7f6428SMatt Spinler { 182ee7f6428SMatt Spinler //TODO openbmc/openbmc#1555 create an elog 183ee7f6428SMatt Spinler log<level::ERR>("Failed to start fan control ready target"); 184ee7f6428SMatt Spinler throw std::runtime_error("Failed to start fan control ready target"); 185ee7f6428SMatt Spinler } 186ee7f6428SMatt Spinler } 187e10416ecSMatt Spinler 188*f96b01e2SGunnar Mills } // namespace control 189*f96b01e2SGunnar Mills } // namespace fan 190*f96b01e2SGunnar Mills } // namespace phosphor 191