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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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