| Shawn McCarney | b0f94e0 | 2025-12-12 14:02:10 -0600 | [diff] [blame] | 1 | /** |
| 2 | * Copyright © 2025 IBM 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 "chassis_status_monitor.hpp" |
| 18 | |
| 19 | #include "types.hpp" |
| 20 | |
| 21 | #include <format> |
| 22 | |
| 23 | namespace phosphor::power::util |
| 24 | { |
| 25 | |
| 26 | constexpr auto INVENTORY_MGR_SERVICE = "xyz.openbmc_project.Inventory.Manager"; |
| 27 | constexpr auto POWER_SEQUENCER_SERVICE = "org.openbmc.control.Power"; |
| 28 | constexpr auto CHASSIS_INPUT_POWER_SERVICE = |
| 29 | "xyz.openbmc_project.Power.Chassis"; |
| 30 | constexpr auto POWER_SUPPLY_SERVICE = "xyz.openbmc_project.Power.PSUMonitor"; |
| 31 | |
| 32 | constexpr auto CHASSIS_POWER_PATH = "/org/openbmc/control/power{}"; |
| 33 | constexpr auto CHASSIS_INPUT_POWER_STATUS_PATH = |
| 34 | "/xyz/openbmc_project/power/chassis/chassis{}"; |
| 35 | constexpr auto POWER_SUPPLIES_STATUS_PATH = |
| 36 | "/xyz/openbmc_project/power/power_supplies/chassis{}/psus"; |
| 37 | |
| 38 | BMCChassisStatusMonitor::BMCChassisStatusMonitor( |
| 39 | sdbusplus::bus_t& bus, size_t number, const std::string& inventoryPath, |
| 40 | const ChassisStatusMonitorOptions& options) : |
| 41 | bus{bus}, number{number}, inventoryPath{inventoryPath}, options{options} |
| 42 | { |
| 43 | chassisPowerPath = std::format(CHASSIS_POWER_PATH, number); |
| 44 | chassisInputPowerStatusPath = |
| 45 | std::format(CHASSIS_INPUT_POWER_STATUS_PATH, number); |
| 46 | powerSuppliesStatusPath = std::format(POWER_SUPPLIES_STATUS_PATH, number); |
| 47 | addMatches(); |
| 48 | getAllProperties(); |
| 49 | } |
| 50 | |
| 51 | void BMCChassisStatusMonitor::addMatches() |
| 52 | { |
| 53 | if (options.isPresentMonitored || options.isAvailableMonitored || |
| 54 | options.isEnabledMonitored) |
| 55 | { |
| 56 | addNameOwnerChangedMatch(INVENTORY_MGR_SERVICE); |
| 57 | addInterfacesAddedMatch(inventoryPath); |
| 58 | if (options.isPresentMonitored) |
| 59 | { |
| 60 | addPropertiesChangedMatch(inventoryPath, INVENTORY_IFACE); |
| 61 | } |
| 62 | if (options.isAvailableMonitored) |
| 63 | { |
| 64 | addPropertiesChangedMatch(inventoryPath, AVAILABILITY_IFACE); |
| 65 | } |
| 66 | if (options.isEnabledMonitored) |
| 67 | { |
| 68 | addPropertiesChangedMatch(inventoryPath, ENABLE_IFACE); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | if (options.isPowerStateMonitored || options.isPowerGoodMonitored) |
| 73 | { |
| 74 | addNameOwnerChangedMatch(POWER_SEQUENCER_SERVICE); |
| 75 | addInterfacesAddedMatch(chassisPowerPath); |
| 76 | addPropertiesChangedMatch(chassisPowerPath, POWER_IFACE); |
| 77 | } |
| 78 | |
| 79 | if (options.isInputPowerStatusMonitored) |
| 80 | { |
| 81 | addNameOwnerChangedMatch(CHASSIS_INPUT_POWER_SERVICE); |
| 82 | addInterfacesAddedMatch(chassisInputPowerStatusPath); |
| 83 | addPropertiesChangedMatch(chassisInputPowerStatusPath, |
| 84 | POWER_SYSTEM_INPUTS_IFACE); |
| 85 | } |
| 86 | |
| 87 | if (options.isPowerSuppliesStatusMonitored) |
| 88 | { |
| 89 | addNameOwnerChangedMatch(POWER_SUPPLY_SERVICE); |
| 90 | addInterfacesAddedMatch(powerSuppliesStatusPath); |
| 91 | addPropertiesChangedMatch(powerSuppliesStatusPath, |
| 92 | POWER_SYSTEM_INPUTS_IFACE); |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | template <typename T> |
| 97 | void BMCChassisStatusMonitor::getProperty( |
| 98 | const std::string& service, const std::string& path, |
| 99 | const std::string& interface, const std::string& propertyName, |
| 100 | std::optional<T>& optionalValue) |
| 101 | { |
| 102 | try |
| 103 | { |
| 104 | T value; |
| 105 | util::getProperty(interface, propertyName, path, service, bus, value); |
| 106 | optionalValue = value; |
| 107 | } |
| 108 | catch (...) |
| 109 | {} |
| 110 | } |
| 111 | |
| 112 | void BMCChassisStatusMonitor::getInventoryManagerProperties() |
| 113 | { |
| 114 | if (options.isPresentMonitored) |
| 115 | { |
| 116 | getProperty(INVENTORY_MGR_SERVICE, inventoryPath, INVENTORY_IFACE, |
| 117 | PRESENT_PROP, isPresentValue); |
| 118 | } |
| 119 | |
| 120 | if (options.isAvailableMonitored) |
| 121 | { |
| 122 | getProperty(INVENTORY_MGR_SERVICE, inventoryPath, AVAILABILITY_IFACE, |
| 123 | AVAILABLE_PROP, isAvailableValue); |
| 124 | } |
| 125 | |
| 126 | if (options.isEnabledMonitored) |
| 127 | { |
| 128 | getProperty(INVENTORY_MGR_SERVICE, inventoryPath, ENABLE_IFACE, |
| 129 | ENABLED_PROP, isEnabledValue); |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | void BMCChassisStatusMonitor::getPowerSequencerProperties() |
| 134 | { |
| 135 | if (options.isPowerStateMonitored) |
| 136 | { |
| 137 | getProperty(POWER_SEQUENCER_SERVICE, chassisPowerPath, POWER_IFACE, |
| 138 | POWER_STATE_PROP, powerStateValue); |
| 139 | } |
| 140 | |
| 141 | if (options.isPowerGoodMonitored) |
| 142 | { |
| 143 | getProperty(POWER_SEQUENCER_SERVICE, chassisPowerPath, POWER_IFACE, |
| 144 | POWER_GOOD_PROP, powerGoodValue); |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | void BMCChassisStatusMonitor::getChassisInputPowerProperties() |
| 149 | { |
| 150 | if (options.isInputPowerStatusMonitored) |
| 151 | { |
| 152 | getProperty(CHASSIS_INPUT_POWER_SERVICE, chassisInputPowerStatusPath, |
| 153 | POWER_SYSTEM_INPUTS_IFACE, STATUS_PROP, |
| 154 | inputPowerStatusValue); |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | void BMCChassisStatusMonitor::getPowerSupplyProperties() |
| 159 | { |
| 160 | if (options.isPowerSuppliesStatusMonitored) |
| 161 | { |
| 162 | getProperty(POWER_SUPPLY_SERVICE, powerSuppliesStatusPath, |
| 163 | POWER_SYSTEM_INPUTS_IFACE, STATUS_PROP, |
| 164 | powerSuppliesStatusValue); |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | template <typename T> |
| 169 | void BMCChassisStatusMonitor::storeProperty(const DbusPropertyMap& properties, |
| 170 | const std::string& propertyName, |
| 171 | std::optional<T>& optionalValue) |
| 172 | { |
| 173 | try |
| 174 | { |
| 175 | auto it = properties.find(propertyName); |
| 176 | if (it != properties.end()) |
| 177 | { |
| 178 | optionalValue = std::get<T>(it->second); |
| 179 | } |
| 180 | } |
| 181 | catch (...) |
| 182 | {} |
| 183 | } |
| 184 | |
| 185 | void BMCChassisStatusMonitor::storeProperties(const DbusPropertyMap& properties, |
| 186 | const std::string& path, |
| 187 | const std::string& interface) |
| 188 | { |
| 189 | try |
| 190 | { |
| 191 | if (interface == INVENTORY_IFACE) |
| 192 | { |
| 193 | storeProperty(properties, PRESENT_PROP, isPresentValue); |
| 194 | } |
| 195 | else if (interface == AVAILABILITY_IFACE) |
| 196 | { |
| 197 | storeProperty(properties, AVAILABLE_PROP, isAvailableValue); |
| 198 | } |
| 199 | else if (interface == ENABLE_IFACE) |
| 200 | { |
| 201 | storeProperty(properties, ENABLED_PROP, isEnabledValue); |
| 202 | } |
| 203 | else if (interface == POWER_IFACE) |
| 204 | { |
| 205 | storeProperty(properties, POWER_STATE_PROP, powerStateValue); |
| 206 | storeProperty(properties, POWER_GOOD_PROP, powerGoodValue); |
| 207 | } |
| 208 | else if (interface == POWER_SYSTEM_INPUTS_IFACE) |
| 209 | { |
| 210 | if (path == chassisInputPowerStatusPath) |
| 211 | { |
| 212 | storeProperty(properties, STATUS_PROP, inputPowerStatusValue); |
| 213 | } |
| 214 | else if (path == powerSuppliesStatusPath) |
| 215 | { |
| 216 | storeProperty(properties, STATUS_PROP, |
| 217 | powerSuppliesStatusValue); |
| 218 | } |
| 219 | } |
| 220 | } |
| 221 | catch (...) |
| 222 | {} |
| 223 | } |
| 224 | |
| 225 | void BMCChassisStatusMonitor::nameOwnerChangedCallback( |
| 226 | sdbusplus::message_t& message) |
| 227 | { |
| 228 | try |
| 229 | { |
| 230 | std::string name, oldOwner, newOwner; |
| 231 | message.read(name, oldOwner, newOwner); |
| 232 | if (!newOwner.empty()) |
| 233 | { |
| 234 | if (name == INVENTORY_MGR_SERVICE) |
| 235 | { |
| 236 | getInventoryManagerProperties(); |
| 237 | } |
| 238 | else if (name == POWER_SEQUENCER_SERVICE) |
| 239 | { |
| 240 | getPowerSequencerProperties(); |
| 241 | } |
| 242 | else if (name == CHASSIS_INPUT_POWER_SERVICE) |
| 243 | { |
| 244 | getChassisInputPowerProperties(); |
| 245 | } |
| 246 | else if (name == POWER_SUPPLY_SERVICE) |
| 247 | { |
| 248 | getPowerSupplyProperties(); |
| 249 | } |
| 250 | } |
| 251 | } |
| 252 | catch (...) |
| 253 | {} |
| 254 | } |
| 255 | |
| 256 | void BMCChassisStatusMonitor::interfacesAddedCallback( |
| 257 | sdbusplus::message_t& message) |
| 258 | { |
| 259 | try |
| 260 | { |
| 261 | sdbusplus::message::object_path path; |
| 262 | std::map<std::string, DbusPropertyMap> interfaces; |
| 263 | message.read(path, interfaces); |
| 264 | for (const auto& [interface, properties] : interfaces) |
| 265 | { |
| 266 | storeProperties(properties, path, interface); |
| 267 | } |
| 268 | } |
| 269 | catch (...) |
| 270 | {} |
| 271 | } |
| 272 | |
| 273 | void BMCChassisStatusMonitor::propertiesChangedCallback( |
| 274 | sdbusplus::message_t& message) |
| 275 | { |
| 276 | try |
| 277 | { |
| 278 | std::string interface; |
| 279 | DbusPropertyMap changedProperties; |
| 280 | std::vector<std::string> invalidatedProperties; |
| 281 | message.read(interface, changedProperties, invalidatedProperties); |
| 282 | storeProperties(changedProperties, message.get_path(), interface); |
| 283 | } |
| 284 | catch (...) |
| 285 | {} |
| 286 | } |
| 287 | |
| 288 | } // namespace phosphor::power::util |