blob: 9c9ace7bb18db432357f7f26a85548663b4c18ae [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>
28
29namespace phosphor::power::sequencer
30{
31
32void 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
59bool BMCServices::isPresent(const std::string& inventoryPath)
60{
61 // Initially assume hardware is not present
62 bool present{false};
63
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050064 // Try to find cached presence value
65 auto it = presenceCache.find(inventoryPath);
66 if (it != presenceCache.end())
Shawn McCarney906cc3f2024-02-01 13:33:06 -060067 {
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050068 present = it->second;
Shawn McCarney906cc3f2024-02-01 13:33:06 -060069 }
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050070 else
Shawn McCarney906cc3f2024-02-01 13:33:06 -060071 {
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050072 // Get presence from D-Bus interface/property
73 try
Shawn McCarney906cc3f2024-02-01 13:33:06 -060074 {
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050075 util::getProperty(INVENTORY_IFACE, PRESENT_PROP, inventoryPath,
76 INVENTORY_MGR_IFACE, bus, present);
Shawn McCarney906cc3f2024-02-01 13:33:06 -060077 }
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050078 catch (const sdbusplus::exception_t& e)
Shawn McCarney906cc3f2024-02-01 13:33:06 -060079 {
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050080 // If exception type is expected and indicates hardware not present
81 if (isExpectedException(e))
82 {
83 present = false;
84 }
85 else
86 {
87 // Re-throw unexpected exception
88 throw;
89 }
Shawn McCarney906cc3f2024-02-01 13:33:06 -060090 }
Shawn McCarneye4fef0f2024-04-05 17:56:09 -050091
92 // Cache presence value
93 presenceCache[inventoryPath] = present;
Shawn McCarney906cc3f2024-02-01 13:33:06 -060094 }
95
96 return present;
97}
98
99std::vector<int> BMCServices::getGPIOValues(const std::string& chipLabel)
100{
101 // Set up the chip object
102 gpiod::chip chip{chipLabel, gpiod::chip::OPEN_BY_LABEL};
103 unsigned int numLines = chip.num_lines();
104 lg2::info(
105 "Reading GPIO values from chip {NAME} with label {LABEL} and {NUM_LINES} lines",
106 "NAME", chip.name(), "LABEL", chipLabel, "NUM_LINES", numLines);
107
108 // Read GPIO values. Work around libgpiod bulk line maximum by getting
109 // values from individual lines.
110 std::vector<int> values;
111 for (unsigned int offset = 0; offset < numLines; ++offset)
112 {
113 gpiod::line line = chip.get_line(offset);
114 line.request({"phosphor-power-control",
115 gpiod::line_request::DIRECTION_INPUT, 0});
116 values.push_back(line.get_value());
117 line.release();
118 }
119 return values;
120}
121
122bool BMCServices::isExpectedException(const sdbusplus::exception_t& e)
123{
124 // Initially assume exception is not one of the expected types
125 bool isExpected{false};
126
127 // If the D-Bus error name is set within the exception
128 if (e.name() != nullptr)
129 {
130 // Check if the error name is one of the expected values when hardware
131 // is not present.
132 //
133 // Sometimes the object path does not exist. Sometimes the object path
134 // exists, but it does not implement the D-Bus interface that contains
135 // the present property. Both of these cases result in exceptions.
136 //
137 // In the case where the interface is not implemented, the systemd
138 // documentation seems to indicate that the error name should be
139 // SD_BUS_ERROR_UNKNOWN_INTERFACE. However, in OpenBMC the
140 // SD_BUS_ERROR_UNKNOWN_PROPERTY error name can occur.
141 std::string name = e.name();
142 if ((name == SD_BUS_ERROR_UNKNOWN_OBJECT) ||
143 (name == SD_BUS_ERROR_UNKNOWN_INTERFACE) ||
144 (name == SD_BUS_ERROR_UNKNOWN_PROPERTY))
145 {
146 isExpected = true;
147 }
148 }
149
150 return isExpected;
151}
152
153} // namespace phosphor::power::sequencer