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 #pragma once
17 
18 #include "pmbus.hpp"
19 #include "xyz/openbmc_project/Logging/Entry/server.hpp"
20 
21 #include <phosphor-logging/lg2.hpp>
22 #include <sdbusplus/bus.hpp>
23 #include <sdbusplus/exception.hpp>
24 
25 #include <cstdint>
26 #include <format>
27 #include <map>
28 #include <memory>
29 #include <string>
30 #include <vector>
31 
32 namespace phosphor::power::sequencer
33 {
34 
35 using namespace sdbusplus::xyz::openbmc_project::Logging::server;
36 using PMBusBase = phosphor::pmbus::PMBusBase;
37 using PMBus = phosphor::pmbus::PMBus;
38 
39 /**
40  * @class Services
41  *
42  * Abstract base class that provides an interface to system services like error
43  * logging and the journal.
44  */
45 class Services
46 {
47   public:
48     // Specify which compiler-generated methods we want
49     Services() = default;
50     Services(const Services&) = delete;
51     Services(Services&&) = delete;
52     Services& operator=(const Services&) = delete;
53     Services& operator=(Services&&) = delete;
54     virtual ~Services() = default;
55 
56     /**
57      * Returns the D-Bus bus object.
58      *
59      * @return D-Bus bus
60      */
61     virtual sdbusplus::bus_t& getBus() = 0;
62 
63     /**
64      * Logs an error message in the system journal.
65      *
66      * @param message message to log
67      */
68     virtual void logErrorMsg(const std::string& message) = 0;
69 
70     /**
71      * Logs an informational message in the system journal.
72      *
73      * @param message message to log
74      */
75     virtual void logInfoMsg(const std::string& message) = 0;
76 
77     /**
78      * Logs an error.
79      *
80      * If logging fails, a message is written to the system journal but an
81      * exception is not thrown.
82      *
83      * @param message Message property of the error log entry
84      * @param severity Severity property of the error log entry
85      * @param additionalData AdditionalData property of the error log entry
86      */
87     virtual void
88         logError(const std::string& message, Entry::Level severity,
89                  std::map<std::string, std::string>& additionalData) = 0;
90 
91     /**
92      * Returns whether the hardware with the specified inventory path is
93      * present.
94      *
95      * Throws an exception if an error occurs while obtaining the presence
96      * value.
97      *
98      * @param inventoryPath D-Bus inventory path of the hardware
99      * @return true if hardware is present, false otherwise
100      */
101     virtual bool isPresent(const std::string& inventoryPath) = 0;
102 
103     /**
104      * Reads all the GPIO values on the chip with the specified label.
105      *
106      * Throws an exception if an error occurs while obtaining the values.
107      *
108      * @param chipLabel label identifying the chip with the GPIOs
109      * @return GPIO values
110      */
111     virtual std::vector<int> getGPIOValues(const std::string& chipLabel) = 0;
112 
113     /**
114      * Creates object for communicating with a PMBus device by reading and
115      * writing sysfs files.
116      *
117      * Throws an exception if an error occurs.
118      *
119      * @param bus I2C bus
120      * @param address I2C address
121      * @param driverName Device driver name
122      * @param instance Chip instance number
123      * @return object for communicating with PMBus device
124      */
125     virtual std::unique_ptr<PMBusBase> createPMBus(
126         uint8_t bus, uint16_t address, const std::string& driverName = "",
127         size_t instance = 0) = 0;
128 
129     /**
130      * Creates a BMC dump.
131      */
132     virtual void createBMCDump() = 0;
133 
134     /**
135      * Clear any cached data.
136      *
137      * Some data may be cached for performance reasons, such as hardware
138      * presence.  Clearing the cache results in the latest data being obtained
139      * by a subsequent method calls.
140      */
141     virtual void clearCache() = 0;
142 };
143 
144 /**
145  * @class BMCServices
146  *
147  * Implementation of the Services interface using standard BMC system services.
148  */
149 class BMCServices : public Services
150 {
151   public:
152     // Specify which compiler-generated methods we want
153     BMCServices() = delete;
154     BMCServices(const BMCServices&) = delete;
155     BMCServices(BMCServices&&) = delete;
156     BMCServices& operator=(const BMCServices&) = delete;
157     BMCServices& operator=(BMCServices&&) = delete;
158     virtual ~BMCServices() = default;
159 
160     /**
161      * Constructor.
162      *
163      * @param bus D-Bus bus object
164      */
BMCServices(sdbusplus::bus_t & bus)165     explicit BMCServices(sdbusplus::bus_t& bus) : bus{bus} {}
166 
167     /** @copydoc Services::getBus() */
getBus()168     virtual sdbusplus::bus_t& getBus() override
169     {
170         return bus;
171     }
172 
173     /** @copydoc Services::logErrorMsg() */
logErrorMsg(const std::string & message)174     virtual void logErrorMsg(const std::string& message) override
175     {
176         lg2::error(message.c_str());
177     }
178 
179     /** @copydoc Services::logInfoMsg() */
logInfoMsg(const std::string & message)180     virtual void logInfoMsg(const std::string& message) override
181     {
182         lg2::info(message.c_str());
183     }
184 
185     /** @copydoc Services::logError() */
186     virtual void
187         logError(const std::string& message, Entry::Level severity,
188                  std::map<std::string, std::string>& additionalData) override;
189 
190     /** @copydoc Services::isPresent() */
191     virtual bool isPresent(const std::string& inventoryPath) override;
192 
193     /** @copydoc Services::getGPIOValues() */
194     virtual std::vector<int>
195         getGPIOValues(const std::string& chipLabel) override;
196 
197     /** @copydoc Services::createPMBus() */
createPMBus(uint8_t bus,uint16_t address,const std::string & driverName="",size_t instance=0)198     virtual std::unique_ptr<PMBusBase> createPMBus(
199         uint8_t bus, uint16_t address, const std::string& driverName = "",
200         size_t instance = 0) override
201     {
202         std::string path =
203             std::format("/sys/bus/i2c/devices/{}-{:04x}", bus, address);
204         return std::make_unique<PMBus>(path, driverName, instance);
205     }
206 
207     /** @copydoc Services::createBMCDump() */
208     virtual void createBMCDump() override;
209 
210     /** @copydoc Services::clearCache() */
clearCache()211     virtual void clearCache() override
212     {
213         presenceCache.clear();
214     }
215 
216   private:
217     /**
218      * Returns whether the specified D-Bus exception is one of the expected
219      * types that can be thrown if hardware is not present.
220      *
221      * @return true if exception type is expected, false otherwise
222      */
223     bool isExpectedException(const sdbusplus::exception_t& e);
224 
225     /**
226      * D-Bus bus object.
227      */
228     sdbusplus::bus_t& bus;
229 
230     /**
231      * Cached presence data.
232      *
233      * Map from inventory paths to presence values.
234      */
235     std::map<std::string, bool> presenceCache{};
236 };
237 
238 } // namespace phosphor::power::sequencer
239