/* // Copyright (c) 2019 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ #include "types.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr const std::array psuInterfaceTypes = { "xyz.openbmc_project.Configuration.pmbus"}; std::string inventoryPath = std::string(INVENTORY_OBJ_PATH) + "/system"; const constexpr char* eventPath = "/xyz/openbmc_project/State/Decorator"; std::vector> powerSupplies; } // namespace ColdRedundancy::ColdRedundancy( boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer, std::shared_ptr& systemBus) : filterTimer(io), systemBus(systemBus) { post(io, [this, &io, &objectServer, &systemBus]() { createPSU(systemBus); }); std::function eventHandler = [this, &io, &objectServer, &systemBus](sdbusplus::message_t& message) { if (message.is_method_error()) { std::cerr << "callback method error\n"; return; } filterTimer.expires_after(std::chrono::seconds(1)); filterTimer.async_wait([this, &io, &objectServer, &systemBus]( const boost::system::error_code& ec) { if (ec == boost::asio::error::operation_aborted) { return; } else if (ec) { std::cerr << "timer error\n"; } createPSU(systemBus); }); }; std::function eventCollect = [&](sdbusplus::message_t& message) { std::string objectName; boost::container::flat_map> values; std::string path = message.get_path(); std::size_t slantingPos = path.find_last_of("/\\"); if ((slantingPos == std::string::npos) || ((slantingPos + 1) >= path.size())) { std::cerr << "Unable to get PSU state name from path\n"; return; } std::string statePSUName = path.substr(slantingPos + 1); std::size_t hypenPos = statePSUName.find("_"); if (hypenPos == std::string::npos) { std::cerr << "Unable to get PSU name from PSU path\n"; return; } std::string psuName = statePSUName.substr(0, hypenPos); try { message.read(objectName, values); } catch (const sdbusplus::exception_t& e) { std::cerr << "Failed to read message from PSU Event\n"; return; } for (auto& psu : powerSupplies) { if (psu->name != psuName) { continue; } std::string psuEventName = "functional"; auto findEvent = values.find(psuEventName); if (findEvent != values.end()) { bool* functional = std::get_if(&(findEvent->second)); if (functional == nullptr) { std::cerr << "Unable to get valid functional status\n"; continue; } if (*functional) { psu->state = CR::PSUState::normal; } else { psu->state = CR::PSUState::acLost; } } } }; using namespace sdbusplus::bus::match::rules; for (const char* type : psuInterfaceTypes) { auto match = std::make_unique( static_cast(*systemBus), type::signal() + member("PropertiesChanged") + path_namespace(inventoryPath) + arg0namespace(type), eventHandler); matches.emplace_back(std::move(match)); } for (const char* eventType : psuEventInterface) { auto eventMatch = std::make_unique( static_cast(*systemBus), type::signal() + member("PropertiesChanged") + path_namespace(eventPath) + arg0namespace(eventType), eventCollect); matches.emplace_back(std::move(eventMatch)); } } static const constexpr int psuDepth = 3; // Check PSU information from entity-manager D-Bus interface and use the bus // address to create PSU Class for cold redundancy. void ColdRedundancy::createPSU( std::shared_ptr& conn) { numberOfPSU = 0; powerSupplies.clear(); // call mapper to get matched obj paths conn->async_method_call( [this, &conn](const boost::system::error_code ec, CR::GetSubTreeType subtree) { if (ec) { std::cerr << "Exception happened when communicating to " "ObjectMapper\n"; return; } for (const auto& object : subtree) { std::string pathName = object.first; for (const auto& serviceIface : object.second) { std::string serviceName = serviceIface.first; for (const auto& interface : serviceIface.second) { // only get property of matched interface bool isIfaceMatched = false; for (const auto& type : psuInterfaceTypes) { if (type == interface) { isIfaceMatched = true; break; } } if (!isIfaceMatched) continue; conn->async_method_call( [this, &conn, interface](const boost::system::error_code ec, CR::PropertyMapType propMap) { if (ec) { std::cerr << "Exception happened when get all " "properties\n"; return; } auto configName = std::get_if(&propMap["Name"]); if (configName == nullptr) { std::cerr << "error finding necessary " "entry in configuration\n"; return; } auto configBus = std::get_if(&propMap["Bus"]); auto configAddress = std::get_if(&propMap["Address"]); if (configBus == nullptr || configAddress == nullptr) { std::cerr << "error finding necessary " "entry in configuration\n"; return; } for (auto& psu : powerSupplies) { if ((static_cast(*configBus) == psu->bus) && (static_cast(*configAddress) == psu->address)) { return; } } uint8_t order = 0; powerSupplies.emplace_back( std::make_unique( *configName, static_cast(*configBus), static_cast(*configAddress), order, conn)); numberOfPSU++; std::vector orders = {}; for (auto& psu : powerSupplies) { orders.push_back(psu->order); } }, serviceName.c_str(), pathName.c_str(), "org.freedesktop.DBus.Properties", "GetAll", interface); } } } }, "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper", "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/xyz/openbmc_project/inventory/system", psuDepth, psuInterfaceTypes); } PowerSupply::PowerSupply( std::string& name, uint8_t bus, uint8_t address, uint8_t order, const std::shared_ptr& dbusConnection) : name(name), bus(bus), address(address), order(order) { CR::getPSUEvent(dbusConnection, name, state); }