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