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