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