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/bus/match.hpp>
28e83604beSCheng C Yang
290dcbdf57SBob King #include <array>
300dcbdf57SBob King #include <filesystem>
310dcbdf57SBob King #include <fstream>
320dcbdf57SBob King #include <iostream>
330dcbdf57SBob King #include <regex>
340dcbdf57SBob King
35e83604beSCheng C Yang namespace
36e83604beSCheng C Yang {
37e83604beSCheng C Yang constexpr const std::array<const char*, 1> psuInterfaceTypes = {
38e83604beSCheng C Yang "xyz.openbmc_project.Configuration.pmbus"};
39e83604beSCheng C Yang std::string inventoryPath = std::string(INVENTORY_OBJ_PATH) + "/system";
40e83604beSCheng C Yang const constexpr char* eventPath = "/xyz/openbmc_project/State/Decorator";
41e83604beSCheng C Yang std::vector<std::unique_ptr<PowerSupply>> powerSupplies;
42e83604beSCheng C Yang } // namespace
43e83604beSCheng C Yang
ColdRedundancy(boost::asio::io_service & io,sdbusplus::asio::object_server & objectServer,std::shared_ptr<sdbusplus::asio::connection> & systemBus)44e83604beSCheng C Yang ColdRedundancy::ColdRedundancy(
45e83604beSCheng C Yang boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
46e83604beSCheng C Yang std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
47*f5402197SPatrick Williams filterTimer(io), systemBus(systemBus)
48e83604beSCheng C Yang {
49e83604beSCheng C Yang post(io,
50e83604beSCheng C Yang [this, &io, &objectServer, &systemBus]() { createPSU(systemBus); });
517354ce62SPatrick Williams std::function<void(sdbusplus::message_t&)> eventHandler =
527354ce62SPatrick Williams [this, &io, &objectServer, &systemBus](sdbusplus::message_t& message) {
53e83604beSCheng C Yang if (message.is_method_error())
54e83604beSCheng C Yang {
55e83604beSCheng C Yang std::cerr << "callback method error\n";
56e83604beSCheng C Yang return;
57e83604beSCheng C Yang }
58e83604beSCheng C Yang filterTimer.expires_after(std::chrono::seconds(1));
59e83604beSCheng C Yang filterTimer.async_wait([this, &io, &objectServer, &systemBus](
60e83604beSCheng C Yang const boost::system::error_code& ec) {
61e83604beSCheng C Yang if (ec == boost::asio::error::operation_aborted)
62e83604beSCheng C Yang {
63e83604beSCheng C Yang return;
64e83604beSCheng C Yang }
65e83604beSCheng C Yang else if (ec)
66e83604beSCheng C Yang {
67e83604beSCheng C Yang std::cerr << "timer error\n";
68e83604beSCheng C Yang }
69e83604beSCheng C Yang createPSU(systemBus);
70e83604beSCheng C Yang });
71e83604beSCheng C Yang };
72e83604beSCheng C Yang
737354ce62SPatrick Williams std::function<void(sdbusplus::message_t&)> eventCollect =
747354ce62SPatrick Williams [&](sdbusplus::message_t& message) {
75e83604beSCheng C Yang std::string objectName;
76e83604beSCheng C Yang boost::container::flat_map<std::string, std::variant<bool>> values;
77e83604beSCheng C Yang std::string path = message.get_path();
78e83604beSCheng C Yang std::size_t slantingPos = path.find_last_of("/\\");
79e83604beSCheng C Yang if ((slantingPos == std::string::npos) ||
80e83604beSCheng C Yang ((slantingPos + 1) >= path.size()))
81e83604beSCheng C Yang {
82e83604beSCheng C Yang std::cerr << "Unable to get PSU state name from path\n";
83e83604beSCheng C Yang return;
84e83604beSCheng C Yang }
85e83604beSCheng C Yang std::string statePSUName = path.substr(slantingPos + 1);
86e83604beSCheng C Yang
87e83604beSCheng C Yang std::size_t hypenPos = statePSUName.find("_");
88e83604beSCheng C Yang if (hypenPos == std::string::npos)
89e83604beSCheng C Yang {
90e83604beSCheng C Yang std::cerr << "Unable to get PSU name from PSU path\n";
91e83604beSCheng C Yang return;
92e83604beSCheng C Yang }
93e83604beSCheng C Yang std::string psuName = statePSUName.substr(0, hypenPos);
94e83604beSCheng C Yang
95e83604beSCheng C Yang try
96e83604beSCheng C Yang {
97e83604beSCheng C Yang message.read(objectName, values);
98e83604beSCheng C Yang }
997354ce62SPatrick Williams catch (const sdbusplus::exception_t& e)
100e83604beSCheng C Yang {
101e83604beSCheng C Yang std::cerr << "Failed to read message from PSU Event\n";
102e83604beSCheng C Yang return;
103e83604beSCheng C Yang }
104e83604beSCheng C Yang
105e83604beSCheng C Yang for (auto& psu : powerSupplies)
106e83604beSCheng C Yang {
107e83604beSCheng C Yang if (psu->name != psuName)
108e83604beSCheng C Yang {
109e83604beSCheng C Yang continue;
110e83604beSCheng C Yang }
111e83604beSCheng C Yang
112e83604beSCheng C Yang std::string psuEventName = "functional";
113e83604beSCheng C Yang auto findEvent = values.find(psuEventName);
114e83604beSCheng C Yang if (findEvent != values.end())
115e83604beSCheng C Yang {
116e83604beSCheng C Yang bool* functional = std::get_if<bool>(&(findEvent->second));
117e83604beSCheng C Yang if (functional == nullptr)
118e83604beSCheng C Yang {
119e83604beSCheng C Yang std::cerr << "Unable to get valid functional status\n";
120e83604beSCheng C Yang continue;
121e83604beSCheng C Yang }
122e83604beSCheng C Yang if (*functional)
123e83604beSCheng C Yang {
124e83604beSCheng C Yang psu->state = CR::PSUState::normal;
125e83604beSCheng C Yang }
126e83604beSCheng C Yang else
127e83604beSCheng C Yang {
128e83604beSCheng C Yang psu->state = CR::PSUState::acLost;
129e83604beSCheng C Yang }
130e83604beSCheng C Yang }
131e83604beSCheng C Yang }
132e83604beSCheng C Yang };
133e83604beSCheng C Yang
134e83604beSCheng C Yang using namespace sdbusplus::bus::match::rules;
135e83604beSCheng C Yang for (const char* type : psuInterfaceTypes)
136e83604beSCheng C Yang {
1377354ce62SPatrick Williams auto match = std::make_unique<sdbusplus::bus::match_t>(
1387354ce62SPatrick Williams static_cast<sdbusplus::bus_t&>(*systemBus),
139e83604beSCheng C Yang type::signal() + member("PropertiesChanged") +
140e83604beSCheng C Yang path_namespace(inventoryPath) + arg0namespace(type),
141e83604beSCheng C Yang eventHandler);
142e83604beSCheng C Yang matches.emplace_back(std::move(match));
143e83604beSCheng C Yang }
144e83604beSCheng C Yang
145e83604beSCheng C Yang for (const char* eventType : psuEventInterface)
146e83604beSCheng C Yang {
1477354ce62SPatrick Williams auto eventMatch = std::make_unique<sdbusplus::bus::match_t>(
1487354ce62SPatrick Williams static_cast<sdbusplus::bus_t&>(*systemBus),
149e83604beSCheng C Yang type::signal() + member("PropertiesChanged") +
150e83604beSCheng C Yang path_namespace(eventPath) + arg0namespace(eventType),
151e83604beSCheng C Yang eventCollect);
152e83604beSCheng C Yang matches.emplace_back(std::move(eventMatch));
153e83604beSCheng C Yang }
154e83604beSCheng C Yang }
155e83604beSCheng C Yang
156e83604beSCheng C Yang static const constexpr int psuDepth = 3;
157e83604beSCheng C Yang // Check PSU information from entity-manager D-Bus interface and use the bus
158e83604beSCheng C Yang // address to create PSU Class for cold redundancy.
createPSU(std::shared_ptr<sdbusplus::asio::connection> & conn)159e83604beSCheng C Yang void ColdRedundancy::createPSU(
160e83604beSCheng C Yang std::shared_ptr<sdbusplus::asio::connection>& conn)
161e83604beSCheng C Yang {
162e83604beSCheng C Yang numberOfPSU = 0;
163e83604beSCheng C Yang powerSupplies.clear();
164e83604beSCheng C Yang
165e83604beSCheng C Yang // call mapper to get matched obj paths
166e83604beSCheng C Yang conn->async_method_call(
167e83604beSCheng C Yang [this, &conn](const boost::system::error_code ec,
168e83604beSCheng C Yang CR::GetSubTreeType subtree) {
169e83604beSCheng C Yang if (ec)
170e83604beSCheng C Yang {
171e83604beSCheng C Yang std::cerr << "Exception happened when communicating to "
172e83604beSCheng C Yang "ObjectMapper\n";
173e83604beSCheng C Yang return;
174e83604beSCheng C Yang }
175e83604beSCheng C Yang for (const auto& object : subtree)
176e83604beSCheng C Yang {
177e83604beSCheng C Yang std::string pathName = object.first;
178e83604beSCheng C Yang for (const auto& serviceIface : object.second)
179e83604beSCheng C Yang {
180e83604beSCheng C Yang std::string serviceName = serviceIface.first;
181e83604beSCheng C Yang for (const auto& interface : serviceIface.second)
182e83604beSCheng C Yang {
183e83604beSCheng C Yang // only get property of matched interface
184e83604beSCheng C Yang bool isIfaceMatched = false;
185e83604beSCheng C Yang for (const auto& type : psuInterfaceTypes)
186e83604beSCheng C Yang {
187e83604beSCheng C Yang if (type == interface)
188e83604beSCheng C Yang {
189e83604beSCheng C Yang isIfaceMatched = true;
190e83604beSCheng C Yang break;
191e83604beSCheng C Yang }
192e83604beSCheng C Yang }
193e83604beSCheng C Yang if (!isIfaceMatched)
194e83604beSCheng C Yang continue;
195e83604beSCheng C Yang
196e83604beSCheng C Yang conn->async_method_call(
197e83604beSCheng C Yang [this, &conn,
198e83604beSCheng C Yang interface](const boost::system::error_code ec,
199e83604beSCheng C Yang CR::PropertyMapType propMap) {
200e83604beSCheng C Yang if (ec)
201e83604beSCheng C Yang {
202*f5402197SPatrick Williams std::cerr
203*f5402197SPatrick Williams << "Exception happened when get all "
204e83604beSCheng C Yang "properties\n";
205e83604beSCheng C Yang return;
206e83604beSCheng C Yang }
207e83604beSCheng C Yang
208e83604beSCheng C Yang auto configName =
209e83604beSCheng C Yang std::get_if<std::string>(&propMap["Name"]);
210e83604beSCheng C Yang if (configName == nullptr)
211e83604beSCheng C Yang {
212e83604beSCheng C Yang std::cerr << "error finding necessary "
213e83604beSCheng C Yang "entry in configuration\n";
214e83604beSCheng C Yang return;
215e83604beSCheng C Yang }
216e83604beSCheng C Yang
217*f5402197SPatrick Williams auto configBus =
218*f5402197SPatrick Williams std::get_if<uint64_t>(&propMap["Bus"]);
219e83604beSCheng C Yang auto configAddress =
220e83604beSCheng C Yang std::get_if<uint64_t>(&propMap["Address"]);
221e83604beSCheng C Yang
222*f5402197SPatrick Williams if (configBus == nullptr ||
223*f5402197SPatrick Williams configAddress == nullptr)
224e83604beSCheng C Yang {
225e83604beSCheng C Yang std::cerr << "error finding necessary "
226e83604beSCheng C Yang "entry in configuration\n";
227e83604beSCheng C Yang return;
228e83604beSCheng C Yang }
229e83604beSCheng C Yang for (auto& psu : powerSupplies)
230e83604beSCheng C Yang {
231e83604beSCheng C Yang if ((static_cast<uint8_t>(*configBus) ==
232e83604beSCheng C Yang psu->bus) &&
233e83604beSCheng C Yang (static_cast<uint8_t>(*configAddress) ==
234e83604beSCheng C Yang psu->address))
235e83604beSCheng C Yang {
236e83604beSCheng C Yang return;
237e83604beSCheng C Yang }
238e83604beSCheng C Yang }
239e83604beSCheng C Yang
240e83604beSCheng C Yang uint8_t order = 0;
241e83604beSCheng C Yang
242e83604beSCheng C Yang powerSupplies.emplace_back(
243e83604beSCheng C Yang std::make_unique<PowerSupply>(
244*f5402197SPatrick Williams *configName,
245*f5402197SPatrick Williams static_cast<uint8_t>(*configBus),
246*f5402197SPatrick Williams static_cast<uint8_t>(*configAddress),
247*f5402197SPatrick Williams order, conn));
248e83604beSCheng C Yang
249e83604beSCheng C Yang numberOfPSU++;
250e83604beSCheng C Yang std::vector<uint8_t> orders = {};
251e83604beSCheng C Yang for (auto& psu : powerSupplies)
252e83604beSCheng C Yang {
253e83604beSCheng C Yang orders.push_back(psu->order);
254e83604beSCheng C Yang }
255e83604beSCheng C Yang },
256e83604beSCheng C Yang serviceName.c_str(), pathName.c_str(),
257*f5402197SPatrick Williams "org.freedesktop.DBus.Properties", "GetAll",
258*f5402197SPatrick Williams interface);
259e83604beSCheng C Yang }
260e83604beSCheng C Yang }
261e83604beSCheng C Yang }
262e83604beSCheng C Yang },
263e83604beSCheng C Yang "xyz.openbmc_project.ObjectMapper",
264e83604beSCheng C Yang "/xyz/openbmc_project/object_mapper",
265e83604beSCheng C Yang "xyz.openbmc_project.ObjectMapper", "GetSubTree",
266e83604beSCheng C Yang "/xyz/openbmc_project/inventory/system", psuDepth, psuInterfaceTypes);
267e83604beSCheng C Yang }
268e83604beSCheng C Yang
PowerSupply(std::string & name,uint8_t bus,uint8_t address,uint8_t order,const std::shared_ptr<sdbusplus::asio::connection> & dbusConnection)269e83604beSCheng C Yang PowerSupply::PowerSupply(
270e83604beSCheng C Yang std::string& name, uint8_t bus, uint8_t address, uint8_t order,
271e83604beSCheng C Yang const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection) :
272*f5402197SPatrick Williams name(name), bus(bus), address(address), order(order)
273e83604beSCheng C Yang {
274e83604beSCheng C Yang CR::getPSUEvent(dbusConnection, name, state);
275e83604beSCheng C Yang }
276