blob: c1ebc44ec17c6ff5bc8c66c1885184df819e16d4 [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) :
Patrick Williamsf5402192024-08-16 15:20:53 -040047 filterTimer(io), systemBus(systemBus)
Cheng C Yange83604b2020-01-09 09:41:47 +080048{
49 post(io,
50 [this, &io, &objectServer, &systemBus]() { createPSU(systemBus); });
Patrick Williams7354ce62022-07-22 19:26:56 -050051 std::function<void(sdbusplus::message_t&)> eventHandler =
52 [this, &io, &objectServer, &systemBus](sdbusplus::message_t& message) {
Patrick Williamsf5402192024-08-16 15:20:53 -040053 if (message.is_method_error())
Cheng C Yange83604b2020-01-09 09:41:47 +080054 {
Patrick Williamsf5402192024-08-16 15:20:53 -040055 std::cerr << "callback method error\n";
Cheng C Yange83604b2020-01-09 09:41:47 +080056 return;
57 }
Patrick Williamsf5402192024-08-16 15:20:53 -040058 filterTimer.expires_after(std::chrono::seconds(1));
59 filterTimer.async_wait([this, &io, &objectServer, &systemBus](
60 const boost::system::error_code& ec) {
61 if (ec == boost::asio::error::operation_aborted)
62 {
63 return;
64 }
65 else if (ec)
66 {
67 std::cerr << "timer error\n";
68 }
69 createPSU(systemBus);
70 });
71 };
Cheng C Yange83604b2020-01-09 09:41:47 +080072
Patrick Williams7354ce62022-07-22 19:26:56 -050073 std::function<void(sdbusplus::message_t&)> eventCollect =
74 [&](sdbusplus::message_t& message) {
Patrick Williamsf5402192024-08-16 15:20:53 -040075 std::string objectName;
76 boost::container::flat_map<std::string, std::variant<bool>> values;
77 std::string path = message.get_path();
78 std::size_t slantingPos = path.find_last_of("/\\");
79 if ((slantingPos == std::string::npos) ||
80 ((slantingPos + 1) >= path.size()))
Cheng C Yange83604b2020-01-09 09:41:47 +080081 {
Patrick Williamsf5402192024-08-16 15:20:53 -040082 std::cerr << "Unable to get PSU state name from path\n";
83 return;
84 }
85 std::string statePSUName = path.substr(slantingPos + 1);
86
87 std::size_t hypenPos = statePSUName.find("_");
88 if (hypenPos == std::string::npos)
89 {
90 std::cerr << "Unable to get PSU name from PSU path\n";
91 return;
92 }
93 std::string psuName = statePSUName.substr(0, hypenPos);
94
95 try
96 {
97 message.read(objectName, values);
98 }
99 catch (const sdbusplus::exception_t& e)
100 {
101 std::cerr << "Failed to read message from PSU Event\n";
102 return;
Cheng C Yange83604b2020-01-09 09:41:47 +0800103 }
104
Patrick Williamsf5402192024-08-16 15:20:53 -0400105 for (auto& psu : powerSupplies)
Cheng C Yange83604b2020-01-09 09:41:47 +0800106 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400107 if (psu->name != psuName)
Cheng C Yange83604b2020-01-09 09:41:47 +0800108 {
109 continue;
110 }
Patrick Williamsf5402192024-08-16 15:20:53 -0400111
112 std::string psuEventName = "functional";
113 auto findEvent = values.find(psuEventName);
114 if (findEvent != values.end())
Cheng C Yange83604b2020-01-09 09:41:47 +0800115 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400116 bool* functional = std::get_if<bool>(&(findEvent->second));
117 if (functional == nullptr)
118 {
119 std::cerr << "Unable to get valid functional status\n";
120 continue;
121 }
122 if (*functional)
123 {
124 psu->state = CR::PSUState::normal;
125 }
126 else
127 {
128 psu->state = CR::PSUState::acLost;
129 }
Cheng C Yange83604b2020-01-09 09:41:47 +0800130 }
131 }
Patrick Williamsf5402192024-08-16 15:20:53 -0400132 };
Cheng C Yange83604b2020-01-09 09:41:47 +0800133
134 using namespace sdbusplus::bus::match::rules;
135 for (const char* type : psuInterfaceTypes)
136 {
Patrick Williams7354ce62022-07-22 19:26:56 -0500137 auto match = std::make_unique<sdbusplus::bus::match_t>(
138 static_cast<sdbusplus::bus_t&>(*systemBus),
Cheng C Yange83604b2020-01-09 09:41:47 +0800139 type::signal() + member("PropertiesChanged") +
140 path_namespace(inventoryPath) + arg0namespace(type),
141 eventHandler);
142 matches.emplace_back(std::move(match));
143 }
144
145 for (const char* eventType : psuEventInterface)
146 {
Patrick Williams7354ce62022-07-22 19:26:56 -0500147 auto eventMatch = std::make_unique<sdbusplus::bus::match_t>(
148 static_cast<sdbusplus::bus_t&>(*systemBus),
Cheng C Yange83604b2020-01-09 09:41:47 +0800149 type::signal() + member("PropertiesChanged") +
150 path_namespace(eventPath) + arg0namespace(eventType),
151 eventCollect);
152 matches.emplace_back(std::move(eventMatch));
153 }
154}
155
156static const constexpr int psuDepth = 3;
157// Check PSU information from entity-manager D-Bus interface and use the bus
158// address to create PSU Class for cold redundancy.
159void ColdRedundancy::createPSU(
160 std::shared_ptr<sdbusplus::asio::connection>& conn)
161{
162 numberOfPSU = 0;
163 powerSupplies.clear();
164
165 // call mapper to get matched obj paths
166 conn->async_method_call(
167 [this, &conn](const boost::system::error_code ec,
168 CR::GetSubTreeType subtree) {
Patrick Williamsf5402192024-08-16 15:20:53 -0400169 if (ec)
Cheng C Yange83604b2020-01-09 09:41:47 +0800170 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400171 std::cerr << "Exception happened when communicating to "
172 "ObjectMapper\n";
173 return;
174 }
175 for (const auto& object : subtree)
176 {
177 std::string pathName = object.first;
178 for (const auto& serviceIface : object.second)
Cheng C Yange83604b2020-01-09 09:41:47 +0800179 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400180 std::string serviceName = serviceIface.first;
181 for (const auto& interface : serviceIface.second)
Cheng C Yange83604b2020-01-09 09:41:47 +0800182 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400183 // only get property of matched interface
184 bool isIfaceMatched = false;
185 for (const auto& type : psuInterfaceTypes)
Cheng C Yange83604b2020-01-09 09:41:47 +0800186 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400187 if (type == interface)
Cheng C Yange83604b2020-01-09 09:41:47 +0800188 {
Patrick Williamsf5402192024-08-16 15:20:53 -0400189 isIfaceMatched = true;
190 break;
Cheng C Yange83604b2020-01-09 09:41:47 +0800191 }
192 }
Patrick Williamsf5402192024-08-16 15:20:53 -0400193 if (!isIfaceMatched)
194 continue;
Cheng C Yange83604b2020-01-09 09:41:47 +0800195
Patrick Williamsf5402192024-08-16 15:20:53 -0400196 conn->async_method_call(
197 [this, &conn,
198 interface](const boost::system::error_code ec,
199 CR::PropertyMapType propMap) {
200 if (ec)
201 {
202 std::cerr
203 << "Exception happened when get all "
204 "properties\n";
205 return;
206 }
Cheng C Yange83604b2020-01-09 09:41:47 +0800207
Patrick Williamsf5402192024-08-16 15:20:53 -0400208 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 }
Cheng C Yange83604b2020-01-09 09:41:47 +0800216
Patrick Williamsf5402192024-08-16 15:20:53 -0400217 auto configBus =
218 std::get_if<uint64_t>(&propMap["Bus"]);
219 auto configAddress =
220 std::get_if<uint64_t>(&propMap["Address"]);
221
222 if (configBus == nullptr ||
223 configAddress == nullptr)
224 {
225 std::cerr << "error finding necessary "
226 "entry in configuration\n";
227 return;
228 }
229 for (auto& psu : powerSupplies)
230 {
231 if ((static_cast<uint8_t>(*configBus) ==
232 psu->bus) &&
233 (static_cast<uint8_t>(*configAddress) ==
234 psu->address))
235 {
236 return;
237 }
238 }
239
240 uint8_t order = 0;
241
242 powerSupplies.emplace_back(
243 std::make_unique<PowerSupply>(
244 *configName,
245 static_cast<uint8_t>(*configBus),
246 static_cast<uint8_t>(*configAddress),
247 order, conn));
248
249 numberOfPSU++;
250 std::vector<uint8_t> orders = {};
251 for (auto& psu : powerSupplies)
252 {
253 orders.push_back(psu->order);
254 }
255 },
256 serviceName.c_str(), pathName.c_str(),
257 "org.freedesktop.DBus.Properties", "GetAll",
258 interface);
259 }
Cheng C Yange83604b2020-01-09 09:41:47 +0800260 }
261 }
Patrick Williamsf5402192024-08-16 15:20:53 -0400262 },
Cheng C Yange83604b2020-01-09 09:41:47 +0800263 "xyz.openbmc_project.ObjectMapper",
264 "/xyz/openbmc_project/object_mapper",
265 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
266 "/xyz/openbmc_project/inventory/system", psuDepth, psuInterfaceTypes);
267}
268
269PowerSupply::PowerSupply(
270 std::string& name, uint8_t bus, uint8_t address, uint8_t order,
271 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection) :
Patrick Williamsf5402192024-08-16 15:20:53 -0400272 name(name), bus(bus), address(address), order(order)
Cheng C Yange83604b2020-01-09 09:41:47 +0800273{
274 CR::getPSUEvent(dbusConnection, name, state);
275}