1 /**
2  * Copyright © 2020 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 "ffdc_file.hpp"
19 #include "journal.hpp"
20 #include "xyz/openbmc_project/Logging/Create/server.hpp"
21 #include "xyz/openbmc_project/Logging/Entry/server.hpp"
22 
23 #include <sdbusplus/bus.hpp>
24 
25 #include <cstdint>
26 #include <map>
27 #include <string>
28 #include <tuple>
29 #include <vector>
30 
31 namespace phosphor::power::regulators
32 {
33 
34 using namespace sdbusplus::xyz::openbmc_project::Logging::server;
35 using FFDCTuple =
36     std::tuple<FFDCFormat, uint8_t, uint8_t, sdbusplus::message::unix_fd>;
37 
38 /**
39  * @class ErrorLogging
40  *
41  * Abstract base class that provides an error logging interface.
42  *
43  * The interface is used to create error logs.
44  */
45 class ErrorLogging
46 {
47   public:
48     // Specify which compiler-generated methods we want
49     ErrorLogging() = default;
50     ErrorLogging(const ErrorLogging&) = delete;
51     ErrorLogging(ErrorLogging&&) = delete;
52     ErrorLogging& operator=(const ErrorLogging&) = delete;
53     ErrorLogging& operator=(ErrorLogging&&) = delete;
54     virtual ~ErrorLogging() = default;
55 
56     /**
57      * Log a regulators configuration file error.
58      *
59      * This error is logged when the regulators configuration file could not be
60      * found, could not be read, or had invalid contents.
61      *
62      * @param severity severity level
63      * @param journal system journal
64      */
65     virtual void logConfigFileError(Entry::Level severity,
66                                     Journal& journal) = 0;
67 
68     /**
69      * Log a D-Bus error.
70      *
71      * This error is logged when D-Bus communication fails.
72      *
73      * @param severity severity level
74      * @param journal system journal
75      */
76     virtual void logDBusError(Entry::Level severity, Journal& journal) = 0;
77 
78     /**
79      * Log an I2C communication error.
80      *
81      * @param severity severity level
82      * @param journal system journal
83      * @param bus I2C bus in the form "/dev/i2c-X", where X is the 0-based bus
84      *            number
85      * @param addr 7 bit I2C address
86      * @param errorNumber errno value from the failed I2C operation
87      */
88     virtual void logI2CError(Entry::Level severity, Journal& journal,
89                              const std::string& bus, uint8_t addr,
90                              int errorNumber) = 0;
91 
92     /**
93      * Log an internal firmware error.
94      *
95      * @param severity severity level
96      * @param journal system journal
97      */
98     virtual void logInternalError(Entry::Level severity, Journal& journal) = 0;
99 
100     /**
101      * Log a PMBus error.
102      *
103      * This error is logged when the I2C communication was successful, but the
104      * PMBus value read is invalid or unsupported.
105      *
106      * @param severity severity level
107      * @param journal system journal
108      * @param inventoryPath D-Bus inventory path of the device where the error
109      *                      occurred
110      */
111     virtual void logPMBusError(Entry::Level severity, Journal& journal,
112                                const std::string& inventoryPath) = 0;
113 
114     /**
115      * Log a write verification error.
116      *
117      * This error is logged when a device register is written, read back, and
118      * the two values do not match.  This is also called a read-back error.
119      *
120      * @param severity severity level
121      * @param journal system journal
122      * @param inventoryPath D-Bus inventory path of the device where the error
123      *                      occurred
124      */
125     virtual void
126         logWriteVerificationError(Entry::Level severity, Journal& journal,
127                                   const std::string& inventoryPath) = 0;
128 };
129 
130 /**
131  * @class DBusErrorLogging
132  *
133  * Implementation of the ErrorLogging interface using D-Bus method calls.
134  */
135 class DBusErrorLogging : public ErrorLogging
136 {
137   public:
138     // Specify which compiler-generated methods we want
139     DBusErrorLogging() = delete;
140     DBusErrorLogging(const DBusErrorLogging&) = delete;
141     DBusErrorLogging(DBusErrorLogging&&) = delete;
142     DBusErrorLogging& operator=(const DBusErrorLogging&) = delete;
143     DBusErrorLogging& operator=(DBusErrorLogging&&) = delete;
144     virtual ~DBusErrorLogging() = default;
145 
146     /**
147      * Constructor.
148      *
149      * @param bus D-Bus bus object
150      */
151     explicit DBusErrorLogging(sdbusplus::bus::bus& bus) : bus{bus}
152     {
153     }
154 
155     /** @copydoc ErrorLogging::logConfigFileError() */
156     virtual void logConfigFileError(Entry::Level severity,
157                                     Journal& journal) override;
158 
159     /** @copydoc ErrorLogging::logDBusError() */
160     virtual void logDBusError(Entry::Level severity, Journal& journal) override;
161 
162     /** @copydoc ErrorLogging::logI2CError() */
163     virtual void logI2CError(Entry::Level severity, Journal& journal,
164                              const std::string& bus, uint8_t addr,
165                              int errorNumber) override;
166 
167     /** @copydoc ErrorLogging::logInternalError() */
168     virtual void logInternalError(Entry::Level severity,
169                                   Journal& journal) override;
170 
171     /** @copydoc ErrorLogging::logPMBusError() */
172     virtual void logPMBusError(Entry::Level severity, Journal& journal,
173                                const std::string& inventoryPath) override;
174 
175     /** @copydoc ErrorLogging::logWriteVerificationError() */
176     virtual void
177         logWriteVerificationError(Entry::Level severity, Journal& journal,
178                                   const std::string& inventoryPath) override;
179 
180   private:
181     /**
182      * Create an FFDCFile object containing the specified lines of text data.
183      *
184      * Throws an exception if an error occurs.
185      *
186      * @param lines lines of text data to write to file
187      * @return FFDCFile object
188      */
189     FFDCFile createFFDCFile(const std::vector<std::string>& lines);
190 
191     /**
192      * Create FFDCFile objects containing debug data to store in the error log.
193      *
194      * If an error occurs, the error is written to the journal but an exception
195      * is not thrown.
196      *
197      * @param journal system journal
198      * @return vector of FFDCFile objects
199      */
200     std::vector<FFDCFile> createFFDCFiles(Journal& journal);
201 
202     /**
203      * Create FFDCTuple objects corresponding to the specified FFDC files.
204      *
205      * The D-Bus method to create an error log requires a vector of tuples to
206      * pass in the FFDC file information.
207      *
208      * @param files FFDC files
209      * @return vector of FFDCTuple objects
210      */
211     std::vector<FFDCTuple> createFFDCTuples(std::vector<FFDCFile>& files);
212 
213     /**
214      * Returns the absolute form of the specified inventory path.
215      *
216      * The inventory paths in the JSON configuration file are relative.  Add the
217      * the necessary prefix to make the path absolute.
218      *
219      * @param inventoryPath relative D-Bus inventory path
220      * @return absolute D-Bus inventory path
221      */
222     std::string getAbsoluteInventoryPath(const std::string& inventoryPath)
223     {
224         std::string absPath = "/xyz/openbmc_project/inventory";
225         if ((!inventoryPath.empty()) && (inventoryPath.front() != '/'))
226         {
227             absPath += '/';
228         }
229         absPath += inventoryPath;
230         return absPath;
231     }
232 
233     /**
234      * Logs an error using the D-Bus CreateWithFFDCFiles method.
235      *
236      * If logging fails, a message is written to the journal but an exception is
237      * not thrown.
238      *
239      * @param message Message property of the error log entry
240      * @param severity Severity property of the error log entry
241      * @param additionalData AdditionalData property of the error log entry
242      * @param journal system journal
243      */
244     void logError(const std::string& message, Entry::Level severity,
245                   std::map<std::string, std::string>& additionalData,
246                   Journal& journal);
247 
248     /**
249      * Removes the specified FFDC files from the file system.
250      *
251      * Also clears the specified vector, removing the FFDCFile objects.
252      *
253      * If an error occurs, the error is written to the journal but an exception
254      * is not thrown.
255      *
256      * @param files FFDC files to remove
257      * @param journal system journal
258      */
259     void removeFFDCFiles(std::vector<FFDCFile>& files, Journal& journal);
260 
261     /**
262      * D-Bus bus object.
263      */
264     sdbusplus::bus::bus& bus;
265 };
266 
267 } // namespace phosphor::power::regulators
268