blob: 5078be1992896990509dbd34383417ca8ff6c184 [file] [log] [blame]
Shawn McCarney906cc3f2024-02-01 13:33:06 -06001/**
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>
Shawn McCarney3a11d632024-05-23 10:12:56 -050028#include <variant>
Shawn McCarney906cc3f2024-02-01 13:33:06 -060029
30namespace phosphor::power::sequencer
31{
32
33void BMCServices::logError(const std::string& message, Entry::Level severity,
34 std::map<std::string, std::string>& additionalData)
35{
36 try
37 {
38 // Add PID to AdditionalData
39 additionalData.emplace("_PID", std::to_string(getpid()));
40
41 // If severity is critical, set error as system terminating
42 if (severity == Entry::Level::Critical)
43 {
44 additionalData.emplace("SEVERITY_DETAIL", "SYSTEM_TERM");
45 }
46
47 auto method = bus.new_method_call(
48 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
49 "xyz.openbmc_project.Logging.Create", "Create");
50 method.append(message, severity, additionalData);
51 bus.call_noreply(method);
52 }
53 catch (const std::exception& e)
54 {
55 lg2::error("Unable to log error {ERROR}: {EXCEPTION}", "ERROR", message,
56 "EXCEPTION", e);
57 }
58}
59
60bool BMCServices::isPresent(const std::string& inventoryPath)
61{
62 // Initially assume hardware is not present
63 bool present{false};
64
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050065 // Try to find cached presence value
66 auto it = presenceCache.find(inventoryPath);
67 if (it != presenceCache.end())
Shawn McCarney906cc3f2024-02-01 13:33:06 -060068 {
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050069 present = it->second;
Shawn McCarney906cc3f2024-02-01 13:33:06 -060070 }
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050071 else
Shawn McCarney906cc3f2024-02-01 13:33:06 -060072 {
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050073 // Get presence from D-Bus interface/property
74 try
Shawn McCarney906cc3f2024-02-01 13:33:06 -060075 {
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050076 util::getProperty(INVENTORY_IFACE, PRESENT_PROP, inventoryPath,
77 INVENTORY_MGR_IFACE, bus, present);
Shawn McCarney906cc3f2024-02-01 13:33:06 -060078 }
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050079 catch (const sdbusplus::exception_t& e)
Shawn McCarney906cc3f2024-02-01 13:33:06 -060080 {
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050081 // If exception type is expected and indicates hardware not present
82 if (isExpectedException(e))
83 {
84 present = false;
85 }
86 else
87 {
88 // Re-throw unexpected exception
89 throw;
90 }
Shawn McCarney906cc3f2024-02-01 13:33:06 -060091 }
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050092
93 // Cache presence value
94 presenceCache[inventoryPath] = present;
Shawn McCarney906cc3f2024-02-01 13:33:06 -060095 }
96
97 return present;
98}
99
100std::vector<int> BMCServices::getGPIOValues(const std::string& chipLabel)
101{
102 // Set up the chip object
103 gpiod::chip chip{chipLabel, gpiod::chip::OPEN_BY_LABEL};
104 unsigned int numLines = chip.num_lines();
105 lg2::info(
106 "Reading GPIO values from chip {NAME} with label {LABEL} and {NUM_LINES} lines",
107 "NAME", chip.name(), "LABEL", chipLabel, "NUM_LINES", numLines);
108
109 // Read GPIO values. Work around libgpiod bulk line maximum by getting
110 // values from individual lines.
111 std::vector<int> values;
112 for (unsigned int offset = 0; offset < numLines; ++offset)
113 {
114 gpiod::line line = chip.get_line(offset);
115 line.request({"phosphor-power-control",
116 gpiod::line_request::DIRECTION_INPUT, 0});
117 values.push_back(line.get_value());
118 line.release();
119 }
120 return values;
121}
122
123bool BMCServices::isExpectedException(const sdbusplus::exception_t& e)
124{
125 // Initially assume exception is not one of the expected types
126 bool isExpected{false};
127
128 // If the D-Bus error name is set within the exception
129 if (e.name() != nullptr)
130 {
131 // Check if the error name is one of the expected values when hardware
132 // is not present.
133 //
134 // Sometimes the object path does not exist. Sometimes the object path
135 // exists, but it does not implement the D-Bus interface that contains
136 // the present property. Both of these cases result in exceptions.
137 //
138 // In the case where the interface is not implemented, the systemd
139 // documentation seems to indicate that the error name should be
140 // SD_BUS_ERROR_UNKNOWN_INTERFACE. However, in OpenBMC the
141 // SD_BUS_ERROR_UNKNOWN_PROPERTY error name can occur.
142 std::string name = e.name();
143 if ((name == SD_BUS_ERROR_UNKNOWN_OBJECT) ||
144 (name == SD_BUS_ERROR_UNKNOWN_INTERFACE) ||
145 (name == SD_BUS_ERROR_UNKNOWN_PROPERTY))
146 {
147 isExpected = true;
148 }
149 }
150
151 return isExpected;
152}
153
Shawn McCarney3a11d632024-05-23 10:12:56 -0500154void BMCServices::createBMCDump()
155{
156 try
157 {
158 auto method = bus.new_method_call(
159 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump/bmc",
160 "xyz.openbmc_project.Dump.Create", "CreateDump");
161 method.append(
162 std::vector<
163 std::pair<std::string, std::variant<std::string, uint64_t>>>());
164 bus.call_noreply(method);
165 }
166 catch (const std::exception& e)
167 {
168 lg2::error("Unable to create BMC dump: {ERROR}", "ERROR", e);
169 }
170}
171
Shawn McCarney906cc3f2024-02-01 13:33:06 -0600172} // namespace phosphor::power::sequencer