| NodeMan97 | 27d1e14 | 2022-07-27 15:10:07 -0500 | [diff] [blame] | 1 | #include "config.h" | 
|  | 2 |  | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 3 | #include "utils.hpp" | 
|  | 4 |  | 
| NodeMan97 | 27d1e14 | 2022-07-27 15:10:07 -0500 | [diff] [blame] | 5 | #include <fmt/format.h> | 
|  | 6 | #include <fmt/printf.h> | 
| Andrew Geissler | f8ae6a0 | 2022-01-21 17:00:20 -0600 | [diff] [blame] | 7 | #include <gpiod.h> | 
|  | 8 |  | 
| Andrew Geissler | 8ffdb26 | 2021-09-20 15:25:19 -0500 | [diff] [blame] | 9 | #include <phosphor-logging/lg2.hpp> | 
| Patrick Williams | 9a286db | 2024-01-17 06:29:47 -0600 | [diff] [blame] | 10 | #include <xyz/openbmc_project/Dump/Create/client.hpp> | 
|  | 11 | #include <xyz/openbmc_project/Logging/Create/client.hpp> | 
|  | 12 | #include <xyz/openbmc_project/ObjectMapper/client.hpp> | 
|  | 13 | #include <xyz/openbmc_project/State/BMC/client.hpp> | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 14 |  | 
| Andrew Geissler | 48a4e5e | 2023-02-15 18:23:34 -0600 | [diff] [blame] | 15 | #include <chrono> | 
| NodeMan97 | 27d1e14 | 2022-07-27 15:10:07 -0500 | [diff] [blame] | 16 | #include <filesystem> | 
|  | 17 |  | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 18 | namespace phosphor | 
|  | 19 | { | 
|  | 20 | namespace state | 
|  | 21 | { | 
|  | 22 | namespace manager | 
|  | 23 | { | 
|  | 24 | namespace utils | 
|  | 25 | { | 
|  | 26 |  | 
| Andrew Geissler | 48a4e5e | 2023-02-15 18:23:34 -0600 | [diff] [blame] | 27 | using namespace std::literals::chrono_literals; | 
|  | 28 |  | 
| Andrew Geissler | 8ffdb26 | 2021-09-20 15:25:19 -0500 | [diff] [blame] | 29 | PHOSPHOR_LOG2_USING; | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 30 |  | 
| Andrew Geissler | 928bbf1 | 2023-02-14 13:30:14 -0600 | [diff] [blame] | 31 | constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; | 
|  | 32 | constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1"; | 
|  | 33 | constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 34 | constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"; | 
|  | 35 |  | 
| Patrick Williams | 9a286db | 2024-01-17 06:29:47 -0600 | [diff] [blame] | 36 | using ObjectMapper = sdbusplus::client::xyz::openbmc_project::ObjectMapper<>; | 
|  | 37 |  | 
| Patrick Williams | 5c4a082 | 2023-02-28 02:40:35 -0600 | [diff] [blame] | 38 | void subscribeToSystemdSignals(sdbusplus::bus_t& bus) | 
| Andrew Geissler | 928bbf1 | 2023-02-14 13:30:14 -0600 | [diff] [blame] | 39 | { | 
|  | 40 | auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, | 
|  | 41 | SYSTEMD_INTERFACE, "Subscribe"); | 
|  | 42 |  | 
|  | 43 | try | 
|  | 44 | { | 
| Andrew Geissler | 48a4e5e | 2023-02-15 18:23:34 -0600 | [diff] [blame] | 45 | // On OpenBMC based systems, systemd has had a few situations where it | 
|  | 46 | // has been unable to respond to this call within the default d-bus | 
|  | 47 | // timeout of 25 seconds. This is due to the large amount of work being | 
|  | 48 | // done by systemd during OpenBMC startup. Set the timeout for this call | 
|  | 49 | // to 60 seconds (worst case seen was around 30s so double it). | 
|  | 50 | bus.call(method, 60s); | 
| Andrew Geissler | 928bbf1 | 2023-02-14 13:30:14 -0600 | [diff] [blame] | 51 | } | 
|  | 52 | catch (const sdbusplus::exception_t& e) | 
|  | 53 | { | 
|  | 54 | error("Failed to subscribe to systemd signals: {ERROR}", "ERROR", e); | 
|  | 55 | throw std::runtime_error("Unable to subscribe to systemd signals"); | 
|  | 56 | } | 
|  | 57 | return; | 
|  | 58 | } | 
|  | 59 |  | 
| Patrick Williams | 5c4a082 | 2023-02-28 02:40:35 -0600 | [diff] [blame] | 60 | std::string getService(sdbusplus::bus_t& bus, std::string path, | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 61 | std::string interface) | 
|  | 62 | { | 
| Patrick Williams | 9a286db | 2024-01-17 06:29:47 -0600 | [diff] [blame] | 63 | auto mapper = bus.new_method_call(ObjectMapper::default_service, | 
|  | 64 | ObjectMapper::instance_path, | 
|  | 65 | ObjectMapper::interface, "GetObject"); | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 66 |  | 
|  | 67 | mapper.append(path, std::vector<std::string>({interface})); | 
|  | 68 |  | 
|  | 69 | std::vector<std::pair<std::string, std::vector<std::string>>> | 
|  | 70 | mapperResponse; | 
|  | 71 |  | 
|  | 72 | try | 
|  | 73 | { | 
|  | 74 | auto mapperResponseMsg = bus.call(mapper); | 
|  | 75 |  | 
|  | 76 | mapperResponseMsg.read(mapperResponse); | 
|  | 77 | if (mapperResponse.empty()) | 
|  | 78 | { | 
| Andrew Geissler | ad65b2d | 2021-09-21 12:53:29 -0500 | [diff] [blame] | 79 | error( | 
|  | 80 | "Error no matching service with path {PATH} and interface {INTERFACE}", | 
|  | 81 | "PATH", path, "INTERFACE", interface); | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 82 | throw std::runtime_error("Error no matching service"); | 
|  | 83 | } | 
|  | 84 | } | 
| Patrick Williams | f053e6f | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 85 | catch (const sdbusplus::exception_t& e) | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 86 | { | 
| Andrew Geissler | 8ffdb26 | 2021-09-20 15:25:19 -0500 | [diff] [blame] | 87 | error("Error in mapper call with path {PATH}, interface " | 
|  | 88 | "{INTERFACE}, and exception {ERROR}", | 
|  | 89 | "PATH", path, "INTERFACE", interface, "ERROR", e); | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 90 | throw; | 
|  | 91 | } | 
|  | 92 |  | 
|  | 93 | return mapperResponse.begin()->first; | 
|  | 94 | } | 
|  | 95 |  | 
| Patrick Williams | f053e6f | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 96 | std::string getProperty(sdbusplus::bus_t& bus, const std::string& path, | 
| Andrew Geissler | 49e6713 | 2022-01-26 14:27:52 -0600 | [diff] [blame] | 97 | const std::string& interface, | 
|  | 98 | const std::string& propertyName) | 
|  | 99 | { | 
|  | 100 | std::variant<std::string> property; | 
|  | 101 | std::string service = getService(bus, path, interface); | 
|  | 102 |  | 
|  | 103 | auto method = bus.new_method_call(service.c_str(), path.c_str(), | 
|  | 104 | PROPERTY_INTERFACE, "Get"); | 
|  | 105 |  | 
|  | 106 | method.append(interface, propertyName); | 
|  | 107 |  | 
|  | 108 | try | 
|  | 109 | { | 
|  | 110 | auto reply = bus.call(method); | 
|  | 111 | reply.read(property); | 
|  | 112 | } | 
| Patrick Williams | f053e6f | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 113 | catch (const sdbusplus::exception_t& e) | 
| Andrew Geissler | 49e6713 | 2022-01-26 14:27:52 -0600 | [diff] [blame] | 114 | { | 
|  | 115 | error("Error in property Get, error {ERROR}, property {PROPERTY}", | 
|  | 116 | "ERROR", e, "PROPERTY", propertyName); | 
|  | 117 | throw; | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | if (std::get<std::string>(property).empty()) | 
|  | 121 | { | 
|  | 122 | error("Error reading property response for {PROPERTY}", "PROPERTY", | 
|  | 123 | propertyName); | 
|  | 124 | throw std::runtime_error("Error reading property response"); | 
|  | 125 | } | 
|  | 126 |  | 
|  | 127 | return std::get<std::string>(property); | 
|  | 128 | } | 
|  | 129 |  | 
| Patrick Williams | f053e6f | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 130 | void setProperty(sdbusplus::bus_t& bus, const std::string& path, | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 131 | const std::string& interface, const std::string& property, | 
|  | 132 | const std::string& value) | 
|  | 133 | { | 
| Patrick Williams | 2975e26 | 2020-05-13 18:01:09 -0500 | [diff] [blame] | 134 | std::variant<std::string> variantValue = value; | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 135 | std::string service = getService(bus, path, interface); | 
|  | 136 |  | 
|  | 137 | auto method = bus.new_method_call(service.c_str(), path.c_str(), | 
|  | 138 | PROPERTY_INTERFACE, "Set"); | 
|  | 139 |  | 
|  | 140 | method.append(interface, property, variantValue); | 
|  | 141 | bus.call_noreply(method); | 
|  | 142 |  | 
|  | 143 | return; | 
|  | 144 | } | 
|  | 145 |  | 
| Andrew Geissler | f8ae6a0 | 2022-01-21 17:00:20 -0600 | [diff] [blame] | 146 | int getGpioValue(const std::string& gpioName) | 
|  | 147 | { | 
| Andrew Geissler | f8ae6a0 | 2022-01-21 17:00:20 -0600 | [diff] [blame] | 148 | int gpioval = -1; | 
|  | 149 | gpiod_line* line = gpiod_line_find(gpioName.c_str()); | 
|  | 150 |  | 
|  | 151 | if (nullptr != line) | 
|  | 152 | { | 
|  | 153 | // take ownership of gpio | 
|  | 154 | if (0 != gpiod_line_request_input(line, "state-manager")) | 
|  | 155 | { | 
|  | 156 | error("Failed request for {GPIO_NAME} GPIO", "GPIO_NAME", gpioName); | 
|  | 157 | } | 
|  | 158 | else | 
|  | 159 | { | 
|  | 160 | // get gpio value | 
|  | 161 | gpioval = gpiod_line_get_value(line); | 
|  | 162 |  | 
|  | 163 | // release ownership of gpio | 
|  | 164 | gpiod_line_close_chip(line); | 
|  | 165 | } | 
|  | 166 | } | 
|  | 167 | return gpioval; | 
|  | 168 | } | 
|  | 169 |  | 
| Andrew Geissler | 9d4d0c9 | 2022-01-26 13:18:12 -0600 | [diff] [blame] | 170 | void createError( | 
| Patrick Williams | f053e6f | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 171 | sdbusplus::bus_t& bus, const std::string& errorMsg, | 
| Patrick Williams | 7e969cb | 2023-08-23 16:24:23 -0500 | [diff] [blame] | 172 | sdbusplus::server::xyz::openbmc_project::logging::Entry::Level errLevel, | 
| Andrew Geissler | d49f51e | 2022-03-07 14:57:07 -0600 | [diff] [blame] | 173 | std::map<std::string, std::string> additionalData) | 
| Andrew Geissler | 9d4d0c9 | 2022-01-26 13:18:12 -0600 | [diff] [blame] | 174 | { | 
| Andrew Geissler | 9d4d0c9 | 2022-01-26 13:18:12 -0600 | [diff] [blame] | 175 | try | 
|  | 176 | { | 
| Andrew Geissler | d49f51e | 2022-03-07 14:57:07 -0600 | [diff] [blame] | 177 | // Always add the _PID on for some extra logging debug | 
| Andrew Geissler | 9d4d0c9 | 2022-01-26 13:18:12 -0600 | [diff] [blame] | 178 | additionalData.emplace("_PID", std::to_string(getpid())); | 
|  | 179 |  | 
| Patrick Williams | 9a286db | 2024-01-17 06:29:47 -0600 | [diff] [blame] | 180 | using LoggingCreate = | 
|  | 181 | sdbusplus::client::xyz::openbmc_project::logging::Create<>; | 
|  | 182 |  | 
|  | 183 | auto method = bus.new_method_call(LoggingCreate::default_service, | 
|  | 184 | LoggingCreate::instance_path, | 
|  | 185 | LoggingCreate::interface, "Create"); | 
| Andrew Geissler | 9d4d0c9 | 2022-01-26 13:18:12 -0600 | [diff] [blame] | 186 |  | 
|  | 187 | method.append(errorMsg, errLevel, additionalData); | 
|  | 188 | auto resp = bus.call(method); | 
|  | 189 | } | 
| Patrick Williams | f053e6f | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 190 | catch (const sdbusplus::exception_t& e) | 
| Andrew Geissler | 9d4d0c9 | 2022-01-26 13:18:12 -0600 | [diff] [blame] | 191 | { | 
|  | 192 | error("sdbusplus D-Bus call exception, error {ERROR} trying to create " | 
|  | 193 | "an error with {ERROR_MSG}", | 
|  | 194 | "ERROR", e, "ERROR_MSG", errorMsg); | 
|  | 195 |  | 
|  | 196 | throw std::runtime_error( | 
|  | 197 | "Error in invoking D-Bus logging create interface"); | 
|  | 198 | } | 
|  | 199 | catch (const std::exception& e) | 
|  | 200 | { | 
|  | 201 | error("D-bus call exception: {ERROR}", "ERROR", e); | 
|  | 202 | throw e; | 
|  | 203 | } | 
|  | 204 | } | 
|  | 205 |  | 
| Patrick Williams | f053e6f | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 206 | void createBmcDump(sdbusplus::bus_t& bus) | 
| Andrew Geissler | 55e96ac | 2022-04-19 11:44:53 -0400 | [diff] [blame] | 207 | { | 
| Patrick Williams | 9a286db | 2024-01-17 06:29:47 -0600 | [diff] [blame] | 208 | using DumpCreate = sdbusplus::client::xyz::openbmc_project::dump::Create<>; | 
|  | 209 | auto dumpPath = | 
|  | 210 | sdbusplus::message::object_path(DumpCreate::namespace_path::value) / | 
|  | 211 | DumpCreate::namespace_path::bmc; | 
|  | 212 |  | 
|  | 213 | auto method = bus.new_method_call(DumpCreate::default_service, | 
|  | 214 | dumpPath.str.c_str(), | 
|  | 215 | DumpCreate::interface, "CreateDump"); | 
| Andrew Geissler | 55e96ac | 2022-04-19 11:44:53 -0400 | [diff] [blame] | 216 | method.append( | 
|  | 217 | std::vector< | 
|  | 218 | std::pair<std::string, std::variant<std::string, uint64_t>>>()); | 
|  | 219 | try | 
|  | 220 | { | 
|  | 221 | bus.call_noreply(method); | 
|  | 222 | } | 
| Patrick Williams | f053e6f | 2022-07-22 19:26:54 -0500 | [diff] [blame] | 223 | catch (const sdbusplus::exception_t& e) | 
| Andrew Geissler | 55e96ac | 2022-04-19 11:44:53 -0400 | [diff] [blame] | 224 | { | 
|  | 225 | error("Failed to create BMC dump, exception:{ERROR}", "ERROR", e); | 
|  | 226 | // just continue, this is error path anyway so we're just collecting | 
|  | 227 | // what we can | 
|  | 228 | } | 
|  | 229 | } | 
|  | 230 |  | 
| NodeMan97 | 27d1e14 | 2022-07-27 15:10:07 -0500 | [diff] [blame] | 231 | bool checkACLoss(size_t& chassisId) | 
|  | 232 | { | 
| Patrick Williams | 9e5cd38 | 2023-05-10 07:50:38 -0500 | [diff] [blame] | 233 | std::string chassisLostPowerFileFmt = fmt::sprintf(CHASSIS_LOST_POWER_FILE, | 
|  | 234 | chassisId); | 
| NodeMan97 | 27d1e14 | 2022-07-27 15:10:07 -0500 | [diff] [blame] | 235 |  | 
|  | 236 | std::filesystem::path chassisPowerLossFile{chassisLostPowerFileFmt}; | 
|  | 237 | if (std::filesystem::exists(chassisPowerLossFile)) | 
|  | 238 | { | 
|  | 239 | return true; | 
|  | 240 | } | 
|  | 241 |  | 
|  | 242 | return false; | 
|  | 243 | } | 
|  | 244 |  | 
| Andrew Geissler | fc1020f | 2023-05-24 17:07:38 -0400 | [diff] [blame] | 245 | bool isBmcReady(sdbusplus::bus_t& bus) | 
|  | 246 | { | 
| Patrick Williams | 9a286db | 2024-01-17 06:29:47 -0600 | [diff] [blame] | 247 | using BMC = sdbusplus::client::xyz::openbmc_project::state::BMC<>; | 
|  | 248 | auto bmcPath = sdbusplus::message::object_path(BMC::namespace_path::value) / | 
|  | 249 | BMC::namespace_path::bmc; | 
|  | 250 |  | 
|  | 251 | auto bmcState = getProperty(bus, bmcPath.str.c_str(), BMC::interface, | 
| Andrew Geissler | fc1020f | 2023-05-24 17:07:38 -0400 | [diff] [blame] | 252 | "CurrentBMCState"); | 
| Patrick Williams | 9a286db | 2024-01-17 06:29:47 -0600 | [diff] [blame] | 253 |  | 
|  | 254 | if (sdbusplus::message::convert_from_string<BMC::BMCState>(bmcState) != | 
|  | 255 | BMC::BMCState::Ready) | 
| Andrew Geissler | fc1020f | 2023-05-24 17:07:38 -0400 | [diff] [blame] | 256 | { | 
|  | 257 | debug("BMC State is {BMC_STATE}", "BMC_STATE", bmcState); | 
|  | 258 | return false; | 
|  | 259 | } | 
|  | 260 | return true; | 
|  | 261 | } | 
|  | 262 |  | 
| Potin Lai | 0886545 | 2023-11-07 23:28:11 +0800 | [diff] [blame] | 263 | bool waitBmcReady(sdbusplus::bus_t& bus, std::chrono::seconds timeout) | 
|  | 264 | { | 
|  | 265 | while (timeout.count() != 0) | 
|  | 266 | { | 
|  | 267 | timeout--; | 
|  | 268 | if (isBmcReady(bus)) | 
|  | 269 | { | 
|  | 270 | return true; | 
|  | 271 | } | 
|  | 272 | std::this_thread::sleep_for(std::chrono::seconds(1)); | 
|  | 273 | } | 
|  | 274 | return false; | 
|  | 275 | } | 
|  | 276 |  | 
| Carol Wang | dc05939 | 2020-03-13 17:39:17 +0800 | [diff] [blame] | 277 | } // namespace utils | 
|  | 278 | } // namespace manager | 
|  | 279 | } // namespace state | 
|  | 280 | } // namespace phosphor |