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