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