/// <summary> /// Delegate that executes the firmware update. /// </summary> /// <param name="stateInfo"> /// FirmwareUpdateInfo object passed as generic object to WaitCallback method. /// </param> private void ExecuteFirmwareUpdate(Object stateInfo) { FirmwareUpdateInfo fwUpdateInfo = (FirmwareUpdateInfo)stateInfo; bool enteredFwUpgradeMode = false; CompletionCode result = CompletionCode.Success; int psuI2CPacketHandleTimeMs = fwUpdateInfo.primaryImage ? psuPriI2CPacketHandleTimeMs : psuSecI2CPacketHandleTimeMs; // Update flag to signal that PSU FW update is in progress so that: // 1. PSU is not falsely signaled as faulty by PSU monitoring code // 2. Other code do not try and access PSU as this can cause FW update failures ChassisState.PsuFwUpdateInProgress[this.PsuId - 1] = true; lock (ChassisState.psuLock[this.PsuId - 1]) { try { fwUpdateStatus = FwUpdateStatusEnum.InProgress; // Read file into memory. The image file is only a few hundred kilobytes so it won't consume much memory. fwUpdateStage = FwUpdateStageEnum.ReadFirmwareImageFile; string[] fwImage = File.ReadAllLines(fwUpdateInfo.fwFilepath); // Remove leading ':' for (int i = 0; i < fwImage.Length; i++) { fwImage[i] = fwImage[i].Remove(0, 1); } // Extract model ID from the firmware image; fwUpdateStage = FwUpdateStageEnum.ExtractModelId; byte[] modelId = ExtractModelId(fwImage, fwUpdateInfo.primaryImage); if (modelId == null) { result = CompletionCode.UnspecifiedError; } // Enter Programming Mode // PSU will verify password, turn off power output and switch to bootloader mode if (result == CompletionCode.Success) { fwUpdateStage = FwUpdateStageEnum.EnterFirmwareUpgradeMode; result = EnterFirmwareUpgradeMode(fwUpdateInfo.primaryImage); } // Model ID Validation // Send model ID to PSU. // PSU will verify model ID and erase current firmware image if (result == CompletionCode.Success) { // Wait for PSU to turn off output and enter programming mode Thread.Sleep(psuEnterProgrammingModeTimeMs); enteredFwUpgradeMode = true; fwUpdateStage = FwUpdateStageEnum.SendModelId; result = SendModelId(modelId); } // Check status for Model ID verification if (result == CompletionCode.Success) { // Wait for PSU to erase program memory Thread.Sleep(psuProgramEraseTimeMs); FirmwareUpdateStatusPacket response = GetFirmwareUpdateStatus(); if (response.CompletionCode != CompletionCode.Success) { result = CompletionCode.UnspecifiedError; Tracer.WriteWarning("ExecuteFirmwareUpdate(): GetFirmwareUpdateStatus Failure after sending model ID: Completion Code: {0}", response.CompletionCode); } else { if (response.UpdateStatus != PsuFwUpdateStatus.FlashEraseOK) { result = CompletionCode.UnspecifiedError; Tracer.WriteWarning("ExecuteFirmwareUpdate(): Model ID verification failed with status: {0}", response.UpdateStatus.ToString()); } } } // Write new firmware image to PSU if (result == CompletionCode.Success) { // Wait for PSU I2C Packet Handling Time Thread.Sleep(psuI2CPacketHandleTimeMs); fwUpdateStage = FwUpdateStageEnum.WriteFirmwareImage; result = WriteFirmwareImage(fwImage, fwUpdateInfo.primaryImage); } // Read back firmware image and verify that the image was written correctly if (result == CompletionCode.Success) { fwUpdateStage = FwUpdateStageEnum.VerifyFirmwareImage; result = VerifyFirmwareImage(fwImage, fwUpdateInfo.primaryImage); } // Exit programming mode if (result == CompletionCode.Success) { fwUpdateStage = FwUpdateStageEnum.ExitFirmwareUpgradeMode; result = ExitFirmwareUpgradeMode(); } if (result == CompletionCode.Success) { // Update firmware upgrade status fwUpdateStage = FwUpdateStageEnum.Completed; fwUpdateStatus = FwUpdateStatusEnum.Success; } else { if (enteredFwUpgradeMode) { ExitFirmwareUpgradeMode(); } fwUpdateStatus = FwUpdateStatusEnum.Failed; Tracer.WriteWarning("ExecuteFirmwareUpdate failed at stage: {0} with completion code: {1}", fwUpdateStage.ToString(), result); } ChassisState.PsuFwUpdateInProgress[this.PsuId - 1] = false; return; } catch (Exception ex) { if (enteredFwUpgradeMode) { ExitFirmwareUpgradeMode(); } fwUpdateStatus = FwUpdateStatusEnum.Failed; Tracer.WriteWarning("ExecuteFirmwareUpdate failed at stage: {0} with exception: {1}", fwUpdateStage.ToString(), ex.Message); ChassisState.PsuFwUpdateInProgress[this.PsuId - 1] = false; return; } } }
/// <summary> /// Writes firmware image to the PSU /// </summary> /// <param name="fwImage">String array containing the firmware image</param> /// <param name="primaryImage"> /// True: Firmware image is for primary controller. /// False: Firmware image is for secondary controller. /// <returns>Completion Code.</returns> private CompletionCode WriteFirmwareImage(string[] fwImage, bool primaryImage) { CompletionCode result = CompletionCode.UnspecifiedError; // Determine the start/end offsets for the image file string startOffset = primaryImage ? priFwWriteStartOffset : secFwWriteStartOffset; string endOffset = primaryImage ? priFwEndOffset : secFwEndOffset; byte endRomPage = primaryImage ? priFwEndPage : secFwEndPage; // Determine the proper time delays for primary/secondary controller int psuI2CPacketHandleTimeMs = primaryImage ? psuPriI2CPacketHandleTimeMs : psuSecI2CPacketHandleTimeMs; int psuBlockProgramWriteTimeMs = primaryImage ? psuPriBlockProgramWriteTimeMs : psuSecBlockProgramWriteTimeMs; Tracer.WriteInfo("WriteFirmwareImage(): Primary Image: {0}", primaryImage); // Find index of first line of the firmware image file int dataIdx = Array.FindIndex<string>(fwImage, p => p.StartsWith(startOffset)); if (dataIdx == -1) { Tracer.WriteWarning("WriteFirmwareImage: Cannot find start of firmware image file. Primary Image: {0}", primaryImage); return result; } int blockIdx = 0; string tmpStr; StringBuilder fwDataStr; byte[] fwDataByteArr; byte romPage = 0; bool writeComplete = false; while (!writeComplete) { // Check validity of each line of the firmware image file tmpStr = fwImage[dataIdx]; if ((string.IsNullOrEmpty(tmpStr)) || (tmpStr.Length != fwImageDataLineLength)) { Tracer.WriteWarning("WriteFirmwareImage: Invalid line in firmware image file. Data index: {0} Line value: {1}", dataIdx, tmpStr); result = CompletionCode.UnspecifiedError; return result; }; // Extract low/high 8 bytes of the payload and write to PSU for (int i = 0; i < 2; i++) { // Remove hex checksum, 8 bytes of payload (low or high), record type and data length fwDataStr = new StringBuilder(tmpStr).Remove(40, 2).Remove(24 - 16*i, 16).Remove(6, 2).Remove(0, 2); // Convert to byte array and update low byte of address fwDataByteArr = Ipmi.IpmiSharedFunc.HexStringToByteArray(fwDataStr.ToString()); fwDataByteArr[1] = (byte)(fwDataByteArr[1] + (i*8)); // Write to PSU result = WriteProgramMemory(fwDataByteArr, false); if (result != CompletionCode.Success) { Tracer.WriteWarning("WriteFirmwareImage: Error writing to program memory: Completion Code: " + result + " Data index: " + dataIdx + " Line value: " + fwDataStr.ToString()); return result; } // Wait for PSU I2C Packet Handling Time Thread.Sleep(psuI2CPacketHandleTimeMs); } dataIdx++; blockIdx++; if (blockIdx == 16) { blockIdx = 0; // Wait for PSU to write block every 16 lines Thread.Sleep(psuBlockProgramWriteTimeMs); } // Check write status FirmwareUpdateStatusPacket response = GetFirmwareUpdateStatus(); if (response.CompletionCode != CompletionCode.Success) { fwUpdateStatus = FwUpdateStatusEnum.Failed; Tracer.WriteWarning("WriteFirmwareImage: GetFirmwareUpdateStatus Failure. Completion Code: " + response.CompletionCode + " Data index: " + dataIdx + " Line value: " + tmpStr); result = response.CompletionCode; return result; } else { if (response.UpdateStatus != PsuFwUpdateStatus.NoError) { fwUpdateStatus = FwUpdateStatusEnum.Failed; Tracer.WriteWarning("WriteFirmwareImage: Write failed with status: " + response.UpdateStatus.ToString() + " Data index: " + dataIdx + " Line value: " + tmpStr); result = CompletionCode.UnspecifiedError; return result; } } // Wait for PSU I2C Packet Handling Time Thread.Sleep(psuI2CPacketHandleTimeMs); // Check if we are at the end of the ROM page if (tmpStr.StartsWith(pageEndOffset)) { // Next line in firmware image file contains the ROM page update data tmpStr = fwImage[dataIdx]; if ((string.IsNullOrEmpty(tmpStr)) || (tmpStr.Length != fwImageRomPageLineLength)) { Tracer.WriteWarning("WriteFirmwareImage: Invalid ROM page update line in firmware image file. Data index: {0} Line value: {1}", dataIdx, tmpStr); result = CompletionCode.UnspecifiedError; return result; }; // Remove hex checksum, record type and data length // Convert to byte array and update low byte of address fwDataByteArr = Ipmi.IpmiSharedFunc.HexStringToByteArray(tmpStr.Remove(12, 2).Remove(6, 2).Remove(0, 2)); fwDataByteArr[1] = (byte)(fwDataByteArr[1] + 4); // Write to PSU result = WriteProgramMemory(fwDataByteArr, true); if (result != CompletionCode.Success) { Tracer.WriteWarning("WriteFirmwareImage: Error writing ROM page to program memory: Completion Code: " + result + " Data index: " + dataIdx + " Line value: " + tmpStr); return result; } dataIdx++; romPage++; // Wait for PSU I2C Packet Handling Time Thread.Sleep(psuI2CPacketHandleTimeMs); } // Check if we are at the end of the file if ((tmpStr.StartsWith(endOffset)) && (romPage == endRomPage)) { writeComplete = true; } } result = CompletionCode.Success; return result; }