blob: 5554f8532a3c978d485f6bacb50ec9c4e04762cb [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>
27#include <sdbusplus/asio/sd_event.hpp>
28#include <sdbusplus/bus/match.hpp>
29
Bob King0dcbdf52020-01-20 17:19:39 +080030#include <array>
31#include <filesystem>
32#include <fstream>
33#include <iostream>
34#include <regex>
35
Cheng C Yange83604b2020-01-09 09:41:47 +080036namespace
37{
38constexpr const std::array<const char*, 1> psuInterfaceTypes = {
39 "xyz.openbmc_project.Configuration.pmbus"};
40std::string inventoryPath = std::string(INVENTORY_OBJ_PATH) + "/system";
41const constexpr char* eventPath = "/xyz/openbmc_project/State/Decorator";
42std::vector<std::unique_ptr<PowerSupply>> powerSupplies;
43} // namespace
44
45ColdRedundancy::ColdRedundancy(
46 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
47 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
48 filterTimer(io),
49 systemBus(systemBus)
50{
51 post(io,
52 [this, &io, &objectServer, &systemBus]() { createPSU(systemBus); });
Patrick Williams7354ce62022-07-22 19:26:56 -050053 std::function<void(sdbusplus::message_t&)> eventHandler =
54 [this, &io, &objectServer, &systemBus](sdbusplus::message_t& message) {
Patrick Williams48781ae2023-05-10 07:50:50 -050055 if (message.is_method_error())
56 {
57 std::cerr << "callback method error\n";
58 return;
59 }
60 filterTimer.expires_after(std::chrono::seconds(1));
61 filterTimer.async_wait([this, &io, &objectServer, &systemBus](
62 const boost::system::error_code& ec) {
63 if (ec == boost::asio::error::operation_aborted)
Cheng C Yange83604b2020-01-09 09:41:47 +080064 {
Cheng C Yange83604b2020-01-09 09:41:47 +080065 return;
66 }
Patrick Williams48781ae2023-05-10 07:50:50 -050067 else if (ec)
68 {
69 std::cerr << "timer error\n";
70 }
71 createPSU(systemBus);
72 });
73 };
Cheng C Yange83604b2020-01-09 09:41:47 +080074
Patrick Williams7354ce62022-07-22 19:26:56 -050075 std::function<void(sdbusplus::message_t&)> eventCollect =
76 [&](sdbusplus::message_t& message) {
Patrick Williams48781ae2023-05-10 07:50:50 -050077 std::string objectName;
78 boost::container::flat_map<std::string, std::variant<bool>> values;
79 std::string path = message.get_path();
80 std::size_t slantingPos = path.find_last_of("/\\");
81 if ((slantingPos == std::string::npos) ||
82 ((slantingPos + 1) >= path.size()))
83 {
84 std::cerr << "Unable to get PSU state name from path\n";
85 return;
86 }
87 std::string statePSUName = path.substr(slantingPos + 1);
Cheng C Yange83604b2020-01-09 09:41:47 +080088
Patrick Williams48781ae2023-05-10 07:50:50 -050089 std::size_t hypenPos = statePSUName.find("_");
90 if (hypenPos == std::string::npos)
91 {
92 std::cerr << "Unable to get PSU name from PSU path\n";
93 return;
94 }
95 std::string psuName = statePSUName.substr(0, hypenPos);
Cheng C Yange83604b2020-01-09 09:41:47 +080096
Patrick Williams48781ae2023-05-10 07:50:50 -050097 try
98 {
99 message.read(objectName, values);
100 }
101 catch (const sdbusplus::exception_t& e)
102 {
103 std::cerr << "Failed to read message from PSU Event\n";
104 return;
105 }
106
107 for (auto& psu : powerSupplies)
108 {
109 if (psu->name != psuName)
Cheng C Yange83604b2020-01-09 09:41:47 +0800110 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500111 continue;
Cheng C Yange83604b2020-01-09 09:41:47 +0800112 }
113
Patrick Williams48781ae2023-05-10 07:50:50 -0500114 std::string psuEventName = "functional";
115 auto findEvent = values.find(psuEventName);
116 if (findEvent != values.end())
Cheng C Yange83604b2020-01-09 09:41:47 +0800117 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500118 bool* functional = std::get_if<bool>(&(findEvent->second));
119 if (functional == nullptr)
Cheng C Yange83604b2020-01-09 09:41:47 +0800120 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500121 std::cerr << "Unable to get valid functional status\n";
Cheng C Yange83604b2020-01-09 09:41:47 +0800122 continue;
123 }
Patrick Williams48781ae2023-05-10 07:50:50 -0500124 if (*functional)
Cheng C Yange83604b2020-01-09 09:41:47 +0800125 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500126 psu->state = CR::PSUState::normal;
127 }
128 else
129 {
130 psu->state = CR::PSUState::acLost;
Cheng C Yange83604b2020-01-09 09:41:47 +0800131 }
132 }
Patrick Williams48781ae2023-05-10 07:50:50 -0500133 }
134 };
Cheng C Yange83604b2020-01-09 09:41:47 +0800135
136 using namespace sdbusplus::bus::match::rules;
137 for (const char* type : psuInterfaceTypes)
138 {
Patrick Williams7354ce62022-07-22 19:26:56 -0500139 auto match = std::make_unique<sdbusplus::bus::match_t>(
140 static_cast<sdbusplus::bus_t&>(*systemBus),
Cheng C Yange83604b2020-01-09 09:41:47 +0800141 type::signal() + member("PropertiesChanged") +
142 path_namespace(inventoryPath) + arg0namespace(type),
143 eventHandler);
144 matches.emplace_back(std::move(match));
145 }
146
147 for (const char* eventType : psuEventInterface)
148 {
Patrick Williams7354ce62022-07-22 19:26:56 -0500149 auto eventMatch = std::make_unique<sdbusplus::bus::match_t>(
150 static_cast<sdbusplus::bus_t&>(*systemBus),
Cheng C Yange83604b2020-01-09 09:41:47 +0800151 type::signal() + member("PropertiesChanged") +
152 path_namespace(eventPath) + arg0namespace(eventType),
153 eventCollect);
154 matches.emplace_back(std::move(eventMatch));
155 }
156}
157
158static const constexpr int psuDepth = 3;
159// Check PSU information from entity-manager D-Bus interface and use the bus
160// address to create PSU Class for cold redundancy.
161void ColdRedundancy::createPSU(
162 std::shared_ptr<sdbusplus::asio::connection>& conn)
163{
164 numberOfPSU = 0;
165 powerSupplies.clear();
166
167 // call mapper to get matched obj paths
168 conn->async_method_call(
169 [this, &conn](const boost::system::error_code ec,
170 CR::GetSubTreeType subtree) {
Patrick Williams48781ae2023-05-10 07:50:50 -0500171 if (ec)
172 {
173 std::cerr << "Exception happened when communicating to "
174 "ObjectMapper\n";
175 return;
176 }
177 for (const auto& object : subtree)
178 {
179 std::string pathName = object.first;
180 for (const auto& serviceIface : object.second)
Cheng C Yange83604b2020-01-09 09:41:47 +0800181 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500182 std::string serviceName = serviceIface.first;
183 for (const auto& interface : serviceIface.second)
Cheng C Yange83604b2020-01-09 09:41:47 +0800184 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500185 // only get property of matched interface
186 bool isIfaceMatched = false;
187 for (const auto& type : psuInterfaceTypes)
Cheng C Yange83604b2020-01-09 09:41:47 +0800188 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500189 if (type == interface)
Cheng C Yange83604b2020-01-09 09:41:47 +0800190 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500191 isIfaceMatched = true;
192 break;
193 }
194 }
195 if (!isIfaceMatched)
196 continue;
197
198 conn->async_method_call(
199 [this, &conn,
200 interface](const boost::system::error_code ec,
201 CR::PropertyMapType propMap) {
202 if (ec)
203 {
204 std::cerr << "Exception happened when get all "
205 "properties\n";
206 return;
207 }
208
209 auto configName =
210 std::get_if<std::string>(&propMap["Name"]);
211 if (configName == nullptr)
212 {
213 std::cerr << "error finding necessary "
214 "entry in configuration\n";
215 return;
216 }
217
218 auto configBus = std::get_if<uint64_t>(&propMap["Bus"]);
219 auto configAddress =
220 std::get_if<uint64_t>(&propMap["Address"]);
221
222 if (configBus == nullptr || configAddress == nullptr)
223 {
224 std::cerr << "error finding necessary "
225 "entry in configuration\n";
226 return;
227 }
228 for (auto& psu : powerSupplies)
229 {
230 if ((static_cast<uint8_t>(*configBus) ==
231 psu->bus) &&
232 (static_cast<uint8_t>(*configAddress) ==
233 psu->address))
Cheng C Yange83604b2020-01-09 09:41:47 +0800234 {
Patrick Williams48781ae2023-05-10 07:50:50 -0500235 return;
Cheng C Yange83604b2020-01-09 09:41:47 +0800236 }
237 }
Cheng C Yange83604b2020-01-09 09:41:47 +0800238
Patrick Williams48781ae2023-05-10 07:50:50 -0500239 uint8_t order = 0;
Cheng C Yange83604b2020-01-09 09:41:47 +0800240
Patrick Williams48781ae2023-05-10 07:50:50 -0500241 powerSupplies.emplace_back(
242 std::make_unique<PowerSupply>(
243 *configName, static_cast<uint8_t>(*configBus),
244 static_cast<uint8_t>(*configAddress), order,
245 conn));
Cheng C Yange83604b2020-01-09 09:41:47 +0800246
Patrick Williams48781ae2023-05-10 07:50:50 -0500247 numberOfPSU++;
248 std::vector<uint8_t> orders = {};
249 for (auto& psu : powerSupplies)
250 {
251 orders.push_back(psu->order);
252 }
253 },
254 serviceName.c_str(), pathName.c_str(),
255 "org.freedesktop.DBus.Properties", "GetAll", interface);
Cheng C Yange83604b2020-01-09 09:41:47 +0800256 }
257 }
Patrick Williams48781ae2023-05-10 07:50:50 -0500258 }
Cheng C Yange83604b2020-01-09 09:41:47 +0800259 },
260 "xyz.openbmc_project.ObjectMapper",
261 "/xyz/openbmc_project/object_mapper",
262 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
263 "/xyz/openbmc_project/inventory/system", psuDepth, psuInterfaceTypes);
264}
265
266PowerSupply::PowerSupply(
267 std::string& name, uint8_t bus, uint8_t address, uint8_t order,
268 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection) :
269 name(name),
270 bus(bus), address(address), order(order)
271{
272 CR::getPSUEvent(dbusConnection, name, state);
273}