blob: 4b1865b178060953e9e89b28bde280d1563ac666 [file] [log] [blame]
Faisal Awada5a582d32024-11-15 14:11:44 -06001/**
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"
Faisal Awada57fb6642025-02-21 16:52:54 -060025#include "utils.hpp"
Faisal Awada5a582d32024-11-15 14:11:44 -060026
27#include <phosphor-logging/lg2.hpp>
28
Faisal Awada8dca5072024-11-23 08:07:38 -060029#include <fstream>
Faisal Awada57fb6642025-02-21 16:52:54 -060030#include <system_error>
Faisal Awada8dca5072024-11-23 08:07:38 -060031
Faisal Awada5a582d32024-11-15 14:11:44 -060032namespace aeiUpdater
33{
Jayanth Othayothf0c0c472024-12-07 02:47:10 -060034
Faisal Awada5a582d32024-11-15 14:11:44 -060035constexpr uint8_t MAX_RETRIES = 0x02; // Constants for retry limits
36
37constexpr int ISP_STATUS_DELAY = 1200; // Delay for ISP status check (1.2s)
38constexpr int MEM_WRITE_DELAY = 5000; // Memory write delay (5s)
Faisal Awada5ace9fb2025-01-07 13:26:25 -060039constexpr int MEM_STRETCH_DELAY = 1; // Delay between writes (1ms)
Faisal Awada5a582d32024-11-15 14:11:44 -060040constexpr int MEM_COMPLETE_DELAY = 2000; // Delay before completion (2s)
41constexpr int REBOOT_DELAY = 8000; // Delay for reboot (8s)
42
Faisal Awada5ace9fb2025-01-07 13:26:25 -060043constexpr uint8_t I2C_SMBUS_BLOCK_MAX = 0x20; // Max Read bytes from PSU
44constexpr uint8_t FW_READ_BLOCK_SIZE = 0x20; // Read bytes from FW file
45constexpr uint8_t BLOCK_WRITE_SIZE = 0x25; // I2C block write size
46
47constexpr uint8_t START_SEQUENCE_INDEX = 0x1; // Starting sequence index
48constexpr uint8_t STATUS_CML_INDEX = 0x4; // Status CML read index
49constexpr uint8_t EXPECTED_MEM_READ_REPLY = 0x5; // Expected memory read reply
50 // size after write data
Faisal Awada5a582d32024-11-15 14:11:44 -060051
52// Register addresses for commands.
53constexpr uint8_t KEY_REGISTER = 0xF6; // Key register
54constexpr uint8_t STATUS_REGISTER = 0xF7; // Status register
55constexpr uint8_t ISP_MEMORY_REGISTER = 0xF9; // ISP memory register
56
57// Define AEI ISP status register commands
58constexpr uint8_t CMD_CLEAR_STATUS = 0x0; // Clear the status register
59constexpr uint8_t CMD_RESET_SEQ = 0x01; // This command will reset ISP OS for
60 // another attempt of a sequential
61 // programming operation.
62constexpr uint8_t CMD_BOOT_ISP = 0x02; // Boot the In-System Programming System.
63constexpr uint8_t CMD_BOOT_PWR = 0x03; // Attempt to boot the Power Management
64 // OS.
65
66// Define AEI ISP response status bit
Faisal Awada5ace9fb2025-01-07 13:26:25 -060067constexpr uint8_t B_ISP_MODE = 0x40; // ISP mode
Faisal Awada5a582d32024-11-15 14:11:44 -060068constexpr uint8_t B_ISP_MODE_CHKSUM_GOOD = 0x41; // ISP mode & good checksum.
Faisal Awada8dca5072024-11-23 08:07:38 -060069constexpr uint8_t SUCCESSFUL_ISP_REBOOT_STATUS = 0x0; // Successful ISP reboot
70 // status
Faisal Awada5a582d32024-11-15 14:11:44 -060071namespace util = phosphor::power::util;
72
73int AeiUpdater::doUpdate()
74{
75 i2cInterface = Updater::getI2C();
Faisal Awada57fb6642025-02-21 16:52:54 -060076 enableEventLogging();
Faisal Awada5a582d32024-11-15 14:11:44 -060077 if (i2cInterface == nullptr)
78 {
Faisal Awada57fb6642025-02-21 16:52:54 -060079 // 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
Faisal Awada5a582d32024-11-15 14:11:44 -060085 throw std::runtime_error("I2C interface error");
86 }
Faisal Awadaf9b426b2025-01-31 11:44:48 -060087 if (!getFirmwarePath() || !isFirmwareFileValid())
88 {
89 return 1; // No firmware file abort download
90 }
Faisal Awada5ace9fb2025-01-07 13:26:25 -060091 bool downloadFwFailed = false; // Download Firmware status
92 int retryProcessTwo(0);
93 int retryProcessOne(0);
Faisal Awada57fb6642025-02-21 16:52:54 -060094 disableEventLogging();
Faisal Awada5ace9fb2025-01-07 13:26:25 -060095 while ((retryProcessTwo < MAX_RETRIES) && (retryProcessOne < MAX_RETRIES))
Faisal Awada5a582d32024-11-15 14:11:44 -060096 {
Faisal Awada5ace9fb2025-01-07 13:26:25 -060097 // Write AEI PSU ISP key
98 if (!writeIspKey())
99 {
100 lg2::error("Failed to set ISP Key");
101 downloadFwFailed = true; // Download Firmware status
Faisal Awada57fb6642025-02-21 16:52:54 -0600102 break;
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600103 }
Faisal Awada5a582d32024-11-15 14:11:44 -0600104
Faisal Awada57fb6642025-02-21 16:52:54 -0600105 if (retryProcessTwo == (MAX_RETRIES - 1))
106 {
107 enableEventLogging();
108 }
109 retryProcessTwo++;
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600110 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 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600126 // Start PSU firmware download.
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600127 if (downloadPsuFirmware())
128 {
129 if (!verifyDownloadFWStatus())
130 {
131 downloadFwFailed = true;
132 continue;
133 }
134 }
135 else
136 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600137 // 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.
Faisal Awadaf9b426b2025-01-31 11:44:48 -0600140 if (retryProcessOne == MAX_RETRIES)
141 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600142 // Callout PSU failed to update FW
143 std::map<std::string, std::string> additionalData = {
144 {"UPDATE_FAILED", "Download firmware failed"}};
145
146 callOutPsuEventLog(additionalData);
Faisal Awadaf9b426b2025-01-31 11:44:48 -0600147 ispReboot(); // Try to set PSU to normal mode
148 }
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600149 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();
Faisal Awada57fb6642025-02-21 16:52:54 -0600162
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600163 if (ispReadRebootStatus() && !downloadFwFailed)
164 {
165 // Download completed successful
166 retryProcessTwo = MAX_RETRIES;
167 break;
168 }
169 else
170 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600171 // Retry the whole download process starting with the key and
172 // if fails again then report event log
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600173 if ((retryProcessOne < (MAX_RETRIES - 1)) &&
174 (retryProcessTwo < (MAX_RETRIES - 1)))
175 {
176 downloadFwFailed = false;
177 break;
178 }
179 }
180 }
181 }
182 if (downloadFwFailed)
Faisal Awada5a582d32024-11-15 14:11:44 -0600183 {
184 return 1;
185 }
Faisal Awada57fb6642025-02-21 16:52:54 -0600186 enableEventLogging();
187 bindUnbind(true);
188 updater::internal::delay(100);
189 callOutGoodEventLog();
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600190 return 0; // Update successful
Faisal Awada5a582d32024-11-15 14:11:44 -0600191}
192
193bool 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"
Faisal Awada57fb6642025-02-21 16:52:54 -0600198 for (int retry = 0; retry < MAX_RETRIES; ++retry)
Faisal Awada5a582d32024-11-15 14:11:44 -0600199 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600200 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 }
Faisal Awada5a582d32024-11-15 14:11:44 -0600229 }
Faisal Awada57fb6642025-02-21 16:52:54 -0600230 return false;
Faisal Awada5a582d32024-11-15 14:11:44 -0600231}
232
233bool AeiUpdater::writeIspMode()
234{
235 // Attempt to set device in ISP mode with retries.
236 uint8_t ispStatus = 0x0;
Faisal Awada57fb6642025-02-21 16:52:54 -0600237 uint8_t exceptionCount = 0;
Faisal Awada5a582d32024-11-15 14:11:44 -0600238 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 {
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600251 lg2::info("Set ISP Mode");
Faisal Awada57fb6642025-02-21 16:52:54 -0600252 disableEventLogging();
Faisal Awada5a582d32024-11-15 14:11:44 -0600253 return true;
254 }
Faisal Awada57fb6642025-02-21 16:52:54 -0600255 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 }
Faisal Awada5a582d32024-11-15 14:11:44 -0600273 }
274 catch (const std::exception& e)
275 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600276 exceptionCount++;
277 // Log error with each retry attempt.
278 lg2::error("Exception during ISP mode write/read: {ERROR}", "ERROR",
Faisal Awada8dca5072024-11-23 08:07:38 -0600279 e);
Faisal Awada57fb6642025-02-21 16:52:54 -0600280 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 }
Faisal Awada5a582d32024-11-15 14:11:44 -0600291 }
292 }
Faisal Awada57fb6642025-02-21 16:52:54 -0600293
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
Faisal Awada5a582d32024-11-15 14:11:44 -0600303 lg2::error("Failed to set ISP Mode");
304 return false; // Failed to set ISP Mode after retries
305}
306
307bool AeiUpdater::writeIspStatusReset()
308{
309 // Reset ISP status register before firmware download.
310 uint8_t ispStatus = 0;
Faisal Awada57fb6642025-02-21 16:52:54 -0600311 uint8_t exceptionCount = 0;
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600312 for (int retry = 0; retry < MAX_RETRIES; retry++)
Faisal Awada5a582d32024-11-15 14:11:44 -0600313 {
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600314 try
315 {
316 i2cInterface->write(STATUS_REGISTER,
317 CMD_RESET_SEQ); // Start reset sequence.
318 retry = MAX_RETRIES;
319 }
Faisal Awada57fb6642025-02-21 16:52:54 -0600320 catch (const i2c::I2CException& e)
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600321 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600322 exceptionCount++;
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600323 // Log any errors encountered during reset sequence.
324 lg2::error("I2C Write ISP reset failed: {ERROR}", "ERROR", e);
Faisal Awada57fb6642025-02-21 16:52:54 -0600325 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 }
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600352 }
353 }
354
Faisal Awada57fb6642025-02-21 16:52:54 -0600355 exceptionCount = 0;
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600356 for (int retry = 0; retry < MAX_RETRIES; ++retry)
357 {
358 try
Faisal Awada5a582d32024-11-15 14:11:44 -0600359 {
360 i2cInterface->read(STATUS_REGISTER, ispStatus);
361 if (ispStatus == B_ISP_MODE)
362 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600363 lg2::info("write/read ISP reset");
364 disableEventLogging();
Faisal Awada5a582d32024-11-15 14:11:44 -0600365 return true; // ISP status reset successfully.
366 }
367 i2cInterface->write(STATUS_REGISTER,
368 CMD_CLEAR_STATUS); // Clear status if
369 // not reset.
Faisal Awada57fb6642025-02-21 16:52:54 -0600370 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 }
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600389 }
390 catch (const std::exception& e)
391 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600392 exceptionCount++;
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600393 // Log any errors encountered during reset sequence.
Faisal Awada57fb6642025-02-21 16:52:54 -0600394 lg2::error("Write/Read or Write error during ISP reset: {ERROR}",
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600395 "ERROR", e);
Faisal Awada57fb6642025-02-21 16:52:54 -0600396 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 }
Faisal Awada5a582d32024-11-15 14:11:44 -0600405 }
406 }
Faisal Awada57fb6642025-02-21 16:52:54 -0600407 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 }
Faisal Awada5a582d32024-11-15 14:11:44 -0600414 lg2::error("Failed to reset ISP Status");
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600415 ispReboot();
Faisal Awada5a582d32024-11-15 14:11:44 -0600416 return false;
417}
418
Faisal Awadaf9b426b2025-01-31 11:44:48 -0600419bool AeiUpdater::getFirmwarePath()
Faisal Awada8dca5072024-11-23 08:07:38 -0600420{
Faisal Awadaf9b426b2025-01-31 11:44:48 -0600421 fspath = updater::internal::getFWFilenamePath(getImageDir());
Faisal Awada8dca5072024-11-23 08:07:38 -0600422 if (fspath.empty())
423 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600424 std::map<std::string, std::string> additionalData = {
425 {"FILE_PATH", "Firmware file path is null"}};
426 // Callout BMC0001 procedure
427 callOutSWEventLog(additionalData);
Faisal Awada8dca5072024-11-23 08:07:38 -0600428 lg2::error("Firmware file path not found");
Faisal Awada8dca5072024-11-23 08:07:38 -0600429 return false;
430 }
431 return true;
432}
433
Faisal Awadaf9b426b2025-01-31 11:44:48 -0600434bool AeiUpdater::isFirmwareFileValid()
435{
436 if (!updater::internal::validateFWFile(fspath))
437 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600438 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);
Faisal Awadaf9b426b2025-01-31 11:44:48 -0600443 lg2::error("Firmware validation failed, fspath={PATH}", "PATH", fspath);
444 return false;
445 }
446 return true;
447}
448
449std::unique_ptr<std::ifstream> AeiUpdater::openFirmwareFile()
Faisal Awada8dca5072024-11-23 08:07:38 -0600450{
451 auto inputFile = updater::internal::openFirmwareFile(fspath);
452 if (!inputFile)
453 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600454 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);
Faisal Awada8dca5072024-11-23 08:07:38 -0600459 lg2::error("Failed to open firmware file");
460 }
461 return inputFile;
462}
463
464std::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
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600471void AeiUpdater::prepareCommandBlock(const std::vector<uint8_t>& dataBlockRead)
Faisal Awada8dca5072024-11-23 08:07:38 -0600472{
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600473 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);
Faisal Awada8dca5072024-11-23 08:07:38 -0600477 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);
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600490}
Faisal Awada8dca5072024-11-23 08:07:38 -0600491
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600492bool AeiUpdater::downloadPsuFirmware()
493{
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600494 // Open firmware file
Faisal Awadaf9b426b2025-01-31 11:44:48 -0600495 auto inputFile = openFirmwareFile();
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600496 if (!inputFile)
497 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600498 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 }
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600508 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 }
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600549 return true;
550}
551
552bool AeiUpdater::performI2cWriteReadWithRetries(
553 uint8_t regAddr, const uint8_t expectedReadSize, uint8_t* readData,
554 const int retries, const int delayTime)
555{
Faisal Awada57fb6642025-02-21 16:52:54 -0600556 uint8_t exceptionCount = 0;
557 uint32_t bigEndianValue = 0;
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600558 for (int i = 0; i < retries; ++i)
559 {
560 uint8_t readReplySize = 0;
561 try
562 {
563 performI2cWriteRead(regAddr, readReplySize, readData, delayTime);
Faisal Awadaf9b426b2025-01-31 11:44:48 -0600564 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)) &&
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600571 (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 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600579 bigEndianValue = (readData[0] << 24) | (readData[1] << 16) |
580 (readData[2] << 8) | (readData[3]);
Faisal Awadaf9b426b2025-01-31 11:44:48 -0600581 lg2::error("Write/read block {NUM} failed", "NUM",
582 bigEndianValue);
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600583 }
584 }
Faisal Awada57fb6642025-02-21 16:52:54 -0600585 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 }
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600599 catch (const std::exception& e)
600 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600601 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());
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600612 }
613 }
Faisal Awada57fb6642025-02-21 16:52:54 -0600614 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);
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600619 return false;
620}
621
622void 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
634bool 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
Faisal Awada8dca5072024-11-23 08:07:38 -0600655}
656
657void 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
676bool AeiUpdater::ispReadRebootStatus()
677{
Faisal Awada57fb6642025-02-21 16:52:54 -0600678 for (int retry = 0; retry < MAX_RETRIES; ++retry)
Faisal Awada8dca5072024-11-23 08:07:38 -0600679 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600680 try
Faisal Awada8dca5072024-11-23 08:07:38 -0600681 {
Faisal Awada57fb6642025-02-21 16:52:54 -0600682 // 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 }
Faisal Awada8dca5072024-11-23 08:07:38 -0600692 }
Faisal Awada57fb6642025-02-21 16:52:54 -0600693 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
Faisal Awada8dca5072024-11-23 08:07:38 -0600724 }
Faisal Awada5ace9fb2025-01-07 13:26:25 -0600725
726 // If we reach here, all retries have failed
727 lg2::error("Failed to reboot ISP status after max retries.");
Faisal Awada8dca5072024-11-23 08:07:38 -0600728 return false;
729}
Faisal Awada5a582d32024-11-15 14:11:44 -0600730} // namespace aeiUpdater