xref: /openbmc/phosphor-power/tools/power-utils/aei_updater.cpp (revision 57fb664c133d31a1f094441f29f30552004bb487)
1 /**
2  * Copyright © 2024 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 
17 #include "config.h"
18 
19 #include "aei_updater.hpp"
20 
21 #include "pmbus.hpp"
22 #include "types.hpp"
23 #include "updater.hpp"
24 #include "utility.hpp"
25 #include "utils.hpp"
26 
27 #include <phosphor-logging/lg2.hpp>
28 
29 #include <fstream>
30 #include <system_error>
31 
32 namespace aeiUpdater
33 {
34 
35 constexpr uint8_t MAX_RETRIES = 0x02;    // Constants for retry limits
36 
37 constexpr int ISP_STATUS_DELAY = 1200;   // Delay for ISP status check (1.2s)
38 constexpr int MEM_WRITE_DELAY = 5000;    // Memory write delay (5s)
39 constexpr int MEM_STRETCH_DELAY = 1;     // Delay between writes (1ms)
40 constexpr int MEM_COMPLETE_DELAY = 2000; // Delay before completion (2s)
41 constexpr int REBOOT_DELAY = 8000;       // Delay for reboot (8s)
42 
43 constexpr uint8_t I2C_SMBUS_BLOCK_MAX = 0x20;    // Max Read bytes from PSU
44 constexpr uint8_t FW_READ_BLOCK_SIZE = 0x20;     // Read bytes from FW file
45 constexpr uint8_t BLOCK_WRITE_SIZE = 0x25;       // I2C block write size
46 
47 constexpr uint8_t START_SEQUENCE_INDEX = 0x1;    // Starting sequence index
48 constexpr uint8_t STATUS_CML_INDEX = 0x4;        // Status CML read index
49 constexpr uint8_t EXPECTED_MEM_READ_REPLY = 0x5; //  Expected memory read reply
50                                                  //  size after write data
51 
52 // Register addresses for commands.
53 constexpr uint8_t KEY_REGISTER = 0xF6;        // Key register
54 constexpr uint8_t STATUS_REGISTER = 0xF7;     // Status register
55 constexpr uint8_t ISP_MEMORY_REGISTER = 0xF9; // ISP memory register
56 
57 // Define AEI ISP status register commands
58 constexpr uint8_t CMD_CLEAR_STATUS = 0x0; // Clear the status register
59 constexpr uint8_t CMD_RESET_SEQ = 0x01;   // This command will reset ISP OS for
60                                           // another attempt of a sequential
61                                           // programming operation.
62 constexpr uint8_t CMD_BOOT_ISP = 0x02; // Boot the In-System Programming System.
63 constexpr uint8_t CMD_BOOT_PWR = 0x03; // Attempt to boot the Power Management
64                                        // OS.
65 
66 // Define AEI ISP response status bit
67 constexpr uint8_t B_ISP_MODE = 0x40;             // ISP mode
68 constexpr uint8_t B_ISP_MODE_CHKSUM_GOOD = 0x41; // ISP mode  & good checksum.
69 constexpr uint8_t SUCCESSFUL_ISP_REBOOT_STATUS = 0x0; // Successful ISP reboot
70                                                       // status
71 using namespace phosphor::logging;
72 namespace util = phosphor::power::util;
73 
doUpdate()74 int AeiUpdater::doUpdate()
75 {
76     i2cInterface = Updater::getI2C();
77     enableEventLogging();
78     if (i2cInterface == nullptr)
79     {
80         // Report serviceable error
81         std::map<std::string, std::string> additionalData = {
82             {"I2C_INTERFACE", "I2C interface is null pointer."}};
83         // Callout PSU & I2C
84         callOutI2CEventLog(additionalData);
85 
86         throw std::runtime_error("I2C interface error");
87     }
88     if (!getFirmwarePath() || !isFirmwareFileValid())
89     {
90         return 1;                  // No firmware file abort download
91     }
92     bool downloadFwFailed = false; // Download Firmware status
93     int retryProcessTwo(0);
94     int retryProcessOne(0);
95     disableEventLogging();
96     while ((retryProcessTwo < MAX_RETRIES) && (retryProcessOne < MAX_RETRIES))
97     {
98         // Write AEI PSU ISP key
99         if (!writeIspKey())
100         {
101             lg2::error("Failed to set ISP Key");
102             downloadFwFailed = true; // Download Firmware status
103             break;
104         }
105 
106         if (retryProcessTwo == (MAX_RETRIES - 1))
107         {
108             enableEventLogging();
109         }
110         retryProcessTwo++;
111         while (retryProcessOne < MAX_RETRIES)
112         {
113             downloadFwFailed = false; // Download Firmware status
114             retryProcessOne++;
115             // Set ISP mode
116             if (!writeIspMode())
117             {
118                 // Write ISP Mode failed MAX_RETRIES times
119                 retryProcessTwo = MAX_RETRIES;
120                 downloadFwFailed = true; // Download Firmware Failed
121                 break;
122             }
123 
124             // Reset ISP status
125             if (writeIspStatusReset())
126             {
127                 // Start PSU firmware download.
128                 if (downloadPsuFirmware())
129                 {
130                     if (!verifyDownloadFWStatus())
131                     {
132                         downloadFwFailed = true;
133                         continue;
134                     }
135                 }
136                 else
137                 {
138                     // One of the block write commands failed, retry download
139                     // procedure one time starting with re-writing initial ISP
140                     // mode. If it fails again, log serviceable error.
141                     if (retryProcessOne == MAX_RETRIES)
142                     {
143                         // Callout PSU failed to update FW
144                         std::map<std::string, std::string> additionalData = {
145                             {"UPDATE_FAILED", "Download firmware failed"}};
146 
147                         callOutPsuEventLog(additionalData);
148                         ispReboot(); // Try to set PSU to normal mode
149                     }
150                     downloadFwFailed = true;
151                     continue;
152                 }
153             }
154             else
155             {
156                 // ISP Status Reset failed MAX_RETRIES times
157                 retryProcessTwo = MAX_RETRIES;
158                 downloadFwFailed = true;
159                 break;
160             }
161 
162             ispReboot();
163 
164             if (ispReadRebootStatus() && !downloadFwFailed)
165             {
166                 // Download completed successful
167                 retryProcessTwo = MAX_RETRIES;
168                 break;
169             }
170             else
171             {
172                 // Retry the whole download process starting with the key and
173                 // if fails again then report event log
174                 if ((retryProcessOne < (MAX_RETRIES - 1)) &&
175                     (retryProcessTwo < (MAX_RETRIES - 1)))
176                 {
177                     downloadFwFailed = false;
178                     break;
179                 }
180             }
181         }
182     }
183     if (downloadFwFailed)
184     {
185         return 1;
186     }
187     enableEventLogging();
188     bindUnbind(true);
189     updater::internal::delay(100);
190     callOutGoodEventLog();
191     return 0; // Update successful
192 }
193 
writeIspKey()194 bool AeiUpdater::writeIspKey()
195 {
196     // ISP Key to unlock programming mode ( ASCII for "artY").
197     constexpr std::array<uint8_t, 4> unlockData = {0x61, 0x72, 0x74,
198                                                    0x59}; // ISP Key "artY"
199     for (int retry = 0; retry < MAX_RETRIES; ++retry)
200     {
201         try
202         {
203             // Send ISP Key to unlock device for firmware update
204             i2cInterface->write(KEY_REGISTER, unlockData.size(),
205                                 unlockData.data());
206             disableEventLogging();
207             return true;
208         }
209         catch (const i2c::I2CException& e)
210         {
211             // Log failure if I2C write fails.
212             lg2::error("I2C write failed: {ERROR}", "ERROR", e);
213             std::map<std::string, std::string> additionalData = {
214                 {"I2C_ISP_KEY", "ISP key failed due to I2C exception"}};
215             callOutI2CEventLog(additionalData, e.what(), e.errorCode);
216             enableEventLogging(); // enable event logging if fail again call out
217                                   // PSU & I2C
218         }
219 
220         catch (const std::exception& e)
221         {
222             lg2::error("Exception write failed: {ERROR}", "ERROR", e);
223             std::map<std::string, std::string> additionalData = {
224                 {"ISP_KEY", "ISP key failed due to exception"},
225                 {"EXCEPTION", e.what()}};
226             callOutPsuEventLog(additionalData);
227             enableEventLogging(); // enable Event Logging if fail again call out
228                                   // PSU
229         }
230     }
231     return false;
232 }
233 
writeIspMode()234 bool AeiUpdater::writeIspMode()
235 {
236     // Attempt to set device in ISP mode with retries.
237     uint8_t ispStatus = 0x0;
238     uint8_t exceptionCount = 0;
239     for (int retry = 0; retry < MAX_RETRIES; ++retry)
240     {
241         try
242         {
243             // Write command to enter ISP mode.
244             i2cInterface->write(STATUS_REGISTER, CMD_BOOT_ISP);
245             // Delay to allow status register update.
246             updater::internal::delay(ISP_STATUS_DELAY);
247             // Read back status register to confirm ISP mode is active.
248             i2cInterface->read(STATUS_REGISTER, ispStatus);
249 
250             if (ispStatus & B_ISP_MODE)
251             {
252                 lg2::info("Set ISP Mode");
253                 disableEventLogging();
254                 return true;
255             }
256             enableEventLogging();
257         }
258         catch (const i2c::I2CException& e)
259         {
260             exceptionCount++;
261             // Log I2C error with each retry attempt.
262             lg2::error("I2C exception during ISP mode write/read: {ERROR}",
263                        "ERROR", e);
264             if (exceptionCount == MAX_RETRIES)
265             {
266                 enableEventLogging();
267                 std::map<std::string, std::string> additionalData = {
268                     {"I2C_FIRMWARE_STATUS",
269                      "Download firmware failed during writeIspMode due to I2C exception"}};
270                 // Callout PSU & I2C
271                 callOutI2CEventLog(additionalData, e.what(), e.errorCode);
272                 return false; // Failed to set ISP Mode
273             }
274         }
275         catch (const std::exception& e)
276         {
277             exceptionCount++;
278             // Log error with each retry attempt.
279             lg2::error("Exception during ISP mode write/read: {ERROR}", "ERROR",
280                        e);
281             if (exceptionCount == MAX_RETRIES)
282             {
283                 enableEventLogging();
284                 std::map<std::string, std::string> additionalData = {
285                     {"FIRMWARE_STATUS",
286                      "Download firmware failed during writeIspMode due to exception"},
287                     {"EXCEPTION", e.what()}};
288                 // Callout PSU
289                 callOutPsuEventLog(additionalData);
290                 return false; // Failed to set ISP Mode
291             }
292         }
293     }
294 
295     if (exceptionCount != MAX_RETRIES)
296     {
297         // Callout PSU
298         std::map<std::string, std::string> additionalData = {
299             {"FIRMWARE_STATUS",
300              "Download firmware failed during writeIspMode"}};
301         callOutPsuEventLog(additionalData);
302     }
303 
304     lg2::error("Failed to set ISP Mode");
305     return false; // Failed to set ISP Mode after retries
306 }
307 
writeIspStatusReset()308 bool AeiUpdater::writeIspStatusReset()
309 {
310     // Reset ISP status register before firmware download.
311     uint8_t ispStatus = 0;
312     uint8_t exceptionCount = 0;
313     for (int retry = 0; retry < MAX_RETRIES; retry++)
314     {
315         try
316         {
317             i2cInterface->write(STATUS_REGISTER,
318                                 CMD_RESET_SEQ); // Start reset sequence.
319             retry = MAX_RETRIES;
320         }
321         catch (const i2c::I2CException& e)
322         {
323             exceptionCount++;
324             // Log any errors encountered during reset sequence.
325             lg2::error("I2C Write ISP reset failed: {ERROR}", "ERROR", e);
326             if (exceptionCount == MAX_RETRIES)
327             {
328                 enableEventLogging();
329                 std::map<std::string, std::string> additionalData = {
330                     {"I2C_ISP_RESET", "I2C exception during ISP status reset"}};
331                 // Callout PSU & I2C
332                 callOutI2CEventLog(additionalData, e.what(), e.errorCode);
333                 ispReboot();
334                 return false;
335             }
336         }
337         catch (const std::exception& e)
338         {
339             exceptionCount++;
340             // Log any errors encountered during reset sequence.
341             lg2::error("Write ISP reset failed: {ERROR}", "ERROR", e);
342             if (exceptionCount == MAX_RETRIES)
343             {
344                 enableEventLogging();
345                 std::map<std::string, std::string> additionalData = {
346                     {"ISP_RESET", "Exception during ISP status reset"},
347                     {"EXCEPTION", e.what()}};
348                 // Callout PSU
349                 callOutPsuEventLog(additionalData);
350                 ispReboot();
351                 return false;
352             }
353         }
354     }
355 
356     exceptionCount = 0;
357     for (int retry = 0; retry < MAX_RETRIES; ++retry)
358     {
359         try
360         {
361             i2cInterface->read(STATUS_REGISTER, ispStatus);
362             if (ispStatus == B_ISP_MODE)
363             {
364                 lg2::info("write/read ISP reset");
365                 disableEventLogging();
366                 return true; // ISP status reset successfully.
367             }
368             i2cInterface->write(STATUS_REGISTER,
369                                 CMD_CLEAR_STATUS); // Clear status if
370                                                    // not reset.
371             lg2::error("Write ISP reset failed");
372             enableEventLogging();
373         }
374         catch (const i2c::I2CException& e)
375         {
376             exceptionCount++;
377             // Log any errors encountered during reset sequence.
378             lg2::error(
379                 "I2C Write/Read or Write error during ISP reset: {ERROR}",
380                 "ERROR", e);
381             if (exceptionCount == MAX_RETRIES)
382             {
383                 enableEventLogging();
384                 std::map<std::string, std::string> additionalData = {
385                     {"I2C_ISP_READ_STATUS",
386                      "I2C exception during read ISP status"}};
387                 // Callout PSU & I2C
388                 callOutI2CEventLog(additionalData, e.what(), e.errorCode);
389             }
390         }
391         catch (const std::exception& e)
392         {
393             exceptionCount++;
394             // Log any errors encountered during reset sequence.
395             lg2::error("Write/Read or Write error during ISP reset: {ERROR}",
396                        "ERROR", e);
397             if (exceptionCount == MAX_RETRIES)
398             {
399                 enableEventLogging();
400                 std::map<std::string, std::string> additionalData = {
401                     {"ISP_READ_STATUS", "Exception during read ISP status"},
402                     {"EXCEPTION", e.what()}};
403                 // Callout PSU
404                 callOutPsuEventLog(additionalData);
405             }
406         }
407     }
408     if (exceptionCount != MAX_RETRIES)
409     {
410         std::map<std::string, std::string> additionalData = {
411             {"ISP_REST_FAILED", "Failed to read ISP expected status"}};
412         // Callout PSU
413         callOutPsuEventLog(additionalData);
414     }
415     lg2::error("Failed to reset ISP Status");
416     ispReboot();
417     return false;
418 }
419 
getFirmwarePath()420 bool AeiUpdater::getFirmwarePath()
421 {
422     fspath = updater::internal::getFWFilenamePath(getImageDir());
423     if (fspath.empty())
424     {
425         std::map<std::string, std::string> additionalData = {
426             {"FILE_PATH", "Firmware file path is null"}};
427         // Callout BMC0001 procedure
428         callOutSWEventLog(additionalData);
429         lg2::error("Firmware file path not found");
430         return false;
431     }
432     return true;
433 }
434 
isFirmwareFileValid()435 bool AeiUpdater::isFirmwareFileValid()
436 {
437     if (!updater::internal::validateFWFile(fspath))
438     {
439         std::map<std::string, std::string> additionalData = {
440             {"FIRMWARE_VALID",
441              "Firmware validation failed, FW file path = " + fspath}};
442         // Callout BMC0001 procedure
443         callOutSWEventLog(additionalData);
444         lg2::error("Firmware validation failed, fspath={PATH}", "PATH", fspath);
445         return false;
446     }
447     return true;
448 }
449 
openFirmwareFile()450 std::unique_ptr<std::ifstream> AeiUpdater::openFirmwareFile()
451 {
452     auto inputFile = updater::internal::openFirmwareFile(fspath);
453     if (!inputFile)
454     {
455         std::map<std::string, std::string> additionalData = {
456             {"FIRMWARE_OPEN",
457              "Firmware file failed to open, FW file path = " + fspath}};
458         // Callout BMC0001 procedure
459         callOutSWEventLog(additionalData);
460         lg2::error("Failed to open firmware file");
461     }
462     return inputFile;
463 }
464 
readFirmwareBlock(std::ifstream & file,const size_t & bytesToRead)465 std::vector<uint8_t> AeiUpdater::readFirmwareBlock(std::ifstream& file,
466                                                    const size_t& bytesToRead)
467 {
468     auto block = updater::internal::readFirmwareBytes(file, bytesToRead);
469     return block;
470 }
471 
prepareCommandBlock(const std::vector<uint8_t> & dataBlockRead)472 void AeiUpdater::prepareCommandBlock(const std::vector<uint8_t>& dataBlockRead)
473 {
474     cmdBlockWrite.clear(); // Clear cmdBlockWrite before use
475     // Assign new values to cmdBlockWrite
476     cmdBlockWrite.push_back(ISP_MEMORY_REGISTER);
477     cmdBlockWrite.push_back(BLOCK_WRITE_SIZE);
478     cmdBlockWrite.insert(cmdBlockWrite.end(), byteSwappedIndex.begin(),
479                          byteSwappedIndex.end());
480     cmdBlockWrite.insert(cmdBlockWrite.end(), dataBlockRead.begin(),
481                          dataBlockRead.end());
482 
483     // Resize to ensure it matches BLOCK_WRITE_SIZE + 1 and append CRC
484     if (cmdBlockWrite.size() != BLOCK_WRITE_SIZE + 1)
485     {
486         cmdBlockWrite.resize(BLOCK_WRITE_SIZE + 1, 0xFF);
487     }
488     cmdBlockWrite.push_back(updater::internal::calculateCRC8(cmdBlockWrite));
489     // Remove the F9 and byte count
490     cmdBlockWrite.erase(cmdBlockWrite.begin(), cmdBlockWrite.begin() + 2);
491 }
492 
downloadPsuFirmware()493 bool AeiUpdater::downloadPsuFirmware()
494 {
495     // Open firmware file
496     auto inputFile = openFirmwareFile();
497     if (!inputFile)
498     {
499         if (isEventLogEnabled())
500         {
501             // Callout BMC0001 procedure
502             std::map<std::string, std::string> additionalData = {
503                 {"FW_FAILED_TO_OPEN", "Firmware file failed to open"},
504                 {"FW_FILE_PATH", fspath}};
505 
506             callOutSWEventLog(additionalData);
507             ispReboot(); // Try to set PSU to normal mode
508         }
509         lg2::error("Unable to open firmware file {FILE}", "FILE", fspath);
510         return false;
511     }
512 
513     // Read and process firmware file in blocks
514     size_t bytesRead = 0;
515     const auto fileSize = std::filesystem::file_size(fspath);
516     bool downloadFailed = false;
517     byteSwappedIndex =
518         updater::internal::bigEndianToLittleEndian(START_SEQUENCE_INDEX);
519     int writeBlockDelay = MEM_WRITE_DELAY;
520 
521     while ((bytesRead < fileSize) && !downloadFailed)
522     {
523         // Read a block of firmware data
524         auto dataRead = readFirmwareBlock(*inputFile, FW_READ_BLOCK_SIZE);
525         bytesRead += dataRead.size();
526 
527         // Prepare command block with the current index and data
528         prepareCommandBlock(dataRead);
529 
530         // Perform I2C write/read with retries
531         uint8_t readData[I2C_SMBUS_BLOCK_MAX] = {};
532         downloadFailed = !performI2cWriteReadWithRetries(
533             ISP_MEMORY_REGISTER, EXPECTED_MEM_READ_REPLY, readData, MAX_RETRIES,
534             writeBlockDelay);
535 
536         // Adjust delay after first write block
537         writeBlockDelay = MEM_STRETCH_DELAY;
538     }
539 
540     inputFile->close();
541 
542     // Log final download status
543     if (downloadFailed)
544     {
545         lg2::error(
546             "Firmware download failed after retries at FW block {BYTESREAD}",
547             "BYTESREAD", bytesRead);
548         return false; // Failed
549     }
550     return true;
551 }
552 
performI2cWriteReadWithRetries(uint8_t regAddr,const uint8_t expectedReadSize,uint8_t * readData,const int retries,const int delayTime)553 bool AeiUpdater::performI2cWriteReadWithRetries(
554     uint8_t regAddr, const uint8_t expectedReadSize, uint8_t* readData,
555     const int retries, const int delayTime)
556 {
557     uint8_t exceptionCount = 0;
558     uint32_t bigEndianValue = 0;
559     for (int i = 0; i < retries; ++i)
560     {
561         uint8_t readReplySize = 0;
562         try
563         {
564             performI2cWriteRead(regAddr, readReplySize, readData, delayTime);
565             if ((readData[STATUS_CML_INDEX] == 0 ||
566                  // The first firmware data packet sent to the PSU have a
567                  // response of 0x80 which indicates firmware update in
568                  // progress. If retry to send the first packet again reply will
569                  // be 0.
570                  (readData[STATUS_CML_INDEX] == 0x80 &&
571                   delayTime == MEM_WRITE_DELAY)) &&
572                 (readReplySize == expectedReadSize) &&
573                 !std::equal(readData, readData + 4, byteSwappedIndex.begin()))
574             {
575                 std::copy(readData, readData + 4, byteSwappedIndex.begin());
576                 return true;
577             }
578             else
579             {
580                 bigEndianValue = (readData[0] << 24) | (readData[1] << 16) |
581                                  (readData[2] << 8) | (readData[3]);
582                 lg2::error("Write/read block {NUM} failed", "NUM",
583                            bigEndianValue);
584             }
585         }
586         catch (const i2c::I2CException& e)
587         {
588             exceptionCount++;
589             if (exceptionCount == MAX_RETRIES)
590             {
591                 std::map<std::string, std::string> additionalData = {
592                     {"I2C_WRITE_READ",
593                      "I2C exception while flashing the firmware."}};
594                 // Callout PSU & I2C
595                 callOutI2CEventLog(additionalData, e.what(), e.errorCode);
596             }
597             lg2::error("I2C exception write/read block failed: {ERROR}",
598                        "ERROR", e.what());
599         }
600         catch (const std::exception& e)
601         {
602             exceptionCount++;
603             if (exceptionCount == MAX_RETRIES)
604             {
605                 std::map<std::string, std::string> additionalData = {
606                     {"WRITE_READ", "Exception while flashing the firmware."},
607                     {"EXCEPTION", e.what()}};
608                 // Callout PSU
609                 callOutPsuEventLog(additionalData);
610             }
611             lg2::error("Exception write/read block failed: {ERROR}", "ERROR",
612                        e.what());
613         }
614     }
615     std::map<std::string, std::string> additionalData = {
616         {"WRITE_READ",
617          "Download firmware failed block: " + std::to_string(bigEndianValue)}};
618     // Callout PSU
619     callOutPsuEventLog(additionalData);
620     return false;
621 }
622 
performI2cWriteRead(uint8_t regAddr,uint8_t & readReplySize,uint8_t * readData,const int & delayTime)623 void AeiUpdater::performI2cWriteRead(uint8_t regAddr, uint8_t& readReplySize,
624                                      uint8_t* readData, const int& delayTime)
625 {
626     i2cInterface->processCall(regAddr, cmdBlockWrite.size(),
627                               cmdBlockWrite.data(), readReplySize, readData);
628 
629     if (delayTime != 0)
630     {
631         updater::internal::delay(delayTime);
632     }
633 }
634 
verifyDownloadFWStatus()635 bool AeiUpdater::verifyDownloadFWStatus()
636 {
637     try
638     {
639         // Read and verify firmware download status.
640         uint8_t status = 0;
641         i2cInterface->read(STATUS_REGISTER, status);
642         if (status != B_ISP_MODE_CHKSUM_GOOD)
643         {
644             lg2::error("Firmware download failed - status: {ERR}", "ERR",
645                        status);
646 
647             return false; // Failed checksum
648         }
649         return true;
650     }
651     catch (const std::exception& e)
652     {
653         lg2::error("I2C read status register failed: {ERROR}", "ERROR", e);
654     }
655     return false; // Failed
656 }
657 
ispReboot()658 void AeiUpdater::ispReboot()
659 {
660     updater::internal::delay(
661         MEM_COMPLETE_DELAY); // Delay before starting the reboot process
662 
663     try
664     {
665         // Write reboot command to the status register
666         i2cInterface->write(STATUS_REGISTER, CMD_BOOT_PWR);
667 
668         updater::internal::delay(
669             REBOOT_DELAY); // Add delay after writing reboot command
670     }
671     catch (const std::exception& e)
672     {
673         lg2::error("I2C write error during reboot: {ERROR}", "ERROR", e);
674     }
675 }
676 
ispReadRebootStatus()677 bool AeiUpdater::ispReadRebootStatus()
678 {
679     for (int retry = 0; retry < MAX_RETRIES; ++retry)
680     {
681         try
682         {
683             // Read from the status register to verify reboot
684             uint8_t data = 1; // Initialize data to a non-zero value
685             i2cInterface->read(STATUS_REGISTER, data);
686 
687             // If the reboot was successful, the read data should be 0
688             if (data == SUCCESSFUL_ISP_REBOOT_STATUS)
689             {
690                 lg2::info("ISP Status Reboot successful.");
691                 return true;
692             }
693         }
694         catch (const i2c::I2CException& e)
695         {
696             if (isEventLogEnabled())
697             {
698                 std::map<std::string, std::string> additionalData = {
699                     {"I2C_READ_REBOOT",
700                      "I2C exception while reading ISP reboot status"}};
701 
702                 // Callout PSU & I2C
703                 callOutI2CEventLog(additionalData, e.what(), e.errorCode);
704             }
705             lg2::error("I2C read error during reboot attempt: {ERROR}", "ERROR",
706                        e);
707         }
708         catch (const std::exception& e)
709         {
710             if (isEventLogEnabled())
711             {
712                 std::map<std::string, std::string> additionalData = {
713                     {"READ_REBOOT",
714                      "Exception while reading ISP reboot status"},
715                     {"EXCEPTION", e.what()}};
716 
717                 // Callout PSU
718                 callOutPsuEventLog(additionalData);
719             }
720             lg2::error("Read exception during reboot attempt: {ERROR}", "ERROR",
721                        e);
722         }
723         // Reboot the PSU
724         ispReboot(); // Try to set PSU to normal mode
725     }
726 
727     // If we reach here, all retries have failed
728     lg2::error("Failed to reboot ISP status after max retries.");
729     return false;
730 }
731 } // namespace aeiUpdater
732