1 /** 2 * Copyright © 2024 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 "services.hpp" 18 19 #include "types.hpp" 20 #include "utility.hpp" 21 22 #include <sys/types.h> // for getpid() 23 #include <unistd.h> // for getpid() 24 25 #include <gpiod.hpp> 26 27 #include <exception> 28 29 namespace phosphor::power::sequencer 30 { 31 32 void BMCServices::logError(const std::string& message, Entry::Level severity, 33 std::map<std::string, std::string>& additionalData) 34 { 35 try 36 { 37 // Add PID to AdditionalData 38 additionalData.emplace("_PID", std::to_string(getpid())); 39 40 // If severity is critical, set error as system terminating 41 if (severity == Entry::Level::Critical) 42 { 43 additionalData.emplace("SEVERITY_DETAIL", "SYSTEM_TERM"); 44 } 45 46 auto method = bus.new_method_call( 47 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging", 48 "xyz.openbmc_project.Logging.Create", "Create"); 49 method.append(message, severity, additionalData); 50 bus.call_noreply(method); 51 } 52 catch (const std::exception& e) 53 { 54 lg2::error("Unable to log error {ERROR}: {EXCEPTION}", "ERROR", message, 55 "EXCEPTION", e); 56 } 57 } 58 59 bool BMCServices::isPresent(const std::string& inventoryPath) 60 { 61 // Initially assume hardware is not present 62 bool present{false}; 63 64 // Get presence from D-Bus interface/property 65 try 66 { 67 util::getProperty(INVENTORY_IFACE, PRESENT_PROP, inventoryPath, 68 INVENTORY_MGR_IFACE, bus, present); 69 } 70 catch (const sdbusplus::exception_t& e) 71 { 72 // If exception type is expected and indicates hardware not present 73 if (isExpectedException(e)) 74 { 75 present = false; 76 } 77 else 78 { 79 // Re-throw unexpected exception 80 throw; 81 } 82 } 83 84 return present; 85 } 86 87 std::vector<int> BMCServices::getGPIOValues(const std::string& chipLabel) 88 { 89 // Set up the chip object 90 gpiod::chip chip{chipLabel, gpiod::chip::OPEN_BY_LABEL}; 91 unsigned int numLines = chip.num_lines(); 92 lg2::info( 93 "Reading GPIO values from chip {NAME} with label {LABEL} and {NUM_LINES} lines", 94 "NAME", chip.name(), "LABEL", chipLabel, "NUM_LINES", numLines); 95 96 // Read GPIO values. Work around libgpiod bulk line maximum by getting 97 // values from individual lines. 98 std::vector<int> values; 99 for (unsigned int offset = 0; offset < numLines; ++offset) 100 { 101 gpiod::line line = chip.get_line(offset); 102 line.request({"phosphor-power-control", 103 gpiod::line_request::DIRECTION_INPUT, 0}); 104 values.push_back(line.get_value()); 105 line.release(); 106 } 107 return values; 108 } 109 110 bool BMCServices::isExpectedException(const sdbusplus::exception_t& e) 111 { 112 // Initially assume exception is not one of the expected types 113 bool isExpected{false}; 114 115 // If the D-Bus error name is set within the exception 116 if (e.name() != nullptr) 117 { 118 // Check if the error name is one of the expected values when hardware 119 // is not present. 120 // 121 // Sometimes the object path does not exist. Sometimes the object path 122 // exists, but it does not implement the D-Bus interface that contains 123 // the present property. Both of these cases result in exceptions. 124 // 125 // In the case where the interface is not implemented, the systemd 126 // documentation seems to indicate that the error name should be 127 // SD_BUS_ERROR_UNKNOWN_INTERFACE. However, in OpenBMC the 128 // SD_BUS_ERROR_UNKNOWN_PROPERTY error name can occur. 129 std::string name = e.name(); 130 if ((name == SD_BUS_ERROR_UNKNOWN_OBJECT) || 131 (name == SD_BUS_ERROR_UNKNOWN_INTERFACE) || 132 (name == SD_BUS_ERROR_UNKNOWN_PROPERTY)) 133 { 134 isExpected = true; 135 } 136 } 137 138 return isExpected; 139 } 140 141 } // namespace phosphor::power::sequencer 142