| /** |
| * Copyright © 2024 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. |
| */ |
| |
| #include "config.h" |
| |
| #include "aei_updater.hpp" |
| |
| #include "pmbus.hpp" |
| #include "types.hpp" |
| #include "updater.hpp" |
| #include "utility.hpp" |
| #include "utils.hpp" |
| |
| #include <phosphor-logging/lg2.hpp> |
| |
| #include <fstream> |
| #include <system_error> |
| |
| namespace aeiUpdater |
| { |
| |
| constexpr uint8_t MAX_RETRIES = 0x02; // Constants for retry limits |
| |
| constexpr int ISP_STATUS_DELAY = 1200; // Delay for ISP status check (1.2s) |
| constexpr int MEM_WRITE_DELAY = 5000; // Memory write delay (5s) |
| constexpr int MEM_STRETCH_DELAY = 1; // Delay between writes (1ms) |
| constexpr int MEM_COMPLETE_DELAY = 2000; // Delay before completion (2s) |
| constexpr int REBOOT_DELAY = 8000; // Delay for reboot (8s) |
| |
| constexpr uint8_t I2C_SMBUS_BLOCK_MAX = 0x20; // Max Read bytes from PSU |
| constexpr uint8_t FW_READ_BLOCK_SIZE = 0x20; // Read bytes from FW file |
| constexpr uint8_t BLOCK_WRITE_SIZE = 0x25; // I2C block write size |
| |
| constexpr uint8_t START_SEQUENCE_INDEX = 0x1; // Starting sequence index |
| constexpr uint8_t STATUS_CML_INDEX = 0x4; // Status CML read index |
| constexpr uint8_t EXPECTED_MEM_READ_REPLY = 0x5; // Expected memory read reply |
| // size after write data |
| |
| // Register addresses for commands. |
| constexpr uint8_t KEY_REGISTER = 0xF6; // Key register |
| constexpr uint8_t STATUS_REGISTER = 0xF7; // Status register |
| constexpr uint8_t ISP_MEMORY_REGISTER = 0xF9; // ISP memory register |
| |
| // Define AEI ISP status register commands |
| constexpr uint8_t CMD_CLEAR_STATUS = 0x0; // Clear the status register |
| constexpr uint8_t CMD_RESET_SEQ = 0x01; // This command will reset ISP OS for |
| // another attempt of a sequential |
| // programming operation. |
| constexpr uint8_t CMD_BOOT_ISP = 0x02; // Boot the In-System Programming System. |
| constexpr uint8_t CMD_BOOT_PWR = 0x03; // Attempt to boot the Power Management |
| // OS. |
| |
| // Define AEI ISP response status bit |
| constexpr uint8_t B_ISP_MODE = 0x40; // ISP mode |
| constexpr uint8_t B_ISP_MODE_CHKSUM_GOOD = 0x41; // ISP mode & good checksum. |
| constexpr uint8_t SUCCESSFUL_ISP_REBOOT_STATUS = 0x0; // Successful ISP reboot |
| // status |
| namespace util = phosphor::power::util; |
| |
| int AeiUpdater::doUpdate() |
| { |
| i2cInterface = Updater::getI2C(); |
| enableEventLogging(); |
| if (i2cInterface == nullptr) |
| { |
| // Report serviceable error |
| std::map<std::string, std::string> additionalData = { |
| {"I2C_INTERFACE", "I2C interface is null pointer."}}; |
| // Callout PSU & I2C |
| callOutI2CEventLog(additionalData); |
| |
| throw std::runtime_error("I2C interface error"); |
| } |
| if (!getFirmwarePath() || !isFirmwareFileValid()) |
| { |
| return 1; // No firmware file abort download |
| } |
| bool downloadFwFailed = false; // Download Firmware status |
| int retryProcessTwo(0); |
| int retryProcessOne(0); |
| disableEventLogging(); |
| while ((retryProcessTwo < MAX_RETRIES) && (retryProcessOne < MAX_RETRIES)) |
| { |
| // Write AEI PSU ISP key |
| if (!writeIspKey()) |
| { |
| lg2::error("Failed to set ISP Key"); |
| downloadFwFailed = true; // Download Firmware status |
| break; |
| } |
| |
| if (retryProcessTwo == (MAX_RETRIES - 1)) |
| { |
| enableEventLogging(); |
| } |
| retryProcessTwo++; |
| while (retryProcessOne < MAX_RETRIES) |
| { |
| downloadFwFailed = false; // Download Firmware status |
| retryProcessOne++; |
| // Set ISP mode |
| if (!writeIspMode()) |
| { |
| // Write ISP Mode failed MAX_RETRIES times |
| retryProcessTwo = MAX_RETRIES; |
| downloadFwFailed = true; // Download Firmware Failed |
| break; |
| } |
| |
| // Reset ISP status |
| if (writeIspStatusReset()) |
| { |
| // Start PSU firmware download. |
| if (downloadPsuFirmware()) |
| { |
| if (!verifyDownloadFWStatus()) |
| { |
| downloadFwFailed = true; |
| continue; |
| } |
| } |
| else |
| { |
| // One of the block write commands failed, retry download |
| // procedure one time starting with re-writing initial ISP |
| // mode. If it fails again, log serviceable error. |
| if (retryProcessOne == MAX_RETRIES) |
| { |
| // Callout PSU failed to update FW |
| std::map<std::string, std::string> additionalData = { |
| {"UPDATE_FAILED", "Download firmware failed"}}; |
| |
| callOutPsuEventLog(additionalData); |
| ispReboot(); // Try to set PSU to normal mode |
| } |
| downloadFwFailed = true; |
| continue; |
| } |
| } |
| else |
| { |
| // ISP Status Reset failed MAX_RETRIES times |
| retryProcessTwo = MAX_RETRIES; |
| downloadFwFailed = true; |
| break; |
| } |
| |
| ispReboot(); |
| |
| if (ispReadRebootStatus() && !downloadFwFailed) |
| { |
| // Download completed successful |
| retryProcessTwo = MAX_RETRIES; |
| break; |
| } |
| else |
| { |
| // Retry the whole download process starting with the key and |
| // if fails again then report event log |
| if ((retryProcessOne < (MAX_RETRIES - 1)) && |
| (retryProcessTwo < (MAX_RETRIES - 1))) |
| { |
| downloadFwFailed = false; |
| break; |
| } |
| } |
| } |
| } |
| if (downloadFwFailed) |
| { |
| return 1; |
| } |
| enableEventLogging(); |
| bindUnbind(true); |
| updater::internal::delay(100); |
| callOutGoodEventLog(); |
| return 0; // Update successful |
| } |
| |
| bool AeiUpdater::writeIspKey() |
| { |
| // ISP Key to unlock programming mode ( ASCII for "artY"). |
| constexpr std::array<uint8_t, 4> unlockData = {0x61, 0x72, 0x74, |
| 0x59}; // ISP Key "artY" |
| for (int retry = 0; retry < MAX_RETRIES; ++retry) |
| { |
| try |
| { |
| // Send ISP Key to unlock device for firmware update |
| i2cInterface->write(KEY_REGISTER, unlockData.size(), |
| unlockData.data()); |
| disableEventLogging(); |
| return true; |
| } |
| catch (const i2c::I2CException& e) |
| { |
| // Log failure if I2C write fails. |
| lg2::error("I2C write failed: {ERROR}", "ERROR", e); |
| std::map<std::string, std::string> additionalData = { |
| {"I2C_ISP_KEY", "ISP key failed due to I2C exception"}}; |
| callOutI2CEventLog(additionalData, e.what(), e.errorCode); |
| enableEventLogging(); // enable event logging if fail again call out |
| // PSU & I2C |
| } |
| |
| catch (const std::exception& e) |
| { |
| lg2::error("Exception write failed: {ERROR}", "ERROR", e); |
| std::map<std::string, std::string> additionalData = { |
| {"ISP_KEY", "ISP key failed due to exception"}, |
| {"EXCEPTION", e.what()}}; |
| callOutPsuEventLog(additionalData); |
| enableEventLogging(); // enable Event Logging if fail again call out |
| // PSU |
| } |
| } |
| return false; |
| } |
| |
| bool AeiUpdater::writeIspMode() |
| { |
| // Attempt to set device in ISP mode with retries. |
| uint8_t ispStatus = 0x0; |
| uint8_t exceptionCount = 0; |
| for (int retry = 0; retry < MAX_RETRIES; ++retry) |
| { |
| try |
| { |
| // Write command to enter ISP mode. |
| i2cInterface->write(STATUS_REGISTER, CMD_BOOT_ISP); |
| // Delay to allow status register update. |
| updater::internal::delay(ISP_STATUS_DELAY); |
| // Read back status register to confirm ISP mode is active. |
| i2cInterface->read(STATUS_REGISTER, ispStatus); |
| |
| if (ispStatus & B_ISP_MODE) |
| { |
| lg2::info("Set ISP Mode"); |
| disableEventLogging(); |
| return true; |
| } |
| enableEventLogging(); |
| } |
| catch (const i2c::I2CException& e) |
| { |
| exceptionCount++; |
| // Log I2C error with each retry attempt. |
| lg2::error("I2C exception during ISP mode write/read: {ERROR}", |
| "ERROR", e); |
| if (exceptionCount == MAX_RETRIES) |
| { |
| enableEventLogging(); |
| std::map<std::string, std::string> additionalData = { |
| {"I2C_FIRMWARE_STATUS", |
| "Download firmware failed during writeIspMode due to I2C exception"}}; |
| // Callout PSU & I2C |
| callOutI2CEventLog(additionalData, e.what(), e.errorCode); |
| return false; // Failed to set ISP Mode |
| } |
| } |
| catch (const std::exception& e) |
| { |
| exceptionCount++; |
| // Log error with each retry attempt. |
| lg2::error("Exception during ISP mode write/read: {ERROR}", "ERROR", |
| e); |
| if (exceptionCount == MAX_RETRIES) |
| { |
| enableEventLogging(); |
| std::map<std::string, std::string> additionalData = { |
| {"FIRMWARE_STATUS", |
| "Download firmware failed during writeIspMode due to exception"}, |
| {"EXCEPTION", e.what()}}; |
| // Callout PSU |
| callOutPsuEventLog(additionalData); |
| return false; // Failed to set ISP Mode |
| } |
| } |
| } |
| |
| if (exceptionCount != MAX_RETRIES) |
| { |
| // Callout PSU |
| std::map<std::string, std::string> additionalData = { |
| {"FIRMWARE_STATUS", |
| "Download firmware failed during writeIspMode"}}; |
| callOutPsuEventLog(additionalData); |
| } |
| |
| lg2::error("Failed to set ISP Mode"); |
| return false; // Failed to set ISP Mode after retries |
| } |
| |
| bool AeiUpdater::writeIspStatusReset() |
| { |
| // Reset ISP status register before firmware download. |
| uint8_t ispStatus = 0; |
| uint8_t exceptionCount = 0; |
| for (int retry = 0; retry < MAX_RETRIES; retry++) |
| { |
| try |
| { |
| i2cInterface->write(STATUS_REGISTER, |
| CMD_RESET_SEQ); // Start reset sequence. |
| retry = MAX_RETRIES; |
| } |
| catch (const i2c::I2CException& e) |
| { |
| exceptionCount++; |
| // Log any errors encountered during reset sequence. |
| lg2::error("I2C Write ISP reset failed: {ERROR}", "ERROR", e); |
| if (exceptionCount == MAX_RETRIES) |
| { |
| enableEventLogging(); |
| std::map<std::string, std::string> additionalData = { |
| {"I2C_ISP_RESET", "I2C exception during ISP status reset"}}; |
| // Callout PSU & I2C |
| callOutI2CEventLog(additionalData, e.what(), e.errorCode); |
| ispReboot(); |
| return false; |
| } |
| } |
| catch (const std::exception& e) |
| { |
| exceptionCount++; |
| // Log any errors encountered during reset sequence. |
| lg2::error("Write ISP reset failed: {ERROR}", "ERROR", e); |
| if (exceptionCount == MAX_RETRIES) |
| { |
| enableEventLogging(); |
| std::map<std::string, std::string> additionalData = { |
| {"ISP_RESET", "Exception during ISP status reset"}, |
| {"EXCEPTION", e.what()}}; |
| // Callout PSU |
| callOutPsuEventLog(additionalData); |
| ispReboot(); |
| return false; |
| } |
| } |
| } |
| |
| exceptionCount = 0; |
| for (int retry = 0; retry < MAX_RETRIES; ++retry) |
| { |
| try |
| { |
| i2cInterface->read(STATUS_REGISTER, ispStatus); |
| if (ispStatus == B_ISP_MODE) |
| { |
| lg2::info("write/read ISP reset"); |
| disableEventLogging(); |
| return true; // ISP status reset successfully. |
| } |
| i2cInterface->write(STATUS_REGISTER, |
| CMD_CLEAR_STATUS); // Clear status if |
| // not reset. |
| lg2::error("Write ISP reset failed"); |
| enableEventLogging(); |
| } |
| catch (const i2c::I2CException& e) |
| { |
| exceptionCount++; |
| // Log any errors encountered during reset sequence. |
| lg2::error( |
| "I2C Write/Read or Write error during ISP reset: {ERROR}", |
| "ERROR", e); |
| if (exceptionCount == MAX_RETRIES) |
| { |
| enableEventLogging(); |
| std::map<std::string, std::string> additionalData = { |
| {"I2C_ISP_READ_STATUS", |
| "I2C exception during read ISP status"}}; |
| // Callout PSU & I2C |
| callOutI2CEventLog(additionalData, e.what(), e.errorCode); |
| } |
| } |
| catch (const std::exception& e) |
| { |
| exceptionCount++; |
| // Log any errors encountered during reset sequence. |
| lg2::error("Write/Read or Write error during ISP reset: {ERROR}", |
| "ERROR", e); |
| if (exceptionCount == MAX_RETRIES) |
| { |
| enableEventLogging(); |
| std::map<std::string, std::string> additionalData = { |
| {"ISP_READ_STATUS", "Exception during read ISP status"}, |
| {"EXCEPTION", e.what()}}; |
| // Callout PSU |
| callOutPsuEventLog(additionalData); |
| } |
| } |
| } |
| if (exceptionCount != MAX_RETRIES) |
| { |
| std::map<std::string, std::string> additionalData = { |
| {"ISP_REST_FAILED", "Failed to read ISP expected status"}}; |
| // Callout PSU |
| callOutPsuEventLog(additionalData); |
| } |
| lg2::error("Failed to reset ISP Status"); |
| ispReboot(); |
| return false; |
| } |
| |
| bool AeiUpdater::getFirmwarePath() |
| { |
| fspath = updater::internal::getFWFilenamePath(getImageDir()); |
| if (fspath.empty()) |
| { |
| std::map<std::string, std::string> additionalData = { |
| {"FILE_PATH", "Firmware file path is null"}}; |
| // Callout BMC0001 procedure |
| callOutSWEventLog(additionalData); |
| lg2::error("Firmware file path not found"); |
| return false; |
| } |
| return true; |
| } |
| |
| bool AeiUpdater::isFirmwareFileValid() |
| { |
| if (!updater::internal::validateFWFile(fspath)) |
| { |
| std::map<std::string, std::string> additionalData = { |
| {"FIRMWARE_VALID", |
| "Firmware validation failed, FW file path = " + fspath}}; |
| // Callout BMC0001 procedure |
| callOutSWEventLog(additionalData); |
| lg2::error("Firmware validation failed, fspath={PATH}", "PATH", fspath); |
| return false; |
| } |
| return true; |
| } |
| |
| std::unique_ptr<std::ifstream> AeiUpdater::openFirmwareFile() |
| { |
| auto inputFile = updater::internal::openFirmwareFile(fspath); |
| if (!inputFile) |
| { |
| std::map<std::string, std::string> additionalData = { |
| {"FIRMWARE_OPEN", |
| "Firmware file failed to open, FW file path = " + fspath}}; |
| // Callout BMC0001 procedure |
| callOutSWEventLog(additionalData); |
| lg2::error("Failed to open firmware file"); |
| } |
| return inputFile; |
| } |
| |
| std::vector<uint8_t> AeiUpdater::readFirmwareBlock(std::ifstream& file, |
| const size_t& bytesToRead) |
| { |
| auto block = updater::internal::readFirmwareBytes(file, bytesToRead); |
| return block; |
| } |
| |
| void AeiUpdater::prepareCommandBlock(const std::vector<uint8_t>& dataBlockRead) |
| { |
| cmdBlockWrite.clear(); // Clear cmdBlockWrite before use |
| // Assign new values to cmdBlockWrite |
| cmdBlockWrite.push_back(ISP_MEMORY_REGISTER); |
| cmdBlockWrite.push_back(BLOCK_WRITE_SIZE); |
| cmdBlockWrite.insert(cmdBlockWrite.end(), byteSwappedIndex.begin(), |
| byteSwappedIndex.end()); |
| cmdBlockWrite.insert(cmdBlockWrite.end(), dataBlockRead.begin(), |
| dataBlockRead.end()); |
| |
| // Resize to ensure it matches BLOCK_WRITE_SIZE + 1 and append CRC |
| if (cmdBlockWrite.size() != BLOCK_WRITE_SIZE + 1) |
| { |
| cmdBlockWrite.resize(BLOCK_WRITE_SIZE + 1, 0xFF); |
| } |
| cmdBlockWrite.push_back(updater::internal::calculateCRC8(cmdBlockWrite)); |
| // Remove the F9 and byte count |
| cmdBlockWrite.erase(cmdBlockWrite.begin(), cmdBlockWrite.begin() + 2); |
| } |
| |
| bool AeiUpdater::downloadPsuFirmware() |
| { |
| // Open firmware file |
| auto inputFile = openFirmwareFile(); |
| if (!inputFile) |
| { |
| if (isEventLogEnabled()) |
| { |
| // Callout BMC0001 procedure |
| std::map<std::string, std::string> additionalData = { |
| {"FW_FAILED_TO_OPEN", "Firmware file failed to open"}, |
| {"FW_FILE_PATH", fspath}}; |
| |
| callOutSWEventLog(additionalData); |
| ispReboot(); // Try to set PSU to normal mode |
| } |
| lg2::error("Unable to open firmware file {FILE}", "FILE", fspath); |
| return false; |
| } |
| |
| // Read and process firmware file in blocks |
| size_t bytesRead = 0; |
| const auto fileSize = std::filesystem::file_size(fspath); |
| bool downloadFailed = false; |
| byteSwappedIndex = |
| updater::internal::bigEndianToLittleEndian(START_SEQUENCE_INDEX); |
| int writeBlockDelay = MEM_WRITE_DELAY; |
| |
| while ((bytesRead < fileSize) && !downloadFailed) |
| { |
| // Read a block of firmware data |
| auto dataRead = readFirmwareBlock(*inputFile, FW_READ_BLOCK_SIZE); |
| bytesRead += dataRead.size(); |
| |
| // Prepare command block with the current index and data |
| prepareCommandBlock(dataRead); |
| |
| // Perform I2C write/read with retries |
| uint8_t readData[I2C_SMBUS_BLOCK_MAX] = {}; |
| downloadFailed = !performI2cWriteReadWithRetries( |
| ISP_MEMORY_REGISTER, EXPECTED_MEM_READ_REPLY, readData, MAX_RETRIES, |
| writeBlockDelay); |
| |
| // Adjust delay after first write block |
| writeBlockDelay = MEM_STRETCH_DELAY; |
| } |
| |
| inputFile->close(); |
| |
| // Log final download status |
| if (downloadFailed) |
| { |
| lg2::error( |
| "Firmware download failed after retries at FW block {BYTESREAD}", |
| "BYTESREAD", bytesRead); |
| return false; // Failed |
| } |
| return true; |
| } |
| |
| bool AeiUpdater::performI2cWriteReadWithRetries( |
| uint8_t regAddr, const uint8_t expectedReadSize, uint8_t* readData, |
| const int retries, const int delayTime) |
| { |
| uint8_t exceptionCount = 0; |
| uint32_t bigEndianValue = 0; |
| for (int i = 0; i < retries; ++i) |
| { |
| uint8_t readReplySize = 0; |
| try |
| { |
| performI2cWriteRead(regAddr, readReplySize, readData, delayTime); |
| if ((readData[STATUS_CML_INDEX] == 0 || |
| // The first firmware data packet sent to the PSU have a |
| // response of 0x80 which indicates firmware update in |
| // progress. If retry to send the first packet again reply will |
| // be 0. |
| (readData[STATUS_CML_INDEX] == 0x80 && |
| delayTime == MEM_WRITE_DELAY)) && |
| (readReplySize == expectedReadSize) && |
| !std::equal(readData, readData + 4, byteSwappedIndex.begin())) |
| { |
| std::copy(readData, readData + 4, byteSwappedIndex.begin()); |
| return true; |
| } |
| else |
| { |
| bigEndianValue = (readData[0] << 24) | (readData[1] << 16) | |
| (readData[2] << 8) | (readData[3]); |
| lg2::error("Write/read block {NUM} failed", "NUM", |
| bigEndianValue); |
| } |
| } |
| catch (const i2c::I2CException& e) |
| { |
| exceptionCount++; |
| if (exceptionCount == MAX_RETRIES) |
| { |
| std::map<std::string, std::string> additionalData = { |
| {"I2C_WRITE_READ", |
| "I2C exception while flashing the firmware."}}; |
| // Callout PSU & I2C |
| callOutI2CEventLog(additionalData, e.what(), e.errorCode); |
| } |
| lg2::error("I2C exception write/read block failed: {ERROR}", |
| "ERROR", e.what()); |
| } |
| catch (const std::exception& e) |
| { |
| exceptionCount++; |
| if (exceptionCount == MAX_RETRIES) |
| { |
| std::map<std::string, std::string> additionalData = { |
| {"WRITE_READ", "Exception while flashing the firmware."}, |
| {"EXCEPTION", e.what()}}; |
| // Callout PSU |
| callOutPsuEventLog(additionalData); |
| } |
| lg2::error("Exception write/read block failed: {ERROR}", "ERROR", |
| e.what()); |
| } |
| } |
| std::map<std::string, std::string> additionalData = { |
| {"WRITE_READ", |
| "Download firmware failed block: " + std::to_string(bigEndianValue)}}; |
| // Callout PSU |
| callOutPsuEventLog(additionalData); |
| return false; |
| } |
| |
| void AeiUpdater::performI2cWriteRead(uint8_t regAddr, uint8_t& readReplySize, |
| uint8_t* readData, const int& delayTime) |
| { |
| i2cInterface->processCall(regAddr, cmdBlockWrite.size(), |
| cmdBlockWrite.data(), readReplySize, readData); |
| |
| if (delayTime != 0) |
| { |
| updater::internal::delay(delayTime); |
| } |
| } |
| |
| bool AeiUpdater::verifyDownloadFWStatus() |
| { |
| try |
| { |
| // Read and verify firmware download status. |
| uint8_t status = 0; |
| i2cInterface->read(STATUS_REGISTER, status); |
| if (status != B_ISP_MODE_CHKSUM_GOOD) |
| { |
| lg2::error("Firmware download failed - status: {ERR}", "ERR", |
| status); |
| |
| return false; // Failed checksum |
| } |
| return true; |
| } |
| catch (const std::exception& e) |
| { |
| lg2::error("I2C read status register failed: {ERROR}", "ERROR", e); |
| } |
| return false; // Failed |
| } |
| |
| void AeiUpdater::ispReboot() |
| { |
| updater::internal::delay( |
| MEM_COMPLETE_DELAY); // Delay before starting the reboot process |
| |
| try |
| { |
| // Write reboot command to the status register |
| i2cInterface->write(STATUS_REGISTER, CMD_BOOT_PWR); |
| |
| updater::internal::delay( |
| REBOOT_DELAY); // Add delay after writing reboot command |
| } |
| catch (const std::exception& e) |
| { |
| lg2::error("I2C write error during reboot: {ERROR}", "ERROR", e); |
| } |
| } |
| |
| bool AeiUpdater::ispReadRebootStatus() |
| { |
| for (int retry = 0; retry < MAX_RETRIES; ++retry) |
| { |
| try |
| { |
| // Read from the status register to verify reboot |
| uint8_t data = 1; // Initialize data to a non-zero value |
| i2cInterface->read(STATUS_REGISTER, data); |
| |
| // If the reboot was successful, the read data should be 0 |
| if (data == SUCCESSFUL_ISP_REBOOT_STATUS) |
| { |
| lg2::info("ISP Status Reboot successful."); |
| return true; |
| } |
| } |
| catch (const i2c::I2CException& e) |
| { |
| if (isEventLogEnabled()) |
| { |
| std::map<std::string, std::string> additionalData = { |
| {"I2C_READ_REBOOT", |
| "I2C exception while reading ISP reboot status"}}; |
| |
| // Callout PSU & I2C |
| callOutI2CEventLog(additionalData, e.what(), e.errorCode); |
| } |
| lg2::error("I2C read error during reboot attempt: {ERROR}", "ERROR", |
| e); |
| } |
| catch (const std::exception& e) |
| { |
| if (isEventLogEnabled()) |
| { |
| std::map<std::string, std::string> additionalData = { |
| {"READ_REBOOT", |
| "Exception while reading ISP reboot status"}, |
| {"EXCEPTION", e.what()}}; |
| |
| // Callout PSU |
| callOutPsuEventLog(additionalData); |
| } |
| lg2::error("Read exception during reboot attempt: {ERROR}", "ERROR", |
| e); |
| } |
| // Reboot the PSU |
| ispReboot(); // Try to set PSU to normal mode |
| } |
| |
| // If we reach here, all retries have failed |
| lg2::error("Failed to reboot ISP status after max retries."); |
| return false; |
| } |
| } // namespace aeiUpdater |