blob: c912ed2a4a2d9a88a56ea55e5f2567e45b7c45f1 [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(
Jayanth Othayoth5ed2eb42024-12-07 03:27:33 -060045 boost::asio::io_service& io,
Cheng C Yange83604b2020-01-09 09:41:47 +080046 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
Patrick Williamsf5402192024-08-16 15:20:53 -040047 filterTimer(io), systemBus(systemBus)
Cheng C Yange83604b2020-01-09 09:41:47 +080048{
Jayanth Othayoth5ed2eb42024-12-07 03:27:33 -060049 post(io, [this, &systemBus]() { createPSU(systemBus); });
Patrick Williams7354ce62022-07-22 19:26:56 -050050 std::function<void(sdbusplus::message_t&)> eventHandler =
Jayanth Othayoth5ed2eb42024-12-07 03:27:33 -060051 [this, &systemBus](sdbusplus::message_t& message) {
Patrick Williamsf5402192024-08-16 15:20:53 -040052 if (message.is_method_error())
Cheng C Yange83604b2020-01-09 09:41:47 +080053 {
Patrick Williamsf5402192024-08-16 15:20:53 -040054 std::cerr << "callback method error\n";
Cheng C Yange83604b2020-01-09 09:41:47 +080055 return;
56 }
Patrick Williamsf5402192024-08-16 15:20:53 -040057 filterTimer.expires_after(std::chrono::seconds(1));
Jayanth Othayoth5ed2eb42024-12-07 03:27:33 -060058 filterTimer.async_wait(
59 [this, &systemBus](const boost::system::error_code& ec) {
60 if (ec == boost::asio::error::operation_aborted)
61 {
62 return;
63 }
64 else if (ec)
65 {
66 std::cerr << "timer error\n";
67 }
68 createPSU(systemBus);
69 });
Patrick Williamsf5402192024-08-16 15:20:53 -040070 };
Cheng C Yange83604b2020-01-09 09:41:47 +080071
Patrick Williams7354ce62022-07-22 19:26:56 -050072 std::function<void(sdbusplus::message_t&)> eventCollect =
73 [&](sdbusplus::message_t& message) {
Patrick Williamsf5402192024-08-16 15:20:53 -040074 std::string objectName;
75 boost::container::flat_map<std::string, std::variant<bool>> values;
76 std::string path = message.get_path();
77 std::size_t slantingPos = path.find_last_of("/\\");
78 if ((slantingPos == std::string::npos) ||
79 ((slantingPos + 1) >= path.size()))
Cheng C Yange83604b2020-01-09 09:41:47 +080080 {
Patrick Williamsf5402192024-08-16 15:20:53 -040081 std::cerr << "Unable to get PSU state name from path\n";
82 return;
83 }
84 std::string statePSUName = path.substr(slantingPos + 1);
85
86 std::size_t hypenPos = statePSUName.find("_");
87 if (hypenPos == std::string::npos)
88 {
89 std::cerr << "Unable to get PSU name from PSU path\n";
90 return;
91 }
92 std::string psuName = statePSUName.substr(0, hypenPos);
93
94 try
95 {
96 message.read(objectName, values);
97 }
98 catch (const sdbusplus::exception_t& e)
99 {
100 std::cerr << "Failed to read message from PSU Event\n";
101 return;
Cheng C Yange83604b2020-01-09 09:41:47 +0800102 }
103
Patrick Williamsf5402192024-08-16 15:20:53 -0400104 for (auto& psu : powerSupplies)
Cheng C Yange83604b2020-01-09 09:41:47 +0800105 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400106 if (psu->name != psuName)
Cheng C Yange83604b2020-01-09 09:41:47 +0800107 {
108 continue;
109 }
Patrick Williamsf5402192024-08-16 15:20:53 -0400110
111 std::string psuEventName = "functional";
112 auto findEvent = values.find(psuEventName);
113 if (findEvent != values.end())
Cheng C Yange83604b2020-01-09 09:41:47 +0800114 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400115 bool* functional = std::get_if<bool>(&(findEvent->second));
116 if (functional == nullptr)
117 {
118 std::cerr << "Unable to get valid functional status\n";
119 continue;
120 }
121 if (*functional)
122 {
123 psu->state = CR::PSUState::normal;
124 }
125 else
126 {
127 psu->state = CR::PSUState::acLost;
128 }
Cheng C Yange83604b2020-01-09 09:41:47 +0800129 }
130 }
Patrick Williamsf5402192024-08-16 15:20:53 -0400131 };
Cheng C Yange83604b2020-01-09 09:41:47 +0800132
133 using namespace sdbusplus::bus::match::rules;
134 for (const char* type : psuInterfaceTypes)
135 {
Patrick Williams7354ce62022-07-22 19:26:56 -0500136 auto match = std::make_unique<sdbusplus::bus::match_t>(
137 static_cast<sdbusplus::bus_t&>(*systemBus),
Cheng C Yange83604b2020-01-09 09:41:47 +0800138 type::signal() + member("PropertiesChanged") +
139 path_namespace(inventoryPath) + arg0namespace(type),
140 eventHandler);
141 matches.emplace_back(std::move(match));
142 }
143
144 for (const char* eventType : psuEventInterface)
145 {
Patrick Williams7354ce62022-07-22 19:26:56 -0500146 auto eventMatch = std::make_unique<sdbusplus::bus::match_t>(
147 static_cast<sdbusplus::bus_t&>(*systemBus),
Cheng C Yange83604b2020-01-09 09:41:47 +0800148 type::signal() + member("PropertiesChanged") +
149 path_namespace(eventPath) + arg0namespace(eventType),
150 eventCollect);
151 matches.emplace_back(std::move(eventMatch));
152 }
153}
154
155static const constexpr int psuDepth = 3;
156// Check PSU information from entity-manager D-Bus interface and use the bus
157// address to create PSU Class for cold redundancy.
158void ColdRedundancy::createPSU(
159 std::shared_ptr<sdbusplus::asio::connection>& conn)
160{
161 numberOfPSU = 0;
162 powerSupplies.clear();
163
164 // call mapper to get matched obj paths
165 conn->async_method_call(
166 [this, &conn](const boost::system::error_code ec,
167 CR::GetSubTreeType subtree) {
Patrick Williamsf5402192024-08-16 15:20:53 -0400168 if (ec)
Cheng C Yange83604b2020-01-09 09:41:47 +0800169 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400170 std::cerr << "Exception happened when communicating to "
171 "ObjectMapper\n";
172 return;
173 }
174 for (const auto& object : subtree)
175 {
176 std::string pathName = object.first;
177 for (const auto& serviceIface : object.second)
Cheng C Yange83604b2020-01-09 09:41:47 +0800178 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400179 std::string serviceName = serviceIface.first;
180 for (const auto& interface : serviceIface.second)
Cheng C Yange83604b2020-01-09 09:41:47 +0800181 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400182 // only get property of matched interface
183 bool isIfaceMatched = false;
184 for (const auto& type : psuInterfaceTypes)
Cheng C Yange83604b2020-01-09 09:41:47 +0800185 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400186 if (type == interface)
Cheng C Yange83604b2020-01-09 09:41:47 +0800187 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400188 isIfaceMatched = true;
189 break;
Cheng C Yange83604b2020-01-09 09:41:47 +0800190 }
191 }
Patrick Williamsf5402192024-08-16 15:20:53 -0400192 if (!isIfaceMatched)
193 continue;
Cheng C Yange83604b2020-01-09 09:41:47 +0800194
Patrick Williamsf5402192024-08-16 15:20:53 -0400195 conn->async_method_call(
196 [this, &conn,
197 interface](const boost::system::error_code ec,
198 CR::PropertyMapType propMap) {
199 if (ec)
200 {
201 std::cerr
202 << "Exception happened when get all "
203 "properties\n";
204 return;
205 }
Cheng C Yange83604b2020-01-09 09:41:47 +0800206
Patrick Williamsf5402192024-08-16 15:20:53 -0400207 auto configName =
208 std::get_if<std::string>(&propMap["Name"]);
209 if (configName == nullptr)
210 {
211 std::cerr << "error finding necessary "
212 "entry in configuration\n";
213 return;
214 }
Cheng C Yange83604b2020-01-09 09:41:47 +0800215
Patrick Williamsf5402192024-08-16 15:20:53 -0400216 auto configBus =
217 std::get_if<uint64_t>(&propMap["Bus"]);
218 auto configAddress =
219 std::get_if<uint64_t>(&propMap["Address"]);
220
221 if (configBus == nullptr ||
222 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))
234 {
235 return;
236 }
237 }
238
239 uint8_t order = 0;
240
241 powerSupplies.emplace_back(
242 std::make_unique<PowerSupply>(
243 *configName,
244 static_cast<uint8_t>(*configBus),
245 static_cast<uint8_t>(*configAddress),
246 order, conn));
247
248 numberOfPSU++;
249 std::vector<uint8_t> orders = {};
250 for (auto& psu : powerSupplies)
251 {
252 orders.push_back(psu->order);
253 }
254 },
255 serviceName.c_str(), pathName.c_str(),
256 "org.freedesktop.DBus.Properties", "GetAll",
257 interface);
258 }
Cheng C Yange83604b2020-01-09 09:41:47 +0800259 }
260 }
Patrick Williamsf5402192024-08-16 15:20:53 -0400261 },
Cheng C Yange83604b2020-01-09 09:41:47 +0800262 "xyz.openbmc_project.ObjectMapper",
263 "/xyz/openbmc_project/object_mapper",
264 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
265 "/xyz/openbmc_project/inventory/system", psuDepth, psuInterfaceTypes);
266}
267
268PowerSupply::PowerSupply(
269 std::string& name, uint8_t bus, uint8_t address, uint8_t order,
270 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection) :
Patrick Williamsf5402192024-08-16 15:20:53 -0400271 name(name), bus(bus), address(address), order(order)
Cheng C Yange83604b2020-01-09 09:41:47 +0800272{
273 CR::getPSUEvent(dbusConnection, name, state);
274}