blob: d13b330edc90726d9bf8170d4d62fb929a2dc8ec [file] [log] [blame]
Cheng C Yange83604b2020-01-09 09:41:47 +08001/*
2// Copyright (c) 2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include "types.hpp"
18
Cheng C Yange83604b2020-01-09 09:41:47 +080019#include <boost/algorithm/string/predicate.hpp>
20#include <boost/algorithm/string/replace.hpp>
21#include <boost/asio/post.hpp>
22#include <boost/container/flat_set.hpp>
23#include <cold_redundancy.hpp>
Cheng C Yange83604b2020-01-09 09:41:47 +080024#include <phosphor-logging/elog-errors.hpp>
Cheng C Yange83604b2020-01-09 09:41:47 +080025#include <sdbusplus/asio/connection.hpp>
26#include <sdbusplus/asio/object_server.hpp>
Cheng C Yange83604b2020-01-09 09:41:47 +080027#include <sdbusplus/bus/match.hpp>
28
Bob King0dcbdf52020-01-20 17:19:39 +080029#include <array>
30#include <filesystem>
31#include <fstream>
32#include <iostream>
33#include <regex>
34
Cheng C Yange83604b2020-01-09 09:41:47 +080035namespace
36{
37constexpr const std::array<const char*, 1> psuInterfaceTypes = {
38 "xyz.openbmc_project.Configuration.pmbus"};
39std::string inventoryPath = std::string(INVENTORY_OBJ_PATH) + "/system";
40const constexpr char* eventPath = "/xyz/openbmc_project/State/Decorator";
41std::vector<std::unique_ptr<PowerSupply>> powerSupplies;
42} // namespace
43
44ColdRedundancy::ColdRedundancy(
45 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
46 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
47 filterTimer(io),
48 systemBus(systemBus)
49{
50 post(io,
51 [this, &io, &objectServer, &systemBus]() { createPSU(systemBus); });
Patrick Williams7354ce62022-07-22 19:26:56 -050052 std::function<void(sdbusplus::message_t&)> eventHandler =
53 [this, &io, &objectServer, &systemBus](sdbusplus::message_t& message) {
Patrick Williams48781ae2023-05-10 07:50:50 -050054 if (message.is_method_error())
55 {
56 std::cerr << "callback method error\n";
57 return;
58 }
59 filterTimer.expires_after(std::chrono::seconds(1));
60 filterTimer.async_wait([this, &io, &objectServer, &systemBus](
61 const boost::system::error_code& ec) {
62 if (ec == boost::asio::error::operation_aborted)
Cheng C Yange83604b2020-01-09 09:41:47 +080063 {
Cheng C Yange83604b2020-01-09 09:41:47 +080064 return;
65 }
Patrick Williams48781ae2023-05-10 07:50:50 -050066 else if (ec)
67 {
68 std::cerr << "timer error\n";
69 }
70 createPSU(systemBus);
71 });
72 };
Cheng C Yange83604b2020-01-09 09:41:47 +080073
Patrick Williams7354ce62022-07-22 19:26:56 -050074 std::function<void(sdbusplus::message_t&)> eventCollect =
75 [&](sdbusplus::message_t& message) {
Patrick Williams48781ae2023-05-10 07:50:50 -050076 std::string objectName;
77 boost::container::flat_map<std::string, std::variant<bool>> values;
78 std::string path = message.get_path();
79 std::size_t slantingPos = path.find_last_of("/\\");
80 if ((slantingPos == std::string::npos) ||
81 ((slantingPos + 1) >= path.size()))
82 {
83 std::cerr << "Unable to get PSU state name from path\n";
84 return;
85 }
86 std::string statePSUName = path.substr(slantingPos + 1);
Cheng C Yange83604b2020-01-09 09:41:47 +080087
Patrick Williams48781ae2023-05-10 07:50:50 -050088 std::size_t hypenPos = statePSUName.find("_");
89 if (hypenPos == std::string::npos)
90 {
91 std::cerr << "Unable to get PSU name from PSU path\n";
92 return;
93 }
94 std::string psuName = statePSUName.substr(0, hypenPos);
Cheng C Yange83604b2020-01-09 09:41:47 +080095
Patrick Williams48781ae2023-05-10 07:50:50 -050096 try
97 {
98 message.read(objectName, values);
99 }
100 catch (const sdbusplus::exception_t& e)
101 {
102 std::cerr << "Failed to read message from PSU Event\n";
103 return;
104 }
105
106 for (auto& psu : powerSupplies)
107 {
108 if (psu->name != psuName)
Cheng C Yange83604b2020-01-09 09:41:47 +0800109 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500110 continue;
Cheng C Yange83604b2020-01-09 09:41:47 +0800111 }
112
Patrick Williams48781ae2023-05-10 07:50:50 -0500113 std::string psuEventName = "functional";
114 auto findEvent = values.find(psuEventName);
115 if (findEvent != values.end())
Cheng C Yange83604b2020-01-09 09:41:47 +0800116 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500117 bool* functional = std::get_if<bool>(&(findEvent->second));
118 if (functional == nullptr)
Cheng C Yange83604b2020-01-09 09:41:47 +0800119 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500120 std::cerr << "Unable to get valid functional status\n";
Cheng C Yange83604b2020-01-09 09:41:47 +0800121 continue;
122 }
Patrick Williams48781ae2023-05-10 07:50:50 -0500123 if (*functional)
Cheng C Yange83604b2020-01-09 09:41:47 +0800124 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500125 psu->state = CR::PSUState::normal;
126 }
127 else
128 {
129 psu->state = CR::PSUState::acLost;
Cheng C Yange83604b2020-01-09 09:41:47 +0800130 }
131 }
Patrick Williams48781ae2023-05-10 07:50:50 -0500132 }
133 };
Cheng C Yange83604b2020-01-09 09:41:47 +0800134
135 using namespace sdbusplus::bus::match::rules;
136 for (const char* type : psuInterfaceTypes)
137 {
Patrick Williams7354ce62022-07-22 19:26:56 -0500138 auto match = std::make_unique<sdbusplus::bus::match_t>(
139 static_cast<sdbusplus::bus_t&>(*systemBus),
Cheng C Yange83604b2020-01-09 09:41:47 +0800140 type::signal() + member("PropertiesChanged") +
141 path_namespace(inventoryPath) + arg0namespace(type),
142 eventHandler);
143 matches.emplace_back(std::move(match));
144 }
145
146 for (const char* eventType : psuEventInterface)
147 {
Patrick Williams7354ce62022-07-22 19:26:56 -0500148 auto eventMatch = std::make_unique<sdbusplus::bus::match_t>(
149 static_cast<sdbusplus::bus_t&>(*systemBus),
Cheng C Yange83604b2020-01-09 09:41:47 +0800150 type::signal() + member("PropertiesChanged") +
151 path_namespace(eventPath) + arg0namespace(eventType),
152 eventCollect);
153 matches.emplace_back(std::move(eventMatch));
154 }
155}
156
157static const constexpr int psuDepth = 3;
158// Check PSU information from entity-manager D-Bus interface and use the bus
159// address to create PSU Class for cold redundancy.
160void ColdRedundancy::createPSU(
161 std::shared_ptr<sdbusplus::asio::connection>& conn)
162{
163 numberOfPSU = 0;
164 powerSupplies.clear();
165
166 // call mapper to get matched obj paths
167 conn->async_method_call(
168 [this, &conn](const boost::system::error_code ec,
169 CR::GetSubTreeType subtree) {
Patrick Williams48781ae2023-05-10 07:50:50 -0500170 if (ec)
171 {
172 std::cerr << "Exception happened when communicating to "
173 "ObjectMapper\n";
174 return;
175 }
176 for (const auto& object : subtree)
177 {
178 std::string pathName = object.first;
179 for (const auto& serviceIface : object.second)
Cheng C Yange83604b2020-01-09 09:41:47 +0800180 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500181 std::string serviceName = serviceIface.first;
182 for (const auto& interface : serviceIface.second)
Cheng C Yange83604b2020-01-09 09:41:47 +0800183 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500184 // only get property of matched interface
185 bool isIfaceMatched = false;
186 for (const auto& type : psuInterfaceTypes)
Cheng C Yange83604b2020-01-09 09:41:47 +0800187 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500188 if (type == interface)
Cheng C Yange83604b2020-01-09 09:41:47 +0800189 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500190 isIfaceMatched = true;
191 break;
192 }
193 }
194 if (!isIfaceMatched)
195 continue;
196
197 conn->async_method_call(
198 [this, &conn,
199 interface](const boost::system::error_code ec,
200 CR::PropertyMapType propMap) {
201 if (ec)
202 {
203 std::cerr << "Exception happened when get all "
204 "properties\n";
205 return;
206 }
207
208 auto configName =
209 std::get_if<std::string>(&propMap["Name"]);
210 if (configName == nullptr)
211 {
212 std::cerr << "error finding necessary "
213 "entry in configuration\n";
214 return;
215 }
216
217 auto configBus = std::get_if<uint64_t>(&propMap["Bus"]);
218 auto configAddress =
219 std::get_if<uint64_t>(&propMap["Address"]);
220
221 if (configBus == nullptr || configAddress == nullptr)
222 {
223 std::cerr << "error finding necessary "
224 "entry in configuration\n";
225 return;
226 }
227 for (auto& psu : powerSupplies)
228 {
229 if ((static_cast<uint8_t>(*configBus) ==
230 psu->bus) &&
231 (static_cast<uint8_t>(*configAddress) ==
232 psu->address))
Cheng C Yange83604b2020-01-09 09:41:47 +0800233 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500234 return;
Cheng C Yange83604b2020-01-09 09:41:47 +0800235 }
236 }
Cheng C Yange83604b2020-01-09 09:41:47 +0800237
Patrick Williams48781ae2023-05-10 07:50:50 -0500238 uint8_t order = 0;
Cheng C Yange83604b2020-01-09 09:41:47 +0800239
Patrick Williams48781ae2023-05-10 07:50:50 -0500240 powerSupplies.emplace_back(
241 std::make_unique<PowerSupply>(
242 *configName, static_cast<uint8_t>(*configBus),
243 static_cast<uint8_t>(*configAddress), order,
244 conn));
Cheng C Yange83604b2020-01-09 09:41:47 +0800245
Patrick Williams48781ae2023-05-10 07:50:50 -0500246 numberOfPSU++;
247 std::vector<uint8_t> orders = {};
248 for (auto& psu : powerSupplies)
249 {
250 orders.push_back(psu->order);
251 }
Patrick Williams319b0dd2023-10-20 11:19:11 -0500252 },
Patrick Williams48781ae2023-05-10 07:50:50 -0500253 serviceName.c_str(), pathName.c_str(),
254 "org.freedesktop.DBus.Properties", "GetAll", interface);
Cheng C Yange83604b2020-01-09 09:41:47 +0800255 }
256 }
Patrick Williams48781ae2023-05-10 07:50:50 -0500257 }
Patrick Williams319b0dd2023-10-20 11:19:11 -0500258 },
Cheng C Yange83604b2020-01-09 09:41:47 +0800259 "xyz.openbmc_project.ObjectMapper",
260 "/xyz/openbmc_project/object_mapper",
261 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
262 "/xyz/openbmc_project/inventory/system", psuDepth, psuInterfaceTypes);
263}
264
265PowerSupply::PowerSupply(
266 std::string& name, uint8_t bus, uint8_t address, uint8_t order,
267 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection) :
268 name(name),
269 bus(bus), address(address), order(order)
270{
271 CR::getPSUEvent(dbusConnection, name, state);
272}