xref: /openbmc/phosphor-power/tools/power-utils/aei_updater.cpp (revision 57fb664c133d31a1f094441f29f30552004bb487)
15a582d3cSFaisal Awada /**
25a582d3cSFaisal Awada  * Copyright © 2024 IBM Corporation
35a582d3cSFaisal Awada  *
45a582d3cSFaisal Awada  * Licensed under the Apache License, Version 2.0 (the "License");
55a582d3cSFaisal Awada  * you may not use this file except in compliance with the License.
65a582d3cSFaisal Awada  * You may obtain a copy of the License at
75a582d3cSFaisal Awada  *
85a582d3cSFaisal Awada  *     http://www.apache.org/licenses/LICENSE-2.0
95a582d3cSFaisal Awada  *
105a582d3cSFaisal Awada  * Unless required by applicable law or agreed to in writing, software
115a582d3cSFaisal Awada  * distributed under the License is distributed on an "AS IS" BASIS,
125a582d3cSFaisal Awada  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135a582d3cSFaisal Awada  * See the License for the specific language governing permissions and
145a582d3cSFaisal Awada  * limitations under the License.
155a582d3cSFaisal Awada  */
165a582d3cSFaisal Awada 
175a582d3cSFaisal Awada #include "config.h"
185a582d3cSFaisal Awada 
195a582d3cSFaisal Awada #include "aei_updater.hpp"
205a582d3cSFaisal Awada 
215a582d3cSFaisal Awada #include "pmbus.hpp"
225a582d3cSFaisal Awada #include "types.hpp"
235a582d3cSFaisal Awada #include "updater.hpp"
245a582d3cSFaisal Awada #include "utility.hpp"
25*57fb664cSFaisal Awada #include "utils.hpp"
265a582d3cSFaisal Awada 
275a582d3cSFaisal Awada #include <phosphor-logging/lg2.hpp>
285a582d3cSFaisal Awada 
298dca5075SFaisal Awada #include <fstream>
30*57fb664cSFaisal Awada #include <system_error>
318dca5075SFaisal Awada 
325a582d3cSFaisal Awada namespace aeiUpdater
335a582d3cSFaisal Awada {
34f0c0c47bSJayanth Othayoth 
355a582d3cSFaisal Awada constexpr uint8_t MAX_RETRIES = 0x02;    // Constants for retry limits
365a582d3cSFaisal Awada 
375a582d3cSFaisal Awada constexpr int ISP_STATUS_DELAY = 1200;   // Delay for ISP status check (1.2s)
385a582d3cSFaisal Awada constexpr int MEM_WRITE_DELAY = 5000;    // Memory write delay (5s)
395ace9fb7SFaisal Awada constexpr int MEM_STRETCH_DELAY = 1;     // Delay between writes (1ms)
405a582d3cSFaisal Awada constexpr int MEM_COMPLETE_DELAY = 2000; // Delay before completion (2s)
415a582d3cSFaisal Awada constexpr int REBOOT_DELAY = 8000;       // Delay for reboot (8s)
425a582d3cSFaisal Awada 
435a582d3cSFaisal Awada constexpr uint8_t I2C_SMBUS_BLOCK_MAX = 0x20;    // Max Read bytes from PSU
445a582d3cSFaisal Awada constexpr uint8_t FW_READ_BLOCK_SIZE = 0x20;     // Read bytes from FW file
455a582d3cSFaisal Awada constexpr uint8_t BLOCK_WRITE_SIZE = 0x25;       // I2C block write size
465ace9fb7SFaisal Awada 
475a582d3cSFaisal Awada constexpr uint8_t START_SEQUENCE_INDEX = 0x1;    // Starting sequence index
485ace9fb7SFaisal Awada constexpr uint8_t STATUS_CML_INDEX = 0x4;        // Status CML read index
495ace9fb7SFaisal Awada constexpr uint8_t EXPECTED_MEM_READ_REPLY = 0x5; //  Expected memory read reply
505ace9fb7SFaisal Awada                                                  //  size after write data
515a582d3cSFaisal Awada 
525a582d3cSFaisal Awada // Register addresses for commands.
535a582d3cSFaisal Awada constexpr uint8_t KEY_REGISTER = 0xF6;        // Key register
545a582d3cSFaisal Awada constexpr uint8_t STATUS_REGISTER = 0xF7;     // Status register
555a582d3cSFaisal Awada constexpr uint8_t ISP_MEMORY_REGISTER = 0xF9; // ISP memory register
565a582d3cSFaisal Awada 
575a582d3cSFaisal Awada // Define AEI ISP status register commands
585a582d3cSFaisal Awada constexpr uint8_t CMD_CLEAR_STATUS = 0x0; // Clear the status register
595a582d3cSFaisal Awada constexpr uint8_t CMD_RESET_SEQ = 0x01;   // This command will reset ISP OS for
605a582d3cSFaisal Awada                                           // another attempt of a sequential
615a582d3cSFaisal Awada                                           // programming operation.
625a582d3cSFaisal Awada constexpr uint8_t CMD_BOOT_ISP = 0x02; // Boot the In-System Programming System.
635a582d3cSFaisal Awada constexpr uint8_t CMD_BOOT_PWR = 0x03; // Attempt to boot the Power Management
645a582d3cSFaisal Awada                                        // OS.
655a582d3cSFaisal Awada 
665a582d3cSFaisal Awada // Define AEI ISP response status bit
675a582d3cSFaisal Awada constexpr uint8_t B_ISP_MODE = 0x40;             // ISP mode
685a582d3cSFaisal Awada constexpr uint8_t B_ISP_MODE_CHKSUM_GOOD = 0x41; // ISP mode  & good checksum.
698dca5075SFaisal Awada constexpr uint8_t SUCCESSFUL_ISP_REBOOT_STATUS = 0x0; // Successful ISP reboot
708dca5075SFaisal Awada                                                       // status
715a582d3cSFaisal Awada using namespace phosphor::logging;
725a582d3cSFaisal Awada namespace util = phosphor::power::util;
735a582d3cSFaisal Awada 
doUpdate()745a582d3cSFaisal Awada int AeiUpdater::doUpdate()
755a582d3cSFaisal Awada {
765a582d3cSFaisal Awada     i2cInterface = Updater::getI2C();
77*57fb664cSFaisal Awada     enableEventLogging();
785a582d3cSFaisal Awada     if (i2cInterface == nullptr)
795a582d3cSFaisal Awada     {
80*57fb664cSFaisal Awada         // Report serviceable error
81*57fb664cSFaisal Awada         std::map<std::string, std::string> additionalData = {
82*57fb664cSFaisal Awada             {"I2C_INTERFACE", "I2C interface is null pointer."}};
83*57fb664cSFaisal Awada         // Callout PSU & I2C
84*57fb664cSFaisal Awada         callOutI2CEventLog(additionalData);
85*57fb664cSFaisal Awada 
865a582d3cSFaisal Awada         throw std::runtime_error("I2C interface error");
875a582d3cSFaisal Awada     }
88f9b426b4SFaisal Awada     if (!getFirmwarePath() || !isFirmwareFileValid())
89f9b426b4SFaisal Awada     {
90f9b426b4SFaisal Awada         return 1;                  // No firmware file abort download
91f9b426b4SFaisal Awada     }
925ace9fb7SFaisal Awada     bool downloadFwFailed = false; // Download Firmware status
935ace9fb7SFaisal Awada     int retryProcessTwo(0);
945ace9fb7SFaisal Awada     int retryProcessOne(0);
95*57fb664cSFaisal Awada     disableEventLogging();
965ace9fb7SFaisal Awada     while ((retryProcessTwo < MAX_RETRIES) && (retryProcessOne < MAX_RETRIES))
975a582d3cSFaisal Awada     {
985ace9fb7SFaisal Awada         // Write AEI PSU ISP key
995ace9fb7SFaisal Awada         if (!writeIspKey())
1005ace9fb7SFaisal Awada         {
1015ace9fb7SFaisal Awada             lg2::error("Failed to set ISP Key");
1025ace9fb7SFaisal Awada             downloadFwFailed = true; // Download Firmware status
103*57fb664cSFaisal Awada             break;
1045a582d3cSFaisal Awada         }
1055a582d3cSFaisal Awada 
106*57fb664cSFaisal Awada         if (retryProcessTwo == (MAX_RETRIES - 1))
107*57fb664cSFaisal Awada         {
108*57fb664cSFaisal Awada             enableEventLogging();
109*57fb664cSFaisal Awada         }
110*57fb664cSFaisal Awada         retryProcessTwo++;
1115ace9fb7SFaisal Awada         while (retryProcessOne < MAX_RETRIES)
1125ace9fb7SFaisal Awada         {
1135ace9fb7SFaisal Awada             downloadFwFailed = false; // Download Firmware status
1145ace9fb7SFaisal Awada             retryProcessOne++;
1155ace9fb7SFaisal Awada             // Set ISP mode
1165ace9fb7SFaisal Awada             if (!writeIspMode())
1175ace9fb7SFaisal Awada             {
1185ace9fb7SFaisal Awada                 // Write ISP Mode failed MAX_RETRIES times
1195ace9fb7SFaisal Awada                 retryProcessTwo = MAX_RETRIES;
1205ace9fb7SFaisal Awada                 downloadFwFailed = true; // Download Firmware Failed
1215ace9fb7SFaisal Awada                 break;
1225ace9fb7SFaisal Awada             }
1235ace9fb7SFaisal Awada 
1245ace9fb7SFaisal Awada             // Reset ISP status
1255ace9fb7SFaisal Awada             if (writeIspStatusReset())
1265ace9fb7SFaisal Awada             {
127*57fb664cSFaisal Awada                 // Start PSU firmware download.
1285ace9fb7SFaisal Awada                 if (downloadPsuFirmware())
1295ace9fb7SFaisal Awada                 {
1305ace9fb7SFaisal Awada                     if (!verifyDownloadFWStatus())
1315ace9fb7SFaisal Awada                     {
1325ace9fb7SFaisal Awada                         downloadFwFailed = true;
1335ace9fb7SFaisal Awada                         continue;
1345ace9fb7SFaisal Awada                     }
1355ace9fb7SFaisal Awada                 }
1365ace9fb7SFaisal Awada                 else
1375ace9fb7SFaisal Awada                 {
138*57fb664cSFaisal Awada                     // One of the block write commands failed, retry download
139*57fb664cSFaisal Awada                     // procedure one time starting with re-writing initial ISP
140*57fb664cSFaisal Awada                     // mode. If it fails again, log serviceable error.
141f9b426b4SFaisal Awada                     if (retryProcessOne == MAX_RETRIES)
142f9b426b4SFaisal Awada                     {
143*57fb664cSFaisal Awada                         // Callout PSU failed to update FW
144*57fb664cSFaisal Awada                         std::map<std::string, std::string> additionalData = {
145*57fb664cSFaisal Awada                             {"UPDATE_FAILED", "Download firmware failed"}};
146*57fb664cSFaisal Awada 
147*57fb664cSFaisal Awada                         callOutPsuEventLog(additionalData);
148f9b426b4SFaisal Awada                         ispReboot(); // Try to set PSU to normal mode
149f9b426b4SFaisal Awada                     }
1505ace9fb7SFaisal Awada                     downloadFwFailed = true;
1515ace9fb7SFaisal Awada                     continue;
1525ace9fb7SFaisal Awada                 }
1535ace9fb7SFaisal Awada             }
1545ace9fb7SFaisal Awada             else
1555ace9fb7SFaisal Awada             {
1565ace9fb7SFaisal Awada                 // ISP Status Reset failed MAX_RETRIES times
1575ace9fb7SFaisal Awada                 retryProcessTwo = MAX_RETRIES;
1585ace9fb7SFaisal Awada                 downloadFwFailed = true;
1595ace9fb7SFaisal Awada                 break;
1605ace9fb7SFaisal Awada             }
1615ace9fb7SFaisal Awada 
1625ace9fb7SFaisal Awada             ispReboot();
163*57fb664cSFaisal Awada 
1645ace9fb7SFaisal Awada             if (ispReadRebootStatus() && !downloadFwFailed)
1655ace9fb7SFaisal Awada             {
1665ace9fb7SFaisal Awada                 // Download completed successful
1675ace9fb7SFaisal Awada                 retryProcessTwo = MAX_RETRIES;
1685ace9fb7SFaisal Awada                 break;
1695ace9fb7SFaisal Awada             }
1705ace9fb7SFaisal Awada             else
1715ace9fb7SFaisal Awada             {
172*57fb664cSFaisal Awada                 // Retry the whole download process starting with the key and
173*57fb664cSFaisal Awada                 // if fails again then report event log
1745ace9fb7SFaisal Awada                 if ((retryProcessOne < (MAX_RETRIES - 1)) &&
1755ace9fb7SFaisal Awada                     (retryProcessTwo < (MAX_RETRIES - 1)))
1765ace9fb7SFaisal Awada                 {
1775ace9fb7SFaisal Awada                     downloadFwFailed = false;
1785ace9fb7SFaisal Awada                     break;
1795ace9fb7SFaisal Awada                 }
1805ace9fb7SFaisal Awada             }
1815ace9fb7SFaisal Awada         }
1825ace9fb7SFaisal Awada     }
1835ace9fb7SFaisal Awada     if (downloadFwFailed)
1845a582d3cSFaisal Awada     {
1855a582d3cSFaisal Awada         return 1;
1865a582d3cSFaisal Awada     }
187*57fb664cSFaisal Awada     enableEventLogging();
188*57fb664cSFaisal Awada     bindUnbind(true);
189*57fb664cSFaisal Awada     updater::internal::delay(100);
190*57fb664cSFaisal Awada     callOutGoodEventLog();
1915ace9fb7SFaisal Awada     return 0; // Update successful
1925a582d3cSFaisal Awada }
1935a582d3cSFaisal Awada 
writeIspKey()1945a582d3cSFaisal Awada bool AeiUpdater::writeIspKey()
1955a582d3cSFaisal Awada {
1965a582d3cSFaisal Awada     // ISP Key to unlock programming mode ( ASCII for "artY").
1975a582d3cSFaisal Awada     constexpr std::array<uint8_t, 4> unlockData = {0x61, 0x72, 0x74,
1985a582d3cSFaisal Awada                                                    0x59}; // ISP Key "artY"
199*57fb664cSFaisal Awada     for (int retry = 0; retry < MAX_RETRIES; ++retry)
200*57fb664cSFaisal Awada     {
2015a582d3cSFaisal Awada         try
2025a582d3cSFaisal Awada         {
2035a582d3cSFaisal Awada             // Send ISP Key to unlock device for firmware update
204*57fb664cSFaisal Awada             i2cInterface->write(KEY_REGISTER, unlockData.size(),
205*57fb664cSFaisal Awada                                 unlockData.data());
206*57fb664cSFaisal Awada             disableEventLogging();
2075a582d3cSFaisal Awada             return true;
2085a582d3cSFaisal Awada         }
209*57fb664cSFaisal Awada         catch (const i2c::I2CException& e)
2105a582d3cSFaisal Awada         {
2115a582d3cSFaisal Awada             // Log failure if I2C write fails.
2128dca5075SFaisal Awada             lg2::error("I2C write failed: {ERROR}", "ERROR", e);
213*57fb664cSFaisal Awada             std::map<std::string, std::string> additionalData = {
214*57fb664cSFaisal Awada                 {"I2C_ISP_KEY", "ISP key failed due to I2C exception"}};
215*57fb664cSFaisal Awada             callOutI2CEventLog(additionalData, e.what(), e.errorCode);
216*57fb664cSFaisal Awada             enableEventLogging(); // enable event logging if fail again call out
217*57fb664cSFaisal Awada                                   // PSU & I2C
2185a582d3cSFaisal Awada         }
219*57fb664cSFaisal Awada 
220*57fb664cSFaisal Awada         catch (const std::exception& e)
221*57fb664cSFaisal Awada         {
222*57fb664cSFaisal Awada             lg2::error("Exception write failed: {ERROR}", "ERROR", e);
223*57fb664cSFaisal Awada             std::map<std::string, std::string> additionalData = {
224*57fb664cSFaisal Awada                 {"ISP_KEY", "ISP key failed due to exception"},
225*57fb664cSFaisal Awada                 {"EXCEPTION", e.what()}};
226*57fb664cSFaisal Awada             callOutPsuEventLog(additionalData);
227*57fb664cSFaisal Awada             enableEventLogging(); // enable Event Logging if fail again call out
228*57fb664cSFaisal Awada                                   // PSU
229*57fb664cSFaisal Awada         }
230*57fb664cSFaisal Awada     }
231*57fb664cSFaisal Awada     return false;
2325a582d3cSFaisal Awada }
2335a582d3cSFaisal Awada 
writeIspMode()2345a582d3cSFaisal Awada bool AeiUpdater::writeIspMode()
2355a582d3cSFaisal Awada {
2365a582d3cSFaisal Awada     // Attempt to set device in ISP mode with retries.
2375a582d3cSFaisal Awada     uint8_t ispStatus = 0x0;
238*57fb664cSFaisal Awada     uint8_t exceptionCount = 0;
2395a582d3cSFaisal Awada     for (int retry = 0; retry < MAX_RETRIES; ++retry)
2405a582d3cSFaisal Awada     {
2415a582d3cSFaisal Awada         try
2425a582d3cSFaisal Awada         {
2435a582d3cSFaisal Awada             // Write command to enter ISP mode.
2445a582d3cSFaisal Awada             i2cInterface->write(STATUS_REGISTER, CMD_BOOT_ISP);
2455a582d3cSFaisal Awada             // Delay to allow status register update.
2465a582d3cSFaisal Awada             updater::internal::delay(ISP_STATUS_DELAY);
2475a582d3cSFaisal Awada             // Read back status register to confirm ISP mode is active.
2485a582d3cSFaisal Awada             i2cInterface->read(STATUS_REGISTER, ispStatus);
2495a582d3cSFaisal Awada 
2505a582d3cSFaisal Awada             if (ispStatus & B_ISP_MODE)
2515a582d3cSFaisal Awada             {
2525ace9fb7SFaisal Awada                 lg2::info("Set ISP Mode");
253*57fb664cSFaisal Awada                 disableEventLogging();
2545a582d3cSFaisal Awada                 return true;
2555a582d3cSFaisal Awada             }
256*57fb664cSFaisal Awada             enableEventLogging();
257*57fb664cSFaisal Awada         }
258*57fb664cSFaisal Awada         catch (const i2c::I2CException& e)
259*57fb664cSFaisal Awada         {
260*57fb664cSFaisal Awada             exceptionCount++;
261*57fb664cSFaisal Awada             // Log I2C error with each retry attempt.
262*57fb664cSFaisal Awada             lg2::error("I2C exception during ISP mode write/read: {ERROR}",
263*57fb664cSFaisal Awada                        "ERROR", e);
264*57fb664cSFaisal Awada             if (exceptionCount == MAX_RETRIES)
265*57fb664cSFaisal Awada             {
266*57fb664cSFaisal Awada                 enableEventLogging();
267*57fb664cSFaisal Awada                 std::map<std::string, std::string> additionalData = {
268*57fb664cSFaisal Awada                     {"I2C_FIRMWARE_STATUS",
269*57fb664cSFaisal Awada                      "Download firmware failed during writeIspMode due to I2C exception"}};
270*57fb664cSFaisal Awada                 // Callout PSU & I2C
271*57fb664cSFaisal Awada                 callOutI2CEventLog(additionalData, e.what(), e.errorCode);
272*57fb664cSFaisal Awada                 return false; // Failed to set ISP Mode
273*57fb664cSFaisal Awada             }
2745a582d3cSFaisal Awada         }
2755a582d3cSFaisal Awada         catch (const std::exception& e)
2765a582d3cSFaisal Awada         {
277*57fb664cSFaisal Awada             exceptionCount++;
278*57fb664cSFaisal Awada             // Log error with each retry attempt.
279*57fb664cSFaisal Awada             lg2::error("Exception during ISP mode write/read: {ERROR}", "ERROR",
2808dca5075SFaisal Awada                        e);
281*57fb664cSFaisal Awada             if (exceptionCount == MAX_RETRIES)
282*57fb664cSFaisal Awada             {
283*57fb664cSFaisal Awada                 enableEventLogging();
284*57fb664cSFaisal Awada                 std::map<std::string, std::string> additionalData = {
285*57fb664cSFaisal Awada                     {"FIRMWARE_STATUS",
286*57fb664cSFaisal Awada                      "Download firmware failed during writeIspMode due to exception"},
287*57fb664cSFaisal Awada                     {"EXCEPTION", e.what()}};
288*57fb664cSFaisal Awada                 // Callout PSU
289*57fb664cSFaisal Awada                 callOutPsuEventLog(additionalData);
290*57fb664cSFaisal Awada                 return false; // Failed to set ISP Mode
2915a582d3cSFaisal Awada             }
2925a582d3cSFaisal Awada         }
293*57fb664cSFaisal Awada     }
294*57fb664cSFaisal Awada 
295*57fb664cSFaisal Awada     if (exceptionCount != MAX_RETRIES)
296*57fb664cSFaisal Awada     {
297*57fb664cSFaisal Awada         // Callout PSU
298*57fb664cSFaisal Awada         std::map<std::string, std::string> additionalData = {
299*57fb664cSFaisal Awada             {"FIRMWARE_STATUS",
300*57fb664cSFaisal Awada              "Download firmware failed during writeIspMode"}};
301*57fb664cSFaisal Awada         callOutPsuEventLog(additionalData);
302*57fb664cSFaisal Awada     }
303*57fb664cSFaisal Awada 
3045a582d3cSFaisal Awada     lg2::error("Failed to set ISP Mode");
3055a582d3cSFaisal Awada     return false; // Failed to set ISP Mode after retries
3065a582d3cSFaisal Awada }
3075a582d3cSFaisal Awada 
writeIspStatusReset()3085a582d3cSFaisal Awada bool AeiUpdater::writeIspStatusReset()
3095a582d3cSFaisal Awada {
3105a582d3cSFaisal Awada     // Reset ISP status register before firmware download.
3115a582d3cSFaisal Awada     uint8_t ispStatus = 0;
312*57fb664cSFaisal Awada     uint8_t exceptionCount = 0;
3135ace9fb7SFaisal Awada     for (int retry = 0; retry < MAX_RETRIES; retry++)
3145ace9fb7SFaisal Awada     {
3155a582d3cSFaisal Awada         try
3165a582d3cSFaisal Awada         {
3175a582d3cSFaisal Awada             i2cInterface->write(STATUS_REGISTER,
3185a582d3cSFaisal Awada                                 CMD_RESET_SEQ); // Start reset sequence.
3195ace9fb7SFaisal Awada             retry = MAX_RETRIES;
3205ace9fb7SFaisal Awada         }
321*57fb664cSFaisal Awada         catch (const i2c::I2CException& e)
3225ace9fb7SFaisal Awada         {
323*57fb664cSFaisal Awada             exceptionCount++;
3245ace9fb7SFaisal Awada             // Log any errors encountered during reset sequence.
3255ace9fb7SFaisal Awada             lg2::error("I2C Write ISP reset failed: {ERROR}", "ERROR", e);
326*57fb664cSFaisal Awada             if (exceptionCount == MAX_RETRIES)
327*57fb664cSFaisal Awada             {
328*57fb664cSFaisal Awada                 enableEventLogging();
329*57fb664cSFaisal Awada                 std::map<std::string, std::string> additionalData = {
330*57fb664cSFaisal Awada                     {"I2C_ISP_RESET", "I2C exception during ISP status reset"}};
331*57fb664cSFaisal Awada                 // Callout PSU & I2C
332*57fb664cSFaisal Awada                 callOutI2CEventLog(additionalData, e.what(), e.errorCode);
333*57fb664cSFaisal Awada                 ispReboot();
334*57fb664cSFaisal Awada                 return false;
335*57fb664cSFaisal Awada             }
336*57fb664cSFaisal Awada         }
337*57fb664cSFaisal Awada         catch (const std::exception& e)
338*57fb664cSFaisal Awada         {
339*57fb664cSFaisal Awada             exceptionCount++;
340*57fb664cSFaisal Awada             // Log any errors encountered during reset sequence.
341*57fb664cSFaisal Awada             lg2::error("Write ISP reset failed: {ERROR}", "ERROR", e);
342*57fb664cSFaisal Awada             if (exceptionCount == MAX_RETRIES)
343*57fb664cSFaisal Awada             {
344*57fb664cSFaisal Awada                 enableEventLogging();
345*57fb664cSFaisal Awada                 std::map<std::string, std::string> additionalData = {
346*57fb664cSFaisal Awada                     {"ISP_RESET", "Exception during ISP status reset"},
347*57fb664cSFaisal Awada                     {"EXCEPTION", e.what()}};
348*57fb664cSFaisal Awada                 // Callout PSU
349*57fb664cSFaisal Awada                 callOutPsuEventLog(additionalData);
350*57fb664cSFaisal Awada                 ispReboot();
351*57fb664cSFaisal Awada                 return false;
352*57fb664cSFaisal Awada             }
3535ace9fb7SFaisal Awada         }
3545ace9fb7SFaisal Awada     }
3555ace9fb7SFaisal Awada 
356*57fb664cSFaisal Awada     exceptionCount = 0;
3575a582d3cSFaisal Awada     for (int retry = 0; retry < MAX_RETRIES; ++retry)
3585a582d3cSFaisal Awada     {
3595ace9fb7SFaisal Awada         try
3605ace9fb7SFaisal Awada         {
3615a582d3cSFaisal Awada             i2cInterface->read(STATUS_REGISTER, ispStatus);
3625a582d3cSFaisal Awada             if (ispStatus == B_ISP_MODE)
3635a582d3cSFaisal Awada             {
364*57fb664cSFaisal Awada                 lg2::info("write/read ISP reset");
365*57fb664cSFaisal Awada                 disableEventLogging();
3665a582d3cSFaisal Awada                 return true; // ISP status reset successfully.
3675a582d3cSFaisal Awada             }
3685a582d3cSFaisal Awada             i2cInterface->write(STATUS_REGISTER,
3695a582d3cSFaisal Awada                                 CMD_CLEAR_STATUS); // Clear status if
3705a582d3cSFaisal Awada                                                    // not reset.
371*57fb664cSFaisal Awada             lg2::error("Write ISP reset failed");
372*57fb664cSFaisal Awada             enableEventLogging();
373*57fb664cSFaisal Awada         }
374*57fb664cSFaisal Awada         catch (const i2c::I2CException& e)
375*57fb664cSFaisal Awada         {
376*57fb664cSFaisal Awada             exceptionCount++;
377*57fb664cSFaisal Awada             // Log any errors encountered during reset sequence.
378*57fb664cSFaisal Awada             lg2::error(
379*57fb664cSFaisal Awada                 "I2C Write/Read or Write error during ISP reset: {ERROR}",
380*57fb664cSFaisal Awada                 "ERROR", e);
381*57fb664cSFaisal Awada             if (exceptionCount == MAX_RETRIES)
382*57fb664cSFaisal Awada             {
383*57fb664cSFaisal Awada                 enableEventLogging();
384*57fb664cSFaisal Awada                 std::map<std::string, std::string> additionalData = {
385*57fb664cSFaisal Awada                     {"I2C_ISP_READ_STATUS",
386*57fb664cSFaisal Awada                      "I2C exception during read ISP status"}};
387*57fb664cSFaisal Awada                 // Callout PSU & I2C
388*57fb664cSFaisal Awada                 callOutI2CEventLog(additionalData, e.what(), e.errorCode);
389*57fb664cSFaisal Awada             }
3905a582d3cSFaisal Awada         }
3915a582d3cSFaisal Awada         catch (const std::exception& e)
3925a582d3cSFaisal Awada         {
393*57fb664cSFaisal Awada             exceptionCount++;
3945a582d3cSFaisal Awada             // Log any errors encountered during reset sequence.
395*57fb664cSFaisal Awada             lg2::error("Write/Read or Write error during ISP reset: {ERROR}",
3965ace9fb7SFaisal Awada                        "ERROR", e);
397*57fb664cSFaisal Awada             if (exceptionCount == MAX_RETRIES)
398*57fb664cSFaisal Awada             {
399*57fb664cSFaisal Awada                 enableEventLogging();
400*57fb664cSFaisal Awada                 std::map<std::string, std::string> additionalData = {
401*57fb664cSFaisal Awada                     {"ISP_READ_STATUS", "Exception during read ISP status"},
402*57fb664cSFaisal Awada                     {"EXCEPTION", e.what()}};
403*57fb664cSFaisal Awada                 // Callout PSU
404*57fb664cSFaisal Awada                 callOutPsuEventLog(additionalData);
4055ace9fb7SFaisal Awada             }
4065a582d3cSFaisal Awada         }
407*57fb664cSFaisal Awada     }
408*57fb664cSFaisal Awada     if (exceptionCount != MAX_RETRIES)
409*57fb664cSFaisal Awada     {
410*57fb664cSFaisal Awada         std::map<std::string, std::string> additionalData = {
411*57fb664cSFaisal Awada             {"ISP_REST_FAILED", "Failed to read ISP expected status"}};
412*57fb664cSFaisal Awada         // Callout PSU
413*57fb664cSFaisal Awada         callOutPsuEventLog(additionalData);
414*57fb664cSFaisal Awada     }
4155a582d3cSFaisal Awada     lg2::error("Failed to reset ISP Status");
4165ace9fb7SFaisal Awada     ispReboot();
4175a582d3cSFaisal Awada     return false;
4185a582d3cSFaisal Awada }
4195a582d3cSFaisal Awada 
getFirmwarePath()420f9b426b4SFaisal Awada bool AeiUpdater::getFirmwarePath()
4218dca5075SFaisal Awada {
422f9b426b4SFaisal Awada     fspath = updater::internal::getFWFilenamePath(getImageDir());
4238dca5075SFaisal Awada     if (fspath.empty())
4248dca5075SFaisal Awada     {
425*57fb664cSFaisal Awada         std::map<std::string, std::string> additionalData = {
426*57fb664cSFaisal Awada             {"FILE_PATH", "Firmware file path is null"}};
427*57fb664cSFaisal Awada         // Callout BMC0001 procedure
428*57fb664cSFaisal Awada         callOutSWEventLog(additionalData);
4298dca5075SFaisal Awada         lg2::error("Firmware file path not found");
4308dca5075SFaisal Awada         return false;
4318dca5075SFaisal Awada     }
4328dca5075SFaisal Awada     return true;
4338dca5075SFaisal Awada }
4348dca5075SFaisal Awada 
isFirmwareFileValid()435f9b426b4SFaisal Awada bool AeiUpdater::isFirmwareFileValid()
436f9b426b4SFaisal Awada {
437f9b426b4SFaisal Awada     if (!updater::internal::validateFWFile(fspath))
438f9b426b4SFaisal Awada     {
439*57fb664cSFaisal Awada         std::map<std::string, std::string> additionalData = {
440*57fb664cSFaisal Awada             {"FIRMWARE_VALID",
441*57fb664cSFaisal Awada              "Firmware validation failed, FW file path = " + fspath}};
442*57fb664cSFaisal Awada         // Callout BMC0001 procedure
443*57fb664cSFaisal Awada         callOutSWEventLog(additionalData);
444f9b426b4SFaisal Awada         lg2::error("Firmware validation failed, fspath={PATH}", "PATH", fspath);
445f9b426b4SFaisal Awada         return false;
446f9b426b4SFaisal Awada     }
447f9b426b4SFaisal Awada     return true;
448f9b426b4SFaisal Awada }
449f9b426b4SFaisal Awada 
openFirmwareFile()450f9b426b4SFaisal Awada std::unique_ptr<std::ifstream> AeiUpdater::openFirmwareFile()
4518dca5075SFaisal Awada {
4528dca5075SFaisal Awada     auto inputFile = updater::internal::openFirmwareFile(fspath);
4538dca5075SFaisal Awada     if (!inputFile)
4548dca5075SFaisal Awada     {
455*57fb664cSFaisal Awada         std::map<std::string, std::string> additionalData = {
456*57fb664cSFaisal Awada             {"FIRMWARE_OPEN",
457*57fb664cSFaisal Awada              "Firmware file failed to open, FW file path = " + fspath}};
458*57fb664cSFaisal Awada         // Callout BMC0001 procedure
459*57fb664cSFaisal Awada         callOutSWEventLog(additionalData);
4608dca5075SFaisal Awada         lg2::error("Failed to open firmware file");
4618dca5075SFaisal Awada     }
4628dca5075SFaisal Awada     return inputFile;
4638dca5075SFaisal Awada }
4648dca5075SFaisal Awada 
readFirmwareBlock(std::ifstream & file,const size_t & bytesToRead)4658dca5075SFaisal Awada std::vector<uint8_t> AeiUpdater::readFirmwareBlock(std::ifstream& file,
4668dca5075SFaisal Awada                                                    const size_t& bytesToRead)
4678dca5075SFaisal Awada {
4688dca5075SFaisal Awada     auto block = updater::internal::readFirmwareBytes(file, bytesToRead);
4698dca5075SFaisal Awada     return block;
4708dca5075SFaisal Awada }
4718dca5075SFaisal Awada 
prepareCommandBlock(const std::vector<uint8_t> & dataBlockRead)4725ace9fb7SFaisal Awada void AeiUpdater::prepareCommandBlock(const std::vector<uint8_t>& dataBlockRead)
4738dca5075SFaisal Awada {
4745ace9fb7SFaisal Awada     cmdBlockWrite.clear(); // Clear cmdBlockWrite before use
4755ace9fb7SFaisal Awada     // Assign new values to cmdBlockWrite
4765ace9fb7SFaisal Awada     cmdBlockWrite.push_back(ISP_MEMORY_REGISTER);
4775ace9fb7SFaisal Awada     cmdBlockWrite.push_back(BLOCK_WRITE_SIZE);
4788dca5075SFaisal Awada     cmdBlockWrite.insert(cmdBlockWrite.end(), byteSwappedIndex.begin(),
4798dca5075SFaisal Awada                          byteSwappedIndex.end());
4808dca5075SFaisal Awada     cmdBlockWrite.insert(cmdBlockWrite.end(), dataBlockRead.begin(),
4818dca5075SFaisal Awada                          dataBlockRead.end());
4828dca5075SFaisal Awada 
4838dca5075SFaisal Awada     // Resize to ensure it matches BLOCK_WRITE_SIZE + 1 and append CRC
4848dca5075SFaisal Awada     if (cmdBlockWrite.size() != BLOCK_WRITE_SIZE + 1)
4858dca5075SFaisal Awada     {
4868dca5075SFaisal Awada         cmdBlockWrite.resize(BLOCK_WRITE_SIZE + 1, 0xFF);
4878dca5075SFaisal Awada     }
4888dca5075SFaisal Awada     cmdBlockWrite.push_back(updater::internal::calculateCRC8(cmdBlockWrite));
4898dca5075SFaisal Awada     // Remove the F9 and byte count
4908dca5075SFaisal Awada     cmdBlockWrite.erase(cmdBlockWrite.begin(), cmdBlockWrite.begin() + 2);
4915ace9fb7SFaisal Awada }
4928dca5075SFaisal Awada 
downloadPsuFirmware()4935ace9fb7SFaisal Awada bool AeiUpdater::downloadPsuFirmware()
4945ace9fb7SFaisal Awada {
4955ace9fb7SFaisal Awada     // Open firmware file
496f9b426b4SFaisal Awada     auto inputFile = openFirmwareFile();
4975ace9fb7SFaisal Awada     if (!inputFile)
4985ace9fb7SFaisal Awada     {
499*57fb664cSFaisal Awada         if (isEventLogEnabled())
500*57fb664cSFaisal Awada         {
501*57fb664cSFaisal Awada             // Callout BMC0001 procedure
502*57fb664cSFaisal Awada             std::map<std::string, std::string> additionalData = {
503*57fb664cSFaisal Awada                 {"FW_FAILED_TO_OPEN", "Firmware file failed to open"},
504*57fb664cSFaisal Awada                 {"FW_FILE_PATH", fspath}};
505*57fb664cSFaisal Awada 
506*57fb664cSFaisal Awada             callOutSWEventLog(additionalData);
507*57fb664cSFaisal Awada             ispReboot(); // Try to set PSU to normal mode
508*57fb664cSFaisal Awada         }
5095ace9fb7SFaisal Awada         lg2::error("Unable to open firmware file {FILE}", "FILE", fspath);
5105ace9fb7SFaisal Awada         return false;
5115ace9fb7SFaisal Awada     }
5125ace9fb7SFaisal Awada 
5135ace9fb7SFaisal Awada     // Read and process firmware file in blocks
5145ace9fb7SFaisal Awada     size_t bytesRead = 0;
5155ace9fb7SFaisal Awada     const auto fileSize = std::filesystem::file_size(fspath);
5165ace9fb7SFaisal Awada     bool downloadFailed = false;
5175ace9fb7SFaisal Awada     byteSwappedIndex =
5185ace9fb7SFaisal Awada         updater::internal::bigEndianToLittleEndian(START_SEQUENCE_INDEX);
5195ace9fb7SFaisal Awada     int writeBlockDelay = MEM_WRITE_DELAY;
5205ace9fb7SFaisal Awada 
5215ace9fb7SFaisal Awada     while ((bytesRead < fileSize) && !downloadFailed)
5225ace9fb7SFaisal Awada     {
5235ace9fb7SFaisal Awada         // Read a block of firmware data
5245ace9fb7SFaisal Awada         auto dataRead = readFirmwareBlock(*inputFile, FW_READ_BLOCK_SIZE);
5255ace9fb7SFaisal Awada         bytesRead += dataRead.size();
5265ace9fb7SFaisal Awada 
5275ace9fb7SFaisal Awada         // Prepare command block with the current index and data
5285ace9fb7SFaisal Awada         prepareCommandBlock(dataRead);
5295ace9fb7SFaisal Awada 
5305ace9fb7SFaisal Awada         // Perform I2C write/read with retries
5315ace9fb7SFaisal Awada         uint8_t readData[I2C_SMBUS_BLOCK_MAX] = {};
5325ace9fb7SFaisal Awada         downloadFailed = !performI2cWriteReadWithRetries(
5335ace9fb7SFaisal Awada             ISP_MEMORY_REGISTER, EXPECTED_MEM_READ_REPLY, readData, MAX_RETRIES,
5345ace9fb7SFaisal Awada             writeBlockDelay);
5355ace9fb7SFaisal Awada 
5365ace9fb7SFaisal Awada         // Adjust delay after first write block
5375ace9fb7SFaisal Awada         writeBlockDelay = MEM_STRETCH_DELAY;
5385ace9fb7SFaisal Awada     }
5395ace9fb7SFaisal Awada 
5405ace9fb7SFaisal Awada     inputFile->close();
5415ace9fb7SFaisal Awada 
5425ace9fb7SFaisal Awada     // Log final download status
5435ace9fb7SFaisal Awada     if (downloadFailed)
5445ace9fb7SFaisal Awada     {
5455ace9fb7SFaisal Awada         lg2::error(
5465ace9fb7SFaisal Awada             "Firmware download failed after retries at FW block {BYTESREAD}",
5475ace9fb7SFaisal Awada             "BYTESREAD", bytesRead);
5485ace9fb7SFaisal Awada         return false; // Failed
5495ace9fb7SFaisal Awada     }
5505ace9fb7SFaisal Awada     return true;
5515ace9fb7SFaisal Awada }
5525ace9fb7SFaisal Awada 
performI2cWriteReadWithRetries(uint8_t regAddr,const uint8_t expectedReadSize,uint8_t * readData,const int retries,const int delayTime)5535ace9fb7SFaisal Awada bool AeiUpdater::performI2cWriteReadWithRetries(
5545ace9fb7SFaisal Awada     uint8_t regAddr, const uint8_t expectedReadSize, uint8_t* readData,
5555ace9fb7SFaisal Awada     const int retries, const int delayTime)
5565ace9fb7SFaisal Awada {
557*57fb664cSFaisal Awada     uint8_t exceptionCount = 0;
558*57fb664cSFaisal Awada     uint32_t bigEndianValue = 0;
5595ace9fb7SFaisal Awada     for (int i = 0; i < retries; ++i)
5605ace9fb7SFaisal Awada     {
5615ace9fb7SFaisal Awada         uint8_t readReplySize = 0;
5625ace9fb7SFaisal Awada         try
5635ace9fb7SFaisal Awada         {
5645ace9fb7SFaisal Awada             performI2cWriteRead(regAddr, readReplySize, readData, delayTime);
565f9b426b4SFaisal Awada             if ((readData[STATUS_CML_INDEX] == 0 ||
566f9b426b4SFaisal Awada                  // The first firmware data packet sent to the PSU have a
567f9b426b4SFaisal Awada                  // response of 0x80 which indicates firmware update in
568f9b426b4SFaisal Awada                  // progress. If retry to send the first packet again reply will
569f9b426b4SFaisal Awada                  // be 0.
570f9b426b4SFaisal Awada                  (readData[STATUS_CML_INDEX] == 0x80 &&
571f9b426b4SFaisal Awada                   delayTime == MEM_WRITE_DELAY)) &&
5725ace9fb7SFaisal Awada                 (readReplySize == expectedReadSize) &&
5735ace9fb7SFaisal Awada                 !std::equal(readData, readData + 4, byteSwappedIndex.begin()))
5745ace9fb7SFaisal Awada             {
5755ace9fb7SFaisal Awada                 std::copy(readData, readData + 4, byteSwappedIndex.begin());
5765ace9fb7SFaisal Awada                 return true;
5775ace9fb7SFaisal Awada             }
5785ace9fb7SFaisal Awada             else
5795ace9fb7SFaisal Awada             {
580*57fb664cSFaisal Awada                 bigEndianValue = (readData[0] << 24) | (readData[1] << 16) |
581*57fb664cSFaisal Awada                                  (readData[2] << 8) | (readData[3]);
582f9b426b4SFaisal Awada                 lg2::error("Write/read block {NUM} failed", "NUM",
583f9b426b4SFaisal Awada                            bigEndianValue);
5845ace9fb7SFaisal Awada             }
5855ace9fb7SFaisal Awada         }
586*57fb664cSFaisal Awada         catch (const i2c::I2CException& e)
587*57fb664cSFaisal Awada         {
588*57fb664cSFaisal Awada             exceptionCount++;
589*57fb664cSFaisal Awada             if (exceptionCount == MAX_RETRIES)
590*57fb664cSFaisal Awada             {
591*57fb664cSFaisal Awada                 std::map<std::string, std::string> additionalData = {
592*57fb664cSFaisal Awada                     {"I2C_WRITE_READ",
593*57fb664cSFaisal Awada                      "I2C exception while flashing the firmware."}};
594*57fb664cSFaisal Awada                 // Callout PSU & I2C
595*57fb664cSFaisal Awada                 callOutI2CEventLog(additionalData, e.what(), e.errorCode);
596*57fb664cSFaisal Awada             }
597*57fb664cSFaisal Awada             lg2::error("I2C exception write/read block failed: {ERROR}",
598*57fb664cSFaisal Awada                        "ERROR", e.what());
599*57fb664cSFaisal Awada         }
6005ace9fb7SFaisal Awada         catch (const std::exception& e)
6015ace9fb7SFaisal Awada         {
602*57fb664cSFaisal Awada             exceptionCount++;
603*57fb664cSFaisal Awada             if (exceptionCount == MAX_RETRIES)
604*57fb664cSFaisal Awada             {
605*57fb664cSFaisal Awada                 std::map<std::string, std::string> additionalData = {
606*57fb664cSFaisal Awada                     {"WRITE_READ", "Exception while flashing the firmware."},
607*57fb664cSFaisal Awada                     {"EXCEPTION", e.what()}};
608*57fb664cSFaisal Awada                 // Callout PSU
609*57fb664cSFaisal Awada                 callOutPsuEventLog(additionalData);
610*57fb664cSFaisal Awada             }
611*57fb664cSFaisal Awada             lg2::error("Exception write/read block failed: {ERROR}", "ERROR",
612*57fb664cSFaisal Awada                        e.what());
6135ace9fb7SFaisal Awada         }
6145ace9fb7SFaisal Awada     }
615*57fb664cSFaisal Awada     std::map<std::string, std::string> additionalData = {
616*57fb664cSFaisal Awada         {"WRITE_READ",
617*57fb664cSFaisal Awada          "Download firmware failed block: " + std::to_string(bigEndianValue)}};
618*57fb664cSFaisal Awada     // Callout PSU
619*57fb664cSFaisal Awada     callOutPsuEventLog(additionalData);
6205ace9fb7SFaisal Awada     return false;
6215ace9fb7SFaisal Awada }
6225ace9fb7SFaisal Awada 
performI2cWriteRead(uint8_t regAddr,uint8_t & readReplySize,uint8_t * readData,const int & delayTime)6235ace9fb7SFaisal Awada void AeiUpdater::performI2cWriteRead(uint8_t regAddr, uint8_t& readReplySize,
6245ace9fb7SFaisal Awada                                      uint8_t* readData, const int& delayTime)
6255ace9fb7SFaisal Awada {
6265ace9fb7SFaisal Awada     i2cInterface->processCall(regAddr, cmdBlockWrite.size(),
6275ace9fb7SFaisal Awada                               cmdBlockWrite.data(), readReplySize, readData);
6285ace9fb7SFaisal Awada 
6295ace9fb7SFaisal Awada     if (delayTime != 0)
6305ace9fb7SFaisal Awada     {
6315ace9fb7SFaisal Awada         updater::internal::delay(delayTime);
6325ace9fb7SFaisal Awada     }
6335ace9fb7SFaisal Awada }
6345ace9fb7SFaisal Awada 
verifyDownloadFWStatus()6355ace9fb7SFaisal Awada bool AeiUpdater::verifyDownloadFWStatus()
6365ace9fb7SFaisal Awada {
6375ace9fb7SFaisal Awada     try
6385ace9fb7SFaisal Awada     {
6395ace9fb7SFaisal Awada         // Read and verify firmware download status.
6405ace9fb7SFaisal Awada         uint8_t status = 0;
6415ace9fb7SFaisal Awada         i2cInterface->read(STATUS_REGISTER, status);
6425ace9fb7SFaisal Awada         if (status != B_ISP_MODE_CHKSUM_GOOD)
6435ace9fb7SFaisal Awada         {
6445ace9fb7SFaisal Awada             lg2::error("Firmware download failed - status: {ERR}", "ERR",
6455ace9fb7SFaisal Awada                        status);
6465ace9fb7SFaisal Awada 
6475ace9fb7SFaisal Awada             return false; // Failed checksum
6485ace9fb7SFaisal Awada         }
6495ace9fb7SFaisal Awada         return true;
6505ace9fb7SFaisal Awada     }
6515ace9fb7SFaisal Awada     catch (const std::exception& e)
6525ace9fb7SFaisal Awada     {
6535ace9fb7SFaisal Awada         lg2::error("I2C read status register failed: {ERROR}", "ERROR", e);
6545ace9fb7SFaisal Awada     }
6555ace9fb7SFaisal Awada     return false; // Failed
6568dca5075SFaisal Awada }
6578dca5075SFaisal Awada 
ispReboot()6588dca5075SFaisal Awada void AeiUpdater::ispReboot()
6598dca5075SFaisal Awada {
6608dca5075SFaisal Awada     updater::internal::delay(
6618dca5075SFaisal Awada         MEM_COMPLETE_DELAY); // Delay before starting the reboot process
6628dca5075SFaisal Awada 
6638dca5075SFaisal Awada     try
6648dca5075SFaisal Awada     {
6658dca5075SFaisal Awada         // Write reboot command to the status register
6668dca5075SFaisal Awada         i2cInterface->write(STATUS_REGISTER, CMD_BOOT_PWR);
6678dca5075SFaisal Awada 
6688dca5075SFaisal Awada         updater::internal::delay(
6698dca5075SFaisal Awada             REBOOT_DELAY); // Add delay after writing reboot command
6708dca5075SFaisal Awada     }
6718dca5075SFaisal Awada     catch (const std::exception& e)
6728dca5075SFaisal Awada     {
6738dca5075SFaisal Awada         lg2::error("I2C write error during reboot: {ERROR}", "ERROR", e);
6748dca5075SFaisal Awada     }
6758dca5075SFaisal Awada }
6768dca5075SFaisal Awada 
ispReadRebootStatus()6778dca5075SFaisal Awada bool AeiUpdater::ispReadRebootStatus()
6788dca5075SFaisal Awada {
679*57fb664cSFaisal Awada     for (int retry = 0; retry < MAX_RETRIES; ++retry)
680*57fb664cSFaisal Awada     {
6818dca5075SFaisal Awada         try
6828dca5075SFaisal Awada         {
6838dca5075SFaisal Awada             // Read from the status register to verify reboot
6848dca5075SFaisal Awada             uint8_t data = 1; // Initialize data to a non-zero value
6858dca5075SFaisal Awada             i2cInterface->read(STATUS_REGISTER, data);
6868dca5075SFaisal Awada 
6878dca5075SFaisal Awada             // If the reboot was successful, the read data should be 0
6885ace9fb7SFaisal Awada             if (data == SUCCESSFUL_ISP_REBOOT_STATUS)
6898dca5075SFaisal Awada             {
6908dca5075SFaisal Awada                 lg2::info("ISP Status Reboot successful.");
6918dca5075SFaisal Awada                 return true;
6928dca5075SFaisal Awada             }
6938dca5075SFaisal Awada         }
694*57fb664cSFaisal Awada         catch (const i2c::I2CException& e)
695*57fb664cSFaisal Awada         {
696*57fb664cSFaisal Awada             if (isEventLogEnabled())
697*57fb664cSFaisal Awada             {
698*57fb664cSFaisal Awada                 std::map<std::string, std::string> additionalData = {
699*57fb664cSFaisal Awada                     {"I2C_READ_REBOOT",
700*57fb664cSFaisal Awada                      "I2C exception while reading ISP reboot status"}};
701*57fb664cSFaisal Awada 
702*57fb664cSFaisal Awada                 // Callout PSU & I2C
703*57fb664cSFaisal Awada                 callOutI2CEventLog(additionalData, e.what(), e.errorCode);
704*57fb664cSFaisal Awada             }
705*57fb664cSFaisal Awada             lg2::error("I2C read error during reboot attempt: {ERROR}", "ERROR",
706*57fb664cSFaisal Awada                        e);
707*57fb664cSFaisal Awada         }
7088dca5075SFaisal Awada         catch (const std::exception& e)
7098dca5075SFaisal Awada         {
710*57fb664cSFaisal Awada             if (isEventLogEnabled())
711*57fb664cSFaisal Awada             {
712*57fb664cSFaisal Awada                 std::map<std::string, std::string> additionalData = {
713*57fb664cSFaisal Awada                     {"READ_REBOOT",
714*57fb664cSFaisal Awada                      "Exception while reading ISP reboot status"},
715*57fb664cSFaisal Awada                     {"EXCEPTION", e.what()}};
716*57fb664cSFaisal Awada 
717*57fb664cSFaisal Awada                 // Callout PSU
718*57fb664cSFaisal Awada                 callOutPsuEventLog(additionalData);
719*57fb664cSFaisal Awada             }
720*57fb664cSFaisal Awada             lg2::error("Read exception during reboot attempt: {ERROR}", "ERROR",
721*57fb664cSFaisal Awada                        e);
722*57fb664cSFaisal Awada         }
723*57fb664cSFaisal Awada         // Reboot the PSU
724*57fb664cSFaisal Awada         ispReboot(); // Try to set PSU to normal mode
7258dca5075SFaisal Awada     }
7265ace9fb7SFaisal Awada 
7275ace9fb7SFaisal Awada     // If we reach here, all retries have failed
7285ace9fb7SFaisal Awada     lg2::error("Failed to reboot ISP status after max retries.");
7298dca5075SFaisal Awada     return false;
7308dca5075SFaisal Awada }
7315a582d3cSFaisal Awada } // namespace aeiUpdater
732