xref: /openbmc/phosphor-power/tools/power-utils/updater.hpp (revision 57fb664c133d31a1f094441f29f30552004bb487)
1 /**
2  * Copyright © 2019 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 "i2c_interface.hpp"
19 
20 #include <sdbusplus/bus.hpp>
21 
22 #include <filesystem>
23 #include <memory>
24 #include <string>
25 
26 class TestUpdater;
27 
28 namespace updater
29 {
30 
31 namespace fs = std::filesystem;
32 
33 constexpr auto FW_UPDATE_FAILED_MSG =
34     "xyz.openbmc_project.Power.PowerSupply.Error.FirmwareUpdateFailed";
35 constexpr auto PSU_FW_FILE_ISSUE_MSG =
36     "xyz.openbmc_project.Power.PowerSupply.Error.FirmwareIssue";
37 constexpr auto FW_UPDATE_SUCCESS_MSG =
38     "xyz.openbmc_project.Power.PowerSupply.Info.FirmwareUpdateSuccessful";
39 
40 constexpr auto ERROR_SEVERITY = "xyz.openbmc_project.Logging.Entry.Level.Error";
41 constexpr auto INFORMATIONAL_SEVERITY =
42     "xyz.openbmc_project.Logging.Entry.Level.Informational";
43 
44 /**
45  * Update PSU firmware
46  *
47  * @param[in] bus - The sdbusplus DBus bus connection
48  * @param[in] psuInventoryPath - The inventory path of the PSU
49  * @param[in] imageDir - The directory containing the PSU image
50  *
51  * @return true if successful, otherwise false
52  */
53 bool update(sdbusplus::bus_t& bus, const std::string& psuInventoryPath,
54             const std::string& imageDir);
55 
56 class Updater
57 {
58   public:
59     friend TestUpdater;
60     Updater() = delete;
61     Updater(const Updater&) = delete;
62     Updater& operator=(const Updater&) = delete;
63     Updater(Updater&&) = default;
64     Updater& operator=(Updater&&) = default;
65 
66     /**
67      * @brief Constructor
68      *
69      * @param psuInventoryPath - The PSU inventory path
70      * @param devPath - The PSU device path
71      * @param imageDir - The update image directory
72      */
73     Updater(const std::string& psuInventoryPath, const std::string& devPath,
74             const std::string& imageDir);
75 
76     /** @brief Destructor */
77     virtual ~Updater() = default;
78 
79     /** @brief Bind or unbind the driver
80      *
81      * @param doBind - indicate if it's going to bind or unbind the driver
82      */
83     void bindUnbind(bool doBind);
84 
85     /** @brief Set the PSU inventory present property
86      *
87      * @param present - The present state to set
88      */
89     void setPresent(bool present);
90 
91     /** @brief Check if it's ready to update the PSU
92      *
93      * @return true if it's ready, otherwise false
94      */
95     bool isReadyToUpdate();
96 
97     /** @brief Do the PSU update
98      *
99      * @return 0 if success, otherwise non-zero
100      */
101     virtual int doUpdate();
102 
103     /** @brief Create I2C device
104      *
105      * Creates the I2C device based on the device name.
106      * e.g. It opens busId 3, address 0x68 for "3-0068"
107      */
108     void createI2CDevice();
109 
110   protected:
111     /** @brief Accessor for PSU inventory path */
getPsuInventoryPath() const112     const std::string& getPsuInventoryPath() const
113     {
114         return psuInventoryPath;
115     }
116 
117     /** @brief Accessor for device path */
getDevPath() const118     const std::string& getDevPath() const
119     {
120         return devPath;
121     }
122 
123     /** @brief Accessor for device name */
getDevName() const124     const std::string& getDevName() const
125     {
126         return devName;
127     }
128 
129     /** @brief Accessor for image directory */
getImageDir() const130     const std::string& getImageDir() const
131     {
132         return imageDir;
133     }
134 
135     /** @brief I2C interface accessor */
getI2C()136     i2c::I2CInterface* getI2C()
137     {
138         return i2c.get();
139     }
140 
141     /**
142      * @brief Creates a serviceable Predictive Event Log,
143      *
144      * This method generates an event log with the given error name, severity,
145      * and additional data. It interacts with the OpenBMC logging service to
146      * record faults.
147      *
148      * @param[in] errorName The name of the error to log.
149      * @param[in] severity The severity level of the error.
150      * @param[in] additionalData Additional key-value pairs containing details
151      *                           about the error.
152      */
153     void createServiceableEventLog(
154         const std::string& errorName, const std::string& severity,
155         std::map<std::string, std::string>& additionalData);
156 
157     /**
158      * @brief Retrieves additional data related to I2C communication.
159      *
160      * This method collects and returns I2C bus information, including the
161      * bus ID, address, and error number, which are used for reporting
162      * Predictive Error Log.
163      *
164      * @return A map containing I2C-related key-value pairs.
165      */
166     std::map<std::string, std::string> getI2CAdditionalData();
167 
168     /**
169      * @brief Call out an I2C-related Predictive Error Log.
170      *
171      * This method creates a serviceable event log related to I2C failures.
172      * It collects additional data about the I2C communication and logs the
173      * failure with appropriate severity.
174      *
175      * @param[in] extraAdditionalData Additional key-value pairs specific to
176      *                                the error context.
177      * @param[in] exceptionString A string describing the exception that
178      *                            triggered the error.
179      * @param[in] errorCode Exception error code.
180      */
181     void callOutI2CEventLog(
182         std::map<std::string, std::string> extraAdditionalData,
183         const std::string& exceptionString = "", const int errorCode = 0);
184 
185     /**
186      * @brief Call out a PSU-related Predictive Error Log.
187      *
188      * This method logs a failure related to PSU firmware updates and additional
189      * diagnostics data to the event log.
190      *
191      * @param[in] extraAdditionalData Additional key-value pairs specific to
192      *                                the PSU-related error.
193      */
194     void callOutPsuEventLog(
195         std::map<std::string, std::string> extraAdditionalData);
196 
197     /**
198      * @brief Call out a software-related Predictive Error Log.
199      *
200      * This method logs a failure related to PSU firmware file issues or other
201      * software-related errors. It merges any additional error-specific data
202      * before logging the event.
203      *
204      * @param[in] extraAdditionalData Additional key-value pairs specific to
205      *                                the software-related error.
206      */
207     void callOutSWEventLog(
208         std::map<std::string, std::string> extraAdditionalData);
209 
210     /**
211      * @brief Accessor to set logEventLog to true
212      *
213      */
enableEventLogging()214     void enableEventLogging()
215     {
216         eventLogState = true;
217     }
218 
219     /**
220      * @brief Accessor to set eventLogState to false
221      *
222      */
disableEventLogging()223     void disableEventLogging()
224     {
225         eventLogState = false;
226     }
227 
228     /**
229      * @brief Accessor eventLogState status (enable true, disable false)
230      *
231      * @return true or false
232      */
isEventLogEnabled()233     bool isEventLogEnabled()
234     {
235         return eventLogState;
236     }
237 
238     /**
239      * @brief Accessor to disable eventLoggedThisSession
240      *
241      */
enableEventLoggedThisSession()242     void enableEventLoggedThisSession()
243     {
244         eventLoggedThisSession = true;
245     }
246 
247     /**
248      * @brief Accessor to retieve eventLoggedThisSession status
249      *
250      * @return true or false
251      */
isEventLoggedThisSession()252     bool isEventLoggedThisSession()
253     {
254         return eventLoggedThisSession;
255     }
256 
257     /**
258      * @brief Call out successful PSU firmware update.
259      *
260      */
261     void callOutGoodEventLog();
262 
263   private:
264     /** @brief The sdbusplus DBus bus connection */
265     sdbusplus::bus_t bus;
266 
267     /** @brief The PSU inventory path */
268     std::string psuInventoryPath;
269 
270     /** @brief The PSU device path
271      *
272      * Usually it is a device in i2c subsystem, e.g.
273      *   /sys/bus/i2c/devices/3-0068
274      */
275     std::string devPath;
276 
277     /** @brief The PSU device name
278      *
279      * Usually it is a i2c device name, e.g.
280      *   3-0068
281      */
282     std::string devName;
283 
284     /** @brief The PSU image directory */
285     std::string imageDir;
286 
287     /** @brief The PSU device driver's path
288      *
289      * Usually it is the PSU driver, e.g.
290      *   /sys/bus/i2c/drivers/ibm-cffps
291      */
292     fs::path driverPath;
293 
294     /** @brief The i2c device interface */
295     std::unique_ptr<i2c::I2CInterface> i2c;
296 
297     /** @brief Event Log flag */
298     bool eventLogState = false;
299 
300     /** @brief Event logged this session flag, this is to make sure no other
301      * event log can be logged
302      */
303     bool eventLoggedThisSession = false;
304 };
305 
306 namespace internal
307 {
308 
309 /**
310  * @brief Factory function to create an Updater instance based on PSU model
311  * number
312  *
313  * @param[in] model - PSU model number
314  * @param[in] psuInventoryPath - PSU inventory path
315  * @param[in] devPath - Device path
316  * @param[in] imageDir - Image directory
317  *
318  * return pointer class based on the device PSU model.
319  */
320 std::unique_ptr<updater::Updater> getClassInstance(
321     const std::string& model, const std::string& psuInventoryPath,
322     const std::string& devPath, const std::string& imageDir);
323 
324 /**
325  * @brief Retrieve the firmware filename path in the specified directory
326  *
327  * @param[in] directory - Path to FS directory
328  *
329  * @retun filename or null
330  */
331 const std::string getFWFilenamePath(const std::string& directory);
332 
333 /**
334  * @brief Calculate CRC-8 for a data vector
335  *
336  * @param[in] data - Firmware data block
337  *
338  * @return CRC8
339  */
340 uint8_t calculateCRC8(const std::vector<uint8_t>& data);
341 
342 /**
343  * @brief Delay execution in milliseconds
344  *
345  * @param[in] milliseconds - Time in milliseconds
346  */
347 void delay(const int& milliseconds);
348 
349 /**
350  * @brief Convert a big-endian value to little-endian
351  *
352  * @param[in] bigEndianValue - Uint 32 bit value
353  *
354  * @return vector of little endians.
355  */
356 std::vector<uint8_t> bigEndianToLittleEndian(const uint32_t bigEndianValue);
357 
358 /**
359  * @brief Validate the existence and size of a firmware file.
360  *
361  * @param[in] fileName - Firmware file name
362  *
363  * @return true for success or false
364  */
365 bool validateFWFile(const std::string& fileName);
366 
367 /**
368  * @brief Open a firmware file for reading in binary mode.
369  *
370  * @param[in] fileName - Firmware file name
371  *
372  * @return pointer to firmware file stream
373  */
374 std::unique_ptr<std::ifstream> openFirmwareFile(const std::string& fileName);
375 
376 /**
377  * @brief Read firmware bytes from file.
378  *
379  * @param[in] inputFile - Input file stream
380  * @param[in] numberOfBytesToRead - Number of bytes to read from firmware file.
381  *
382  * @return vector of data read
383  */
384 std::vector<uint8_t> readFirmwareBytes(std::ifstream& inputFile,
385                                        const size_t numberOfBytesToRead);
386 
387 } // namespace internal
388 } // namespace updater
389