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