1*e83604beSCheng C Yang /* 2*e83604beSCheng C Yang // Copyright (c) 2019 Intel Corporation 3*e83604beSCheng C Yang // 4*e83604beSCheng C Yang // Licensed under the Apache License, Version 2.0 (the "License"); 5*e83604beSCheng C Yang // you may not use this file except in compliance with the License. 6*e83604beSCheng C Yang // You may obtain a copy of the License at 7*e83604beSCheng C Yang // 8*e83604beSCheng C Yang // http://www.apache.org/licenses/LICENSE-2.0 9*e83604beSCheng C Yang // 10*e83604beSCheng C Yang // Unless required by applicable law or agreed to in writing, software 11*e83604beSCheng C Yang // distributed under the License is distributed on an "AS IS" BASIS, 12*e83604beSCheng C Yang // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*e83604beSCheng C Yang // See the License for the specific language governing permissions and 14*e83604beSCheng C Yang // limitations under the License. 15*e83604beSCheng C Yang */ 16*e83604beSCheng C Yang 17*e83604beSCheng C Yang #include "types.hpp" 18*e83604beSCheng C Yang 19*e83604beSCheng C Yang #include <array> 20*e83604beSCheng C Yang #include <boost/algorithm/string/predicate.hpp> 21*e83604beSCheng C Yang #include <boost/algorithm/string/replace.hpp> 22*e83604beSCheng C Yang #include <boost/asio/post.hpp> 23*e83604beSCheng C Yang #include <boost/container/flat_set.hpp> 24*e83604beSCheng C Yang #include <cold_redundancy.hpp> 25*e83604beSCheng C Yang #include <filesystem> 26*e83604beSCheng C Yang #include <fstream> 27*e83604beSCheng C Yang #include <iostream> 28*e83604beSCheng C Yang #include <phosphor-logging/elog-errors.hpp> 29*e83604beSCheng C Yang #include <regex> 30*e83604beSCheng C Yang #include <sdbusplus/asio/connection.hpp> 31*e83604beSCheng C Yang #include <sdbusplus/asio/object_server.hpp> 32*e83604beSCheng C Yang #include <sdbusplus/asio/sd_event.hpp> 33*e83604beSCheng C Yang #include <sdbusplus/bus/match.hpp> 34*e83604beSCheng C Yang 35*e83604beSCheng C Yang namespace 36*e83604beSCheng C Yang { 37*e83604beSCheng C Yang constexpr const std::array<const char*, 1> psuInterfaceTypes = { 38*e83604beSCheng C Yang "xyz.openbmc_project.Configuration.pmbus"}; 39*e83604beSCheng C Yang std::string inventoryPath = std::string(INVENTORY_OBJ_PATH) + "/system"; 40*e83604beSCheng C Yang const constexpr char* eventPath = "/xyz/openbmc_project/State/Decorator"; 41*e83604beSCheng C Yang std::vector<std::unique_ptr<PowerSupply>> powerSupplies; 42*e83604beSCheng C Yang } // namespace 43*e83604beSCheng C Yang 44*e83604beSCheng C Yang ColdRedundancy::ColdRedundancy( 45*e83604beSCheng C Yang boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer, 46*e83604beSCheng C Yang std::shared_ptr<sdbusplus::asio::connection>& systemBus) : 47*e83604beSCheng C Yang filterTimer(io), 48*e83604beSCheng C Yang systemBus(systemBus) 49*e83604beSCheng C Yang { 50*e83604beSCheng C Yang post(io, 51*e83604beSCheng C Yang [this, &io, &objectServer, &systemBus]() { createPSU(systemBus); }); 52*e83604beSCheng C Yang std::function<void(sdbusplus::message::message&)> eventHandler = 53*e83604beSCheng C Yang [this, &io, &objectServer, 54*e83604beSCheng C Yang &systemBus](sdbusplus::message::message& message) { 55*e83604beSCheng C Yang if (message.is_method_error()) 56*e83604beSCheng C Yang { 57*e83604beSCheng C Yang std::cerr << "callback method error\n"; 58*e83604beSCheng C Yang return; 59*e83604beSCheng C Yang } 60*e83604beSCheng C Yang filterTimer.expires_after(std::chrono::seconds(1)); 61*e83604beSCheng C Yang filterTimer.async_wait([this, &io, &objectServer, &systemBus]( 62*e83604beSCheng C Yang const boost::system::error_code& ec) { 63*e83604beSCheng C Yang if (ec == boost::asio::error::operation_aborted) 64*e83604beSCheng C Yang { 65*e83604beSCheng C Yang return; 66*e83604beSCheng C Yang } 67*e83604beSCheng C Yang else if (ec) 68*e83604beSCheng C Yang { 69*e83604beSCheng C Yang std::cerr << "timer error\n"; 70*e83604beSCheng C Yang } 71*e83604beSCheng C Yang createPSU(systemBus); 72*e83604beSCheng C Yang }); 73*e83604beSCheng C Yang }; 74*e83604beSCheng C Yang 75*e83604beSCheng C Yang std::function<void(sdbusplus::message::message&)> eventCollect = 76*e83604beSCheng C Yang [&](sdbusplus::message::message& message) { 77*e83604beSCheng C Yang std::string objectName; 78*e83604beSCheng C Yang boost::container::flat_map<std::string, std::variant<bool>> values; 79*e83604beSCheng C Yang std::string path = message.get_path(); 80*e83604beSCheng C Yang std::size_t slantingPos = path.find_last_of("/\\"); 81*e83604beSCheng C Yang if ((slantingPos == std::string::npos) || 82*e83604beSCheng C Yang ((slantingPos + 1) >= path.size())) 83*e83604beSCheng C Yang { 84*e83604beSCheng C Yang std::cerr << "Unable to get PSU state name from path\n"; 85*e83604beSCheng C Yang return; 86*e83604beSCheng C Yang } 87*e83604beSCheng C Yang std::string statePSUName = path.substr(slantingPos + 1); 88*e83604beSCheng C Yang 89*e83604beSCheng C Yang std::size_t hypenPos = statePSUName.find("_"); 90*e83604beSCheng C Yang if (hypenPos == std::string::npos) 91*e83604beSCheng C Yang { 92*e83604beSCheng C Yang std::cerr << "Unable to get PSU name from PSU path\n"; 93*e83604beSCheng C Yang return; 94*e83604beSCheng C Yang } 95*e83604beSCheng C Yang std::string psuName = statePSUName.substr(0, hypenPos); 96*e83604beSCheng C Yang 97*e83604beSCheng C Yang try 98*e83604beSCheng C Yang { 99*e83604beSCheng C Yang message.read(objectName, values); 100*e83604beSCheng C Yang } 101*e83604beSCheng C Yang catch (const sdbusplus::exception::exception& e) 102*e83604beSCheng C Yang { 103*e83604beSCheng C Yang std::cerr << "Failed to read message from PSU Event\n"; 104*e83604beSCheng C Yang return; 105*e83604beSCheng C Yang } 106*e83604beSCheng C Yang 107*e83604beSCheng C Yang for (auto& psu : powerSupplies) 108*e83604beSCheng C Yang { 109*e83604beSCheng C Yang if (psu->name != psuName) 110*e83604beSCheng C Yang { 111*e83604beSCheng C Yang continue; 112*e83604beSCheng C Yang } 113*e83604beSCheng C Yang 114*e83604beSCheng C Yang std::string psuEventName = "functional"; 115*e83604beSCheng C Yang auto findEvent = values.find(psuEventName); 116*e83604beSCheng C Yang if (findEvent != values.end()) 117*e83604beSCheng C Yang { 118*e83604beSCheng C Yang bool* functional = std::get_if<bool>(&(findEvent->second)); 119*e83604beSCheng C Yang if (functional == nullptr) 120*e83604beSCheng C Yang { 121*e83604beSCheng C Yang std::cerr << "Unable to get valid functional status\n"; 122*e83604beSCheng C Yang continue; 123*e83604beSCheng C Yang } 124*e83604beSCheng C Yang if (*functional) 125*e83604beSCheng C Yang { 126*e83604beSCheng C Yang psu->state = CR::PSUState::normal; 127*e83604beSCheng C Yang } 128*e83604beSCheng C Yang else 129*e83604beSCheng C Yang { 130*e83604beSCheng C Yang psu->state = CR::PSUState::acLost; 131*e83604beSCheng C Yang } 132*e83604beSCheng C Yang } 133*e83604beSCheng C Yang } 134*e83604beSCheng C Yang }; 135*e83604beSCheng C Yang 136*e83604beSCheng C Yang using namespace sdbusplus::bus::match::rules; 137*e83604beSCheng C Yang for (const char* type : psuInterfaceTypes) 138*e83604beSCheng C Yang { 139*e83604beSCheng C Yang auto match = std::make_unique<sdbusplus::bus::match::match>( 140*e83604beSCheng C Yang static_cast<sdbusplus::bus::bus&>(*systemBus), 141*e83604beSCheng C Yang type::signal() + member("PropertiesChanged") + 142*e83604beSCheng C Yang path_namespace(inventoryPath) + arg0namespace(type), 143*e83604beSCheng C Yang eventHandler); 144*e83604beSCheng C Yang matches.emplace_back(std::move(match)); 145*e83604beSCheng C Yang } 146*e83604beSCheng C Yang 147*e83604beSCheng C Yang for (const char* eventType : psuEventInterface) 148*e83604beSCheng C Yang { 149*e83604beSCheng C Yang auto eventMatch = std::make_unique<sdbusplus::bus::match::match>( 150*e83604beSCheng C Yang static_cast<sdbusplus::bus::bus&>(*systemBus), 151*e83604beSCheng C Yang type::signal() + member("PropertiesChanged") + 152*e83604beSCheng C Yang path_namespace(eventPath) + arg0namespace(eventType), 153*e83604beSCheng C Yang eventCollect); 154*e83604beSCheng C Yang matches.emplace_back(std::move(eventMatch)); 155*e83604beSCheng C Yang } 156*e83604beSCheng C Yang } 157*e83604beSCheng C Yang 158*e83604beSCheng C Yang static const constexpr int psuDepth = 3; 159*e83604beSCheng C Yang // Check PSU information from entity-manager D-Bus interface and use the bus 160*e83604beSCheng C Yang // address to create PSU Class for cold redundancy. 161*e83604beSCheng C Yang void ColdRedundancy::createPSU( 162*e83604beSCheng C Yang std::shared_ptr<sdbusplus::asio::connection>& conn) 163*e83604beSCheng C Yang { 164*e83604beSCheng C Yang numberOfPSU = 0; 165*e83604beSCheng C Yang powerSupplies.clear(); 166*e83604beSCheng C Yang 167*e83604beSCheng C Yang // call mapper to get matched obj paths 168*e83604beSCheng C Yang conn->async_method_call( 169*e83604beSCheng C Yang [this, &conn](const boost::system::error_code ec, 170*e83604beSCheng C Yang CR::GetSubTreeType subtree) { 171*e83604beSCheng C Yang if (ec) 172*e83604beSCheng C Yang { 173*e83604beSCheng C Yang std::cerr << "Exception happened when communicating to " 174*e83604beSCheng C Yang "ObjectMapper\n"; 175*e83604beSCheng C Yang return; 176*e83604beSCheng C Yang } 177*e83604beSCheng C Yang for (const auto& object : subtree) 178*e83604beSCheng C Yang { 179*e83604beSCheng C Yang std::string pathName = object.first; 180*e83604beSCheng C Yang for (const auto& serviceIface : object.second) 181*e83604beSCheng C Yang { 182*e83604beSCheng C Yang std::string serviceName = serviceIface.first; 183*e83604beSCheng C Yang for (const auto& interface : serviceIface.second) 184*e83604beSCheng C Yang { 185*e83604beSCheng C Yang // only get property of matched interface 186*e83604beSCheng C Yang bool isIfaceMatched = false; 187*e83604beSCheng C Yang for (const auto& type : psuInterfaceTypes) 188*e83604beSCheng C Yang { 189*e83604beSCheng C Yang if (type == interface) 190*e83604beSCheng C Yang { 191*e83604beSCheng C Yang isIfaceMatched = true; 192*e83604beSCheng C Yang break; 193*e83604beSCheng C Yang } 194*e83604beSCheng C Yang } 195*e83604beSCheng C Yang if (!isIfaceMatched) 196*e83604beSCheng C Yang continue; 197*e83604beSCheng C Yang 198*e83604beSCheng C Yang conn->async_method_call( 199*e83604beSCheng C Yang [this, &conn, 200*e83604beSCheng C Yang interface](const boost::system::error_code ec, 201*e83604beSCheng C Yang CR::PropertyMapType propMap) { 202*e83604beSCheng C Yang if (ec) 203*e83604beSCheng C Yang { 204*e83604beSCheng C Yang std::cerr 205*e83604beSCheng C Yang << "Exception happened when get all " 206*e83604beSCheng C Yang "properties\n"; 207*e83604beSCheng C Yang return; 208*e83604beSCheng C Yang } 209*e83604beSCheng C Yang 210*e83604beSCheng C Yang auto configName = 211*e83604beSCheng C Yang std::get_if<std::string>(&propMap["Name"]); 212*e83604beSCheng C Yang if (configName == nullptr) 213*e83604beSCheng C Yang { 214*e83604beSCheng C Yang std::cerr << "error finding necessary " 215*e83604beSCheng C Yang "entry in configuration\n"; 216*e83604beSCheng C Yang return; 217*e83604beSCheng C Yang } 218*e83604beSCheng C Yang 219*e83604beSCheng C Yang auto configBus = 220*e83604beSCheng C Yang std::get_if<uint64_t>(&propMap["Bus"]); 221*e83604beSCheng C Yang auto configAddress = 222*e83604beSCheng C Yang std::get_if<uint64_t>(&propMap["Address"]); 223*e83604beSCheng C Yang 224*e83604beSCheng C Yang if (configBus == nullptr || 225*e83604beSCheng C Yang configAddress == nullptr) 226*e83604beSCheng C Yang { 227*e83604beSCheng C Yang std::cerr << "error finding necessary " 228*e83604beSCheng C Yang "entry in configuration\n"; 229*e83604beSCheng C Yang return; 230*e83604beSCheng C Yang } 231*e83604beSCheng C Yang for (auto& psu : powerSupplies) 232*e83604beSCheng C Yang { 233*e83604beSCheng C Yang if ((static_cast<uint8_t>(*configBus) == 234*e83604beSCheng C Yang psu->bus) && 235*e83604beSCheng C Yang (static_cast<uint8_t>(*configAddress) == 236*e83604beSCheng C Yang psu->address)) 237*e83604beSCheng C Yang { 238*e83604beSCheng C Yang return; 239*e83604beSCheng C Yang } 240*e83604beSCheng C Yang } 241*e83604beSCheng C Yang 242*e83604beSCheng C Yang uint8_t order = 0; 243*e83604beSCheng C Yang 244*e83604beSCheng C Yang powerSupplies.emplace_back( 245*e83604beSCheng C Yang std::make_unique<PowerSupply>( 246*e83604beSCheng C Yang *configName, 247*e83604beSCheng C Yang static_cast<uint8_t>(*configBus), 248*e83604beSCheng C Yang static_cast<uint8_t>(*configAddress), 249*e83604beSCheng C Yang order, conn)); 250*e83604beSCheng C Yang 251*e83604beSCheng C Yang numberOfPSU++; 252*e83604beSCheng C Yang std::vector<uint8_t> orders = {}; 253*e83604beSCheng C Yang for (auto& psu : powerSupplies) 254*e83604beSCheng C Yang { 255*e83604beSCheng C Yang orders.push_back(psu->order); 256*e83604beSCheng C Yang } 257*e83604beSCheng C Yang }, 258*e83604beSCheng C Yang serviceName.c_str(), pathName.c_str(), 259*e83604beSCheng C Yang "org.freedesktop.DBus.Properties", "GetAll", 260*e83604beSCheng C Yang interface); 261*e83604beSCheng C Yang } 262*e83604beSCheng C Yang } 263*e83604beSCheng C Yang } 264*e83604beSCheng C Yang }, 265*e83604beSCheng C Yang "xyz.openbmc_project.ObjectMapper", 266*e83604beSCheng C Yang "/xyz/openbmc_project/object_mapper", 267*e83604beSCheng C Yang "xyz.openbmc_project.ObjectMapper", "GetSubTree", 268*e83604beSCheng C Yang "/xyz/openbmc_project/inventory/system", psuDepth, psuInterfaceTypes); 269*e83604beSCheng C Yang } 270*e83604beSCheng C Yang 271*e83604beSCheng C Yang PowerSupply::PowerSupply( 272*e83604beSCheng C Yang std::string& name, uint8_t bus, uint8_t address, uint8_t order, 273*e83604beSCheng C Yang const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection) : 274*e83604beSCheng C Yang name(name), 275*e83604beSCheng C Yang bus(bus), address(address), order(order) 276*e83604beSCheng C Yang { 277*e83604beSCheng C Yang CR::getPSUEvent(dbusConnection, name, state); 278*e83604beSCheng C Yang } 279