blob: 79ecc5bacf6021f642671a41ff2a943aac5562dd [file] [log] [blame]
/**
* Copyright © 2019 IBM Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "i2c_interface.hpp"
#include <sdbusplus/bus.hpp>
#include <filesystem>
#include <memory>
#include <string>
class TestUpdater;
namespace updater
{
namespace fs = std::filesystem;
constexpr auto FW_UPDATE_FAILED_MSG =
"xyz.openbmc_project.Power.PowerSupply.Error.FirmwareUpdateFailed";
constexpr auto PSU_FW_FILE_ISSUE_MSG =
"xyz.openbmc_project.Power.PowerSupply.Error.FirmwareIssue";
constexpr auto FW_UPDATE_SUCCESS_MSG =
"xyz.openbmc_project.Power.PowerSupply.Info.FirmwareUpdateSuccessful";
constexpr auto ERROR_SEVERITY = "xyz.openbmc_project.Logging.Entry.Level.Error";
constexpr auto INFORMATIONAL_SEVERITY =
"xyz.openbmc_project.Logging.Entry.Level.Informational";
/**
* Update PSU firmware
*
* @param[in] bus - The sdbusplus DBus bus connection
* @param[in] psuInventoryPath - The inventory path of the PSU
* @param[in] imageDir - The directory containing the PSU image
*
* @return true if successful, otherwise false
*/
bool update(sdbusplus::bus_t& bus, const std::string& psuInventoryPath,
const std::string& imageDir);
/**
* Validate number of present PSUs vs number of required PSUs for this system,
* and validate all PSUs have same model before proceeding to Update PSU
* firmware
*
* @param[in] bus - The sdbusplus DBus bus connection
* @param[in] psuInventoryPath - The inventory path of the PSU
* @param[in] imageDir - The directory containing the PSU image
*
* @return true if successful, otherwise false
*/
bool validateAndUpdate(sdbusplus::bus_t& bus,
const std::string& psuInventoryPath,
const std::string& imageDir);
class Updater
{
public:
friend TestUpdater;
Updater() = delete;
Updater(const Updater&) = delete;
Updater& operator=(const Updater&) = delete;
Updater(Updater&&) = default;
Updater& operator=(Updater&&) = default;
/**
* @brief Constructor
*
* @param psuInventoryPath - The PSU inventory path
* @param devPath - The PSU device path
* @param imageDir - The update image directory
*/
Updater(const std::string& psuInventoryPath, const std::string& devPath,
const std::string& imageDir);
/** @brief Destructor */
virtual ~Updater() = default;
/** @brief Bind or unbind the driver
*
* @param doBind - indicate if it's going to bind or unbind the driver
*/
void bindUnbind(bool doBind);
/** @brief Set the PSU inventory present property
*
* @param present - The present state to set
*/
void setPresent(bool present);
/** @brief Check if it's ready to update the PSU
*
* @return true if it's ready, otherwise false
*/
bool isReadyToUpdate();
/** @brief Do the PSU update
*
* @return 0 if success, otherwise non-zero
*/
virtual int doUpdate();
/** @brief Create I2C device
*
* Creates the I2C device based on the device name.
* e.g. It opens busId 3, address 0x68 for "3-0068"
*/
void createI2CDevice();
protected:
/** @brief Accessor for PSU inventory path */
const std::string& getPsuInventoryPath() const
{
return psuInventoryPath;
}
/** @brief Accessor for device path */
const std::string& getDevPath() const
{
return devPath;
}
/** @brief Accessor for device name */
const std::string& getDevName() const
{
return devName;
}
/** @brief Accessor for image directory */
const std::string& getImageDir() const
{
return imageDir;
}
/** @brief I2C interface accessor */
i2c::I2CInterface* getI2C()
{
return i2c.get();
}
/**
* @brief Creates a serviceable Predictive Event Log,
*
* This method generates an event log with the given error name, severity,
* and additional data. It interacts with the OpenBMC logging service to
* record faults.
*
* @param[in] errorName The name of the error to log.
* @param[in] severity The severity level of the error.
* @param[in] additionalData Additional key-value pairs containing details
* about the error.
*/
void createServiceableEventLog(
const std::string& errorName, const std::string& severity,
std::map<std::string, std::string>& additionalData);
/**
* @brief Retrieves additional data related to I2C communication.
*
* This method collects and returns I2C bus information, including the
* bus ID, address, and error number, which are used for reporting
* Predictive Error Log.
*
* @return A map containing I2C-related key-value pairs.
*/
std::map<std::string, std::string> getI2CAdditionalData();
/**
* @brief Call out an I2C-related Predictive Error Log.
*
* This method creates a serviceable event log related to I2C failures.
* It collects additional data about the I2C communication and logs the
* failure with appropriate severity.
*
* @param[in] extraAdditionalData Additional key-value pairs specific to
* the error context.
* @param[in] exceptionString A string describing the exception that
* triggered the error.
* @param[in] errorCode Exception error code.
*/
void callOutI2CEventLog(
std::map<std::string, std::string> extraAdditionalData,
const std::string& exceptionString = "", const int errorCode = 0);
/**
* @brief Call out a PSU-related Predictive Error Log.
*
* This method logs a failure related to PSU firmware updates and additional
* diagnostics data to the event log.
*
* @param[in] extraAdditionalData Additional key-value pairs specific to
* the PSU-related error.
*/
void callOutPsuEventLog(
std::map<std::string, std::string> extraAdditionalData);
/**
* @brief Call out a software-related Predictive Error Log.
*
* This method logs a failure related to PSU firmware file issues or other
* software-related errors. It merges any additional error-specific data
* before logging the event.
*
* @param[in] extraAdditionalData Additional key-value pairs specific to
* the software-related error.
*/
void callOutSWEventLog(
std::map<std::string, std::string> extraAdditionalData);
/**
* @brief Accessor to set logEventLog to true
*
*/
void enableEventLogging()
{
eventLogState = true;
}
/**
* @brief Accessor to set eventLogState to false
*
*/
void disableEventLogging()
{
eventLogState = false;
}
/**
* @brief Accessor eventLogState status (enable true, disable false)
*
* @return true or false
*/
bool isEventLogEnabled()
{
return eventLogState;
}
/**
* @brief Accessor to disable eventLoggedThisSession
*
*/
void enableEventLoggedThisSession()
{
eventLoggedThisSession = true;
}
/**
* @brief Accessor to retieve eventLoggedThisSession status
*
* @return true or false
*/
bool isEventLoggedThisSession()
{
return eventLoggedThisSession;
}
/**
* @brief Call out successful PSU firmware update.
*
*/
void callOutGoodEventLog();
private:
/** @brief The sdbusplus DBus bus connection */
sdbusplus::bus_t bus;
/** @brief The PSU inventory path */
std::string psuInventoryPath;
/** @brief The PSU device path
*
* Usually it is a device in i2c subsystem, e.g.
* /sys/bus/i2c/devices/3-0068
*/
std::string devPath;
/** @brief The PSU device name
*
* Usually it is a i2c device name, e.g.
* 3-0068
*/
std::string devName;
/** @brief The PSU image directory */
std::string imageDir;
/** @brief The PSU device driver's path
*
* Usually it is the PSU driver, e.g.
* /sys/bus/i2c/drivers/ibm-cffps
*/
fs::path driverPath;
/** @brief The i2c device interface */
std::unique_ptr<i2c::I2CInterface> i2c;
/** @brief Event Log flag */
bool eventLogState = false;
/** @brief Event logged this session flag, this is to make sure no other
* event log can be logged
*/
bool eventLoggedThisSession = false;
};
namespace internal
{
/**
* @brief Factory function to create an Updater instance based on PSU model
* number
*
* @param[in] model - PSU model number
* @param[in] psuInventoryPath - PSU inventory path
* @param[in] devPath - Device path
* @param[in] imageDir - Image directory
*
* return pointer class based on the device PSU model.
*/
std::unique_ptr<updater::Updater> getClassInstance(
const std::string& model, const std::string& psuInventoryPath,
const std::string& devPath, const std::string& imageDir);
/**
* @brief Retrieve the firmware filename path in the specified directory
*
* @param[in] directory - Path to FS directory
*
* @retun filename or null
*/
const std::string getFWFilenamePath(const std::string& directory);
/**
* @brief Calculate CRC-8 for a data vector
*
* @param[in] data - Firmware data block
*
* @return CRC8
*/
uint8_t calculateCRC8(const std::vector<uint8_t>& data);
/**
* @brief Delay execution in milliseconds
*
* @param[in] milliseconds - Time in milliseconds
*/
void delay(const int& milliseconds);
/**
* @brief Convert a big-endian value to little-endian
*
* @param[in] bigEndianValue - Uint 32 bit value
*
* @return vector of little endians.
*/
std::vector<uint8_t> bigEndianToLittleEndian(const uint32_t bigEndianValue);
/**
* @brief Validate the existence and size of a firmware file.
*
* @param[in] fileName - Firmware file name
*
* @return true for success or false
*/
bool validateFWFile(const std::string& fileName);
/**
* @brief Open a firmware file for reading in binary mode.
*
* @param[in] fileName - Firmware file name
*
* @return pointer to firmware file stream
*/
std::unique_ptr<std::ifstream> openFirmwareFile(const std::string& fileName);
/**
* @brief Read firmware bytes from file.
*
* @param[in] inputFile - Input file stream
* @param[in] numberOfBytesToRead - Number of bytes to read from firmware file.
*
* @return vector of data read
*/
std::vector<uint8_t> readFirmwareBytes(std::ifstream& inputFile,
const size_t numberOfBytesToRead);
} // namespace internal
} // namespace updater