blob: 79ecc5bacf6021f642671a41ff2a943aac5562dd [file] [log] [blame]
Lei YUd19df252019-10-25 17:31:52 +08001/**
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
Lei YU7c2fbbb2019-11-06 14:56:02 +080018#include "i2c_interface.hpp"
19
Lei YU9ab6d752019-10-28 17:03:20 +080020#include <sdbusplus/bus.hpp>
Brandon Wymand1bc4ce2019-12-13 14:20:34 -060021
22#include <filesystem>
Faisal Awadaec61bbd2024-11-04 08:46:20 -060023#include <memory>
Lei YUd19df252019-10-25 17:31:52 +080024#include <string>
25
Lei YU7c2fbbb2019-11-06 14:56:02 +080026class TestUpdater;
27
Lei YUd19df252019-10-25 17:31:52 +080028namespace updater
29{
30
Lei YU9ab6d752019-10-28 17:03:20 +080031namespace fs = std::filesystem;
32
Faisal Awada57fb6642025-02-21 16:52:54 -060033constexpr auto FW_UPDATE_FAILED_MSG =
34 "xyz.openbmc_project.Power.PowerSupply.Error.FirmwareUpdateFailed";
35constexpr auto PSU_FW_FILE_ISSUE_MSG =
36 "xyz.openbmc_project.Power.PowerSupply.Error.FirmwareIssue";
37constexpr auto FW_UPDATE_SUCCESS_MSG =
38 "xyz.openbmc_project.Power.PowerSupply.Info.FirmwareUpdateSuccessful";
39
40constexpr auto ERROR_SEVERITY = "xyz.openbmc_project.Logging.Entry.Level.Error";
41constexpr auto INFORMATIONAL_SEVERITY =
42 "xyz.openbmc_project.Logging.Entry.Level.Informational";
43
Lei YUd19df252019-10-25 17:31:52 +080044/**
45 * Update PSU firmware
46 *
Faisal Awadaec61bbd2024-11-04 08:46:20 -060047 * @param[in] bus - The sdbusplus DBus bus connection
Lei YUd19df252019-10-25 17:31:52 +080048 * @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 */
Faisal Awadaec61bbd2024-11-04 08:46:20 -060053bool update(sdbusplus::bus_t& bus, const std::string& psuInventoryPath,
54 const std::string& imageDir);
Lei YUd19df252019-10-25 17:31:52 +080055
Faisal Awadafe5b5c62025-03-22 10:50:01 -050056/**
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 */
67bool validateAndUpdate(sdbusplus::bus_t& bus,
68 const std::string& psuInventoryPath,
69 const std::string& imageDir);
70
Lei YU9ab6d752019-10-28 17:03:20 +080071class Updater
72{
73 public:
Lei YU7c2fbbb2019-11-06 14:56:02 +080074 friend TestUpdater;
Lei YU9ab6d752019-10-28 17:03:20 +080075 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 */
Faisal Awadaec61bbd2024-11-04 08:46:20 -060092 virtual ~Updater() = default;
Lei YU9ab6d752019-10-28 17:03:20 +080093
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
Lei YU575ed132019-10-29 17:22:16 +0800106 /** @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
Lei YU9ab6d752019-10-28 17:03:20 +0800112 /** @brief Do the PSU update
113 *
114 * @return 0 if success, otherwise non-zero
115 */
Faisal Awadaec61bbd2024-11-04 08:46:20 -0600116 virtual int doUpdate();
Lei YU9ab6d752019-10-28 17:03:20 +0800117
Lei YU7c2fbbb2019-11-06 14:56:02 +0800118 /** @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
Faisal Awadaec61bbd2024-11-04 08:46:20 -0600125 protected:
126 /** @brief Accessor for PSU inventory path */
127 const std::string& getPsuInventoryPath() const
128 {
129 return psuInventoryPath;
130 }
131
132 /** @brief Accessor for device path */
133 const std::string& getDevPath() const
134 {
135 return devPath;
136 }
137
138 /** @brief Accessor for device name */
139 const std::string& getDevName() const
140 {
141 return devName;
142 }
143
144 /** @brief Accessor for image directory */
145 const std::string& getImageDir() const
146 {
147 return imageDir;
148 }
149
150 /** @brief I2C interface accessor */
151 i2c::I2CInterface* getI2C()
152 {
153 return i2c.get();
154 }
155
Faisal Awada57fb6642025-02-21 16:52:54 -0600156 /**
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 */
229 void enableEventLogging()
230 {
231 eventLogState = true;
232 }
233
234 /**
235 * @brief Accessor to set eventLogState to false
236 *
237 */
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 */
248 bool isEventLogEnabled()
249 {
250 return eventLogState;
251 }
252
253 /**
254 * @brief Accessor to disable eventLoggedThisSession
255 *
256 */
257 void enableEventLoggedThisSession()
258 {
259 eventLoggedThisSession = true;
260 }
261
262 /**
263 * @brief Accessor to retieve eventLoggedThisSession status
264 *
265 * @return true or false
266 */
267 bool isEventLoggedThisSession()
268 {
269 return eventLoggedThisSession;
270 }
271
272 /**
273 * @brief Call out successful PSU firmware update.
274 *
275 */
276 void callOutGoodEventLog();
277
Lei YU9ab6d752019-10-28 17:03:20 +0800278 private:
279 /** @brief The sdbusplus DBus bus connection */
Patrick Williams7354ce62022-07-22 19:26:56 -0500280 sdbusplus::bus_t bus;
Lei YU9ab6d752019-10-28 17:03:20 +0800281
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;
Lei YU7c2fbbb2019-11-06 14:56:02 +0800308
309 /** @brief The i2c device interface */
310 std::unique_ptr<i2c::I2CInterface> i2c;
Faisal Awada57fb6642025-02-21 16:52:54 -0600311
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;
Lei YU9ab6d752019-10-28 17:03:20 +0800319};
320
Faisal Awadaec61bbd2024-11-04 08:46:20 -0600321namespace internal
322{
323
324/**
Faisal Awadaec61bbd2024-11-04 08:46:20 -0600325 * @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 */
335std::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 */
346const 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 */
355uint8_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 */
362void 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 */
371std::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 */
380bool 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 */
389std::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 */
399std::vector<uint8_t> readFirmwareBytes(std::ifstream& inputFile,
400 const size_t numberOfBytesToRead);
401
Faisal Awadaec61bbd2024-11-04 08:46:20 -0600402} // namespace internal
Lei YUd19df252019-10-25 17:31:52 +0800403} // namespace updater