3 These are the common Fault Tolerant Write (FTW) functions that are shared
4 by DXE FTW driver and SMM FTW driver.
6 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "FaultTolerantWrite.h"
20 // Fault Tolerant Write Protocol API
23 Query the largest block that may be updated in a fault tolerant manner.
26 @param This The pointer to this protocol instance.
27 @param BlockSize A pointer to a caller allocated UINTN that is updated to
28 indicate the size of the largest block that can be updated.
30 @return EFI_SUCCESS The function completed successfully
36 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
40 EFI_FTW_DEVICE
*FtwDevice
;
42 if (!FeaturePcdGet(PcdFullFtwServiceEnable
)) {
43 return EFI_UNSUPPORTED
;
46 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
48 *BlockSize
= FtwDevice
->SpareAreaLength
;
54 Allocates space for the protocol to maintain information about writes.
55 Since writes must be completed in a fault tolerant manner and multiple
56 updates will require more resources to be successful, this function
57 enables the protocol to ensure that enough space exists to track
58 information about the upcoming writes.
60 All writes must be completed or aborted before another fault tolerant write can occur.
62 @param This The pointer to this protocol instance.
63 @param CallerId The GUID identifying the write.
64 @param PrivateDataSize The size of the caller's private data
65 that must be recorded for each write.
66 @param NumberOfWrites The number of fault tolerant block writes
67 that will need to occur.
69 @return EFI_SUCCESS The function completed successfully
70 @retval EFI_ABORTED The function could not complete successfully.
71 @retval EFI_ACCESS_DENIED All allocated writes have not been completed.
77 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
78 IN EFI_GUID
*CallerId
,
79 IN UINTN PrivateDataSize
,
80 IN UINTN NumberOfWrites
86 EFI_FTW_DEVICE
*FtwDevice
;
87 EFI_FAULT_TOLERANT_WRITE_HEADER
*FtwHeader
;
89 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
91 Status
= WorkSpaceRefresh (FtwDevice
);
92 if (EFI_ERROR (Status
)) {
96 // Check if there is enough space for the coming allocation
98 if (FTW_WRITE_TOTAL_SIZE (NumberOfWrites
, PrivateDataSize
) > FtwDevice
->FtwWorkSpaceHeader
->WriteQueueSize
) {
99 DEBUG ((EFI_D_ERROR
, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId
));
100 return EFI_BUFFER_TOO_SMALL
;
103 // Find the last write header and record.
104 // If the FtwHeader is complete, skip the completed last write header/records
106 FtwHeader
= FtwDevice
->FtwLastWriteHeader
;
109 // Previous write has not completed, access denied.
111 if ((FtwHeader
->HeaderAllocated
== FTW_VALID_STATE
) || (FtwHeader
->WritesAllocated
== FTW_VALID_STATE
)) {
112 return EFI_ACCESS_DENIED
;
115 // If workspace is not enough, then reclaim workspace
117 Offset
= (UINT8
*) FtwHeader
- (UINT8
*) FtwDevice
->FtwWorkSpace
;
118 if (Offset
+ FTW_WRITE_TOTAL_SIZE (NumberOfWrites
, PrivateDataSize
) > FtwDevice
->FtwWorkSpaceSize
) {
119 Status
= FtwReclaimWorkSpace (FtwDevice
, TRUE
);
120 if (EFI_ERROR (Status
)) {
124 FtwHeader
= FtwDevice
->FtwLastWriteHeader
;
127 // Prepare FTW write header,
128 // overwrite the buffer and write to workspace.
130 FtwHeader
->WritesAllocated
= FTW_INVALID_STATE
;
131 FtwHeader
->Complete
= FTW_INVALID_STATE
;
132 CopyMem (&FtwHeader
->CallerId
, CallerId
, sizeof (EFI_GUID
));
133 FtwHeader
->NumberOfWrites
= NumberOfWrites
;
134 FtwHeader
->PrivateDataSize
= PrivateDataSize
;
135 FtwHeader
->HeaderAllocated
= FTW_VALID_STATE
;
137 Length
= sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
);
138 Status
= FtwDevice
->FtwFvBlock
->Write (
139 FtwDevice
->FtwFvBlock
,
140 FtwDevice
->FtwWorkSpaceLba
,
141 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
145 if (EFI_ERROR (Status
)) {
149 // Update Header->WriteAllocated as VALID
151 Status
= FtwUpdateFvState (
152 FtwDevice
->FtwFvBlock
,
153 FtwDevice
->FtwWorkSpaceLba
,
154 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
157 if (EFI_ERROR (Status
)) {
163 "Ftw: Allocate() success, Caller:%g, # %d\n",
173 Write a record with fault tolerant mannaer.
174 Since the content has already backuped in spare block, the write is
175 guaranteed to be completed with fault tolerant manner.
177 @param This The pointer to this protocol instance.
178 @param Fvb The FVB protocol that provides services for
179 reading, writing, and erasing the target block.
181 @retval EFI_SUCCESS The function completed successfully
182 @retval EFI_ABORTED The function could not complete successfully
187 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
188 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
192 EFI_FTW_DEVICE
*FtwDevice
;
193 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
194 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
196 EFI_LBA WorkSpaceLbaOffset
;
198 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
200 WorkSpaceLbaOffset
= FtwDevice
->FtwWorkSpaceLba
- FtwDevice
->FtwWorkBlockLba
;
203 // Spare Complete but Destination not complete,
204 // Recover the target block with the spare block.
206 Header
= FtwDevice
->FtwLastWriteHeader
;
207 Record
= FtwDevice
->FtwLastWriteRecord
;
210 // IF target block is working block, THEN Flush Spare Block To Working Block;
211 // ELSE flush spare block to target block, which may be boot block after all.
213 if (IsWorkingBlock (FtwDevice
, Fvb
, Record
->Lba
)) {
215 // If target block is working block,
216 // it also need to set SPARE_COMPLETED to spare block.
218 Offset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
219 Status
= FtwUpdateFvState (
220 FtwDevice
->FtwBackupFvb
,
221 FtwDevice
->FtwSpareLba
+ WorkSpaceLbaOffset
,
222 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
225 if (EFI_ERROR (Status
)) {
229 Status
= FlushSpareBlockToWorkingBlock (FtwDevice
);
230 } else if (IsBootBlock (FtwDevice
, Fvb
, Record
->Lba
)) {
234 Status
= FlushSpareBlockToBootBlock (FtwDevice
);
237 // Update blocks other than working block or boot block
239 Status
= FlushSpareBlockToTargetBlock (FtwDevice
, Fvb
, Record
->Lba
);
242 if (EFI_ERROR (Status
)) {
246 // Record the DestionationComplete in record
248 Offset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
249 Status
= FtwUpdateFvState (
250 FtwDevice
->FtwFvBlock
,
251 FtwDevice
->FtwWorkSpaceLba
,
252 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
255 if (EFI_ERROR (Status
)) {
259 Record
->DestinationComplete
= FTW_VALID_STATE
;
262 // If this is the last Write in these write sequence,
263 // set the complete flag of write header.
265 if (IsLastRecordOfWrites (Header
, Record
)) {
266 Offset
= (UINT8
*) Header
- FtwDevice
->FtwWorkSpace
;
267 Status
= FtwUpdateFvState (
268 FtwDevice
->FtwFvBlock
,
269 FtwDevice
->FtwWorkSpaceLba
,
270 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
273 Header
->Complete
= FTW_VALID_STATE
;
274 if (EFI_ERROR (Status
)) {
283 Starts a target block update. This function will record data about write
284 in fault tolerant storage and will complete the write in a recoverable
285 manner, ensuring at all times that either the original contents or
286 the modified contents are available.
288 @param This The pointer to this protocol instance.
289 @param Lba The logical block address of the target block.
290 @param Offset The offset within the target block to place the data.
291 @param Length The number of bytes to write to the target block.
292 @param PrivateData A pointer to private data that the caller requires to
293 complete any pending writes in the event of a fault.
294 @param FvBlockHandle The handle of FVB protocol that provides services for
295 reading, writing, and erasing the target block.
296 @param Buffer The data to write.
298 @retval EFI_SUCCESS The function completed successfully
299 @retval EFI_ABORTED The function could not complete successfully.
300 @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block.
301 Offset + *NumBytes > SpareAreaLength.
302 @retval EFI_ACCESS_DENIED No writes have been allocated.
303 @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.
304 @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.
310 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
314 IN VOID
*PrivateData
,
315 IN EFI_HANDLE FvBlockHandle
,
320 EFI_FTW_DEVICE
*FtwDevice
;
321 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
322 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
323 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
328 UINTN SpareBufferSize
;
332 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress
;
334 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
336 Status
= WorkSpaceRefresh (FtwDevice
);
337 if (EFI_ERROR (Status
)) {
341 Header
= FtwDevice
->FtwLastWriteHeader
;
342 Record
= FtwDevice
->FtwLastWriteRecord
;
344 if (IsErasedFlashBuffer ((UINT8
*) Header
, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER
))) {
345 if (PrivateData
== NULL
) {
347 // Ftw Write Header is not allocated.
348 // No additional private data, the private data size is zero. Number of record can be set to 1.
350 Status
= FtwAllocate (This
, &gEfiCallerIdGuid
, 0, 1);
351 if (EFI_ERROR (Status
)) {
356 // Ftw Write Header is not allocated
357 // Additional private data is not NULL, the private data size can't be determined.
359 DEBUG ((EFI_D_ERROR
, "Ftw: no allocates space for write record!\n"));
360 DEBUG ((EFI_D_ERROR
, "Ftw: Allocate service should be called before Write service!\n"));
361 return EFI_NOT_READY
;
366 // If Record is out of the range of Header, return access denied.
368 if (((UINTN
)((UINT8
*) Record
- (UINT8
*) Header
)) > FTW_WRITE_TOTAL_SIZE (Header
->NumberOfWrites
- 1, Header
->PrivateDataSize
)) {
369 return EFI_ACCESS_DENIED
;
373 // Check the COMPLETE flag of last write header
375 if (Header
->Complete
== FTW_VALID_STATE
) {
376 return EFI_ACCESS_DENIED
;
379 if (Record
->DestinationComplete
== FTW_VALID_STATE
) {
380 return EFI_ACCESS_DENIED
;
383 if ((Record
->SpareComplete
== FTW_VALID_STATE
) && (Record
->DestinationComplete
!= FTW_VALID_STATE
)) {
384 return EFI_NOT_READY
;
387 // Check if the input data can fit within the target block
389 if ((Offset
+ Length
) > FtwDevice
->SpareAreaLength
) {
390 return EFI_BAD_BUFFER_SIZE
;
393 // Get the FVB protocol by handle
395 Status
= FtwGetFvbByHandle (FvBlockHandle
, &Fvb
);
396 if (EFI_ERROR (Status
)) {
397 return EFI_NOT_FOUND
;
400 Status
= Fvb
->GetPhysicalAddress (Fvb
, &FvbPhysicalAddress
);
401 if (EFI_ERROR (Status
)) {
402 DEBUG ((EFI_D_ERROR
, "FtwLite: Get FVB physical address - %r\n", Status
));
407 // Set BootBlockUpdate FLAG if it's updating boot block.
409 if (IsBootBlock (FtwDevice
, Fvb
, Lba
)) {
410 Record
->BootBlockUpdate
= FTW_VALID_STATE
;
413 // Write the record to the work space.
416 Record
->Offset
= Offset
;
417 Record
->Length
= Length
;
418 Record
->RelativeOffset
= (INT64
) (FvbPhysicalAddress
+ (UINTN
) Lba
* FtwDevice
->BlockSize
) - (INT64
) FtwDevice
->SpareAreaAddress
;
419 if (PrivateData
!= NULL
) {
420 CopyMem ((Record
+ 1), PrivateData
, (UINTN
) Header
->PrivateDataSize
);
423 MyOffset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
424 MyLength
= FTW_RECORD_SIZE (Header
->PrivateDataSize
);
426 Status
= FtwDevice
->FtwFvBlock
->Write (
427 FtwDevice
->FtwFvBlock
,
428 FtwDevice
->FtwWorkSpaceLba
,
429 FtwDevice
->FtwWorkSpaceBase
+ MyOffset
,
433 if (EFI_ERROR (Status
)) {
437 // Record has written to working block, then do the data.
440 // Allocate a memory buffer
442 MyBufferSize
= FtwDevice
->SpareAreaLength
;
443 MyBuffer
= AllocatePool (MyBufferSize
);
444 if (MyBuffer
== NULL
) {
445 return EFI_OUT_OF_RESOURCES
;
448 // Read all original data from target block to memory buffer
451 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
452 MyLength
= FtwDevice
->BlockSize
;
453 Status
= Fvb
->Read (Fvb
, Lba
+ Index
, 0, &MyLength
, Ptr
);
454 if (EFI_ERROR (Status
)) {
462 // Overwrite the updating range data with
463 // the input buffer content
465 CopyMem (MyBuffer
+ Offset
, Buffer
, Length
);
468 // Try to keep the content of spare block
469 // Save spare block into a spare backup memory buffer (Sparebuffer)
471 SpareBufferSize
= FtwDevice
->SpareAreaLength
;
472 SpareBuffer
= AllocatePool (SpareBufferSize
);
473 if (SpareBuffer
== NULL
) {
475 return EFI_OUT_OF_RESOURCES
;
479 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
480 MyLength
= FtwDevice
->BlockSize
;
481 Status
= FtwDevice
->FtwBackupFvb
->Read (
482 FtwDevice
->FtwBackupFvb
,
483 FtwDevice
->FtwSpareLba
+ Index
,
488 if (EFI_ERROR (Status
)) {
490 FreePool (SpareBuffer
);
497 // Write the memory buffer to spare block
499 Status
= FtwEraseSpareBlock (FtwDevice
);
501 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
502 MyLength
= FtwDevice
->BlockSize
;
503 Status
= FtwDevice
->FtwBackupFvb
->Write (
504 FtwDevice
->FtwBackupFvb
,
505 FtwDevice
->FtwSpareLba
+ Index
,
510 if (EFI_ERROR (Status
)) {
512 FreePool (SpareBuffer
);
524 // Set the SpareComplete in the FTW record,
526 MyOffset
= (UINT8
*) Record
- FtwDevice
->FtwWorkSpace
;
527 Status
= FtwUpdateFvState (
528 FtwDevice
->FtwFvBlock
,
529 FtwDevice
->FtwWorkSpaceLba
,
530 FtwDevice
->FtwWorkSpaceBase
+ MyOffset
,
533 if (EFI_ERROR (Status
)) {
534 FreePool (SpareBuffer
);
538 Record
->SpareComplete
= FTW_VALID_STATE
;
541 // Since the content has already backuped in spare block, the write is
542 // guaranteed to be completed with fault tolerant manner.
544 Status
= FtwWriteRecord (This
, Fvb
);
545 if (EFI_ERROR (Status
)) {
546 FreePool (SpareBuffer
);
550 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
552 Status
= FtwEraseSpareBlock (FtwDevice
);
554 for (Index
= 0; Index
< FtwDevice
->NumberOfSpareBlock
; Index
+= 1) {
555 MyLength
= FtwDevice
->BlockSize
;
556 Status
= FtwDevice
->FtwBackupFvb
->Write (
557 FtwDevice
->FtwBackupFvb
,
558 FtwDevice
->FtwSpareLba
+ Index
,
563 if (EFI_ERROR (Status
)) {
564 FreePool (SpareBuffer
);
573 FreePool (SpareBuffer
);
577 "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",
587 Restarts a previously interrupted write. The caller must provide the
588 block protocol needed to complete the interrupted write.
590 @param This The pointer to this protocol instance.
591 @param FvBlockHandle The handle of FVB protocol that provides services for
592 reading, writing, and erasing the target block.
594 @retval EFI_SUCCESS The function completed successfully
595 @retval EFI_ACCESS_DENIED No pending writes exist
596 @retval EFI_NOT_FOUND FVB protocol not found by the handle
597 @retval EFI_ABORTED The function could not complete successfully
603 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
604 IN EFI_HANDLE FvBlockHandle
608 EFI_FTW_DEVICE
*FtwDevice
;
609 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
610 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
611 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
613 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
615 Status
= WorkSpaceRefresh (FtwDevice
);
616 if (EFI_ERROR (Status
)) {
620 Header
= FtwDevice
->FtwLastWriteHeader
;
621 Record
= FtwDevice
->FtwLastWriteRecord
;
624 // Spare Complete but Destination not complete,
625 // Recover the targt block with the spare block.
627 Status
= FtwGetFvbByHandle (FvBlockHandle
, &Fvb
);
628 if (EFI_ERROR (Status
)) {
629 return EFI_NOT_FOUND
;
633 // Check the COMPLETE flag of last write header
635 if (Header
->Complete
== FTW_VALID_STATE
) {
636 return EFI_ACCESS_DENIED
;
640 // Check the flags of last write record
642 if (Record
->DestinationComplete
== FTW_VALID_STATE
) {
643 return EFI_ACCESS_DENIED
;
646 if ((Record
->SpareComplete
!= FTW_VALID_STATE
)) {
651 // Since the content has already backuped in spare block, the write is
652 // guaranteed to be completed with fault tolerant manner.
654 Status
= FtwWriteRecord (This
, Fvb
);
655 if (EFI_ERROR (Status
)) {
661 // This is restart, no need to keep spareblock content.
663 FtwEraseSpareBlock (FtwDevice
);
665 DEBUG ((EFI_D_ERROR
, "Ftw: Restart() success \n"));
670 Aborts all previous allocated writes.
672 @param This The pointer to this protocol instance.
674 @retval EFI_SUCCESS The function completed successfully
675 @retval EFI_ABORTED The function could not complete successfully.
676 @retval EFI_NOT_FOUND No allocated writes exist.
682 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
687 EFI_FTW_DEVICE
*FtwDevice
;
689 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
691 Status
= WorkSpaceRefresh (FtwDevice
);
692 if (EFI_ERROR (Status
)) {
696 if (FtwDevice
->FtwLastWriteHeader
->HeaderAllocated
!= FTW_VALID_STATE
) {
697 return EFI_NOT_FOUND
;
700 if (FtwDevice
->FtwLastWriteHeader
->Complete
== FTW_VALID_STATE
) {
701 return EFI_NOT_FOUND
;
704 // Update the complete state of the header as VALID and abort.
706 Offset
= (UINT8
*) FtwDevice
->FtwLastWriteHeader
- FtwDevice
->FtwWorkSpace
;
707 Status
= FtwUpdateFvState (
708 FtwDevice
->FtwFvBlock
,
709 FtwDevice
->FtwWorkSpaceLba
,
710 FtwDevice
->FtwWorkSpaceBase
+ Offset
,
713 if (EFI_ERROR (Status
)) {
717 FtwDevice
->FtwLastWriteHeader
->Complete
= FTW_VALID_STATE
;
719 DEBUG ((EFI_D_ERROR
, "Ftw: Abort() success \n"));
724 Starts a target block update. This records information about the write
725 in fault tolerant storage and will complete the write in a recoverable
726 manner, ensuring at all times that either the original contents or
727 the modified contents are available.
729 @param This The pointer to this protocol instance.
730 @param CallerId The GUID identifying the last write.
731 @param Lba The logical block address of the last write.
732 @param Offset The offset within the block of the last write.
733 @param Length The length of the last write.
734 @param PrivateDataSize bytes from the private data
735 stored for this write.
736 @param PrivateData A pointer to a buffer. The function will copy
737 @param Complete A Boolean value with TRUE indicating
738 that the write was completed.
740 @retval EFI_SUCCESS The function completed successfully
741 @retval EFI_ABORTED The function could not complete successfully
742 @retval EFI_NOT_FOUND No allocated writes exist
743 @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough
749 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL
*This
,
750 OUT EFI_GUID
*CallerId
,
754 IN OUT UINTN
*PrivateDataSize
,
755 OUT VOID
*PrivateData
,
756 OUT BOOLEAN
*Complete
760 EFI_FTW_DEVICE
*FtwDevice
;
761 EFI_FAULT_TOLERANT_WRITE_HEADER
*Header
;
762 EFI_FAULT_TOLERANT_WRITE_RECORD
*Record
;
764 if (!FeaturePcdGet(PcdFullFtwServiceEnable
)) {
765 return EFI_UNSUPPORTED
;
768 FtwDevice
= FTW_CONTEXT_FROM_THIS (This
);
770 Status
= WorkSpaceRefresh (FtwDevice
);
771 if (EFI_ERROR (Status
)) {
775 Header
= FtwDevice
->FtwLastWriteHeader
;
776 Record
= FtwDevice
->FtwLastWriteRecord
;
779 // If Header is incompleted and the last record has completed, then
780 // call Abort() to set the Header->Complete FLAG.
782 if ((Header
->Complete
!= FTW_VALID_STATE
) &&
783 (Record
->DestinationComplete
== FTW_VALID_STATE
) &&
784 IsLastRecordOfWrites (Header
, Record
)
787 Status
= FtwAbort (This
);
789 return EFI_NOT_FOUND
;
792 // If there is no write header/record, return not found.
794 if (Header
->HeaderAllocated
!= FTW_VALID_STATE
) {
796 return EFI_NOT_FOUND
;
799 // If this record SpareComplete has not set, then it can not restart.
801 if (Record
->SpareComplete
!= FTW_VALID_STATE
) {
802 Status
= GetPreviousRecordOfWrites (Header
, &Record
);
803 if (EFI_ERROR (Status
)) {
806 return EFI_NOT_FOUND
;
808 ASSERT (Record
!= NULL
);
812 // Fill all the requested values
814 CopyMem (CallerId
, &Header
->CallerId
, sizeof (EFI_GUID
));
816 *Offset
= (UINTN
) Record
->Offset
;
817 *Length
= (UINTN
) Record
->Length
;
818 *Complete
= (BOOLEAN
) (Record
->DestinationComplete
== FTW_VALID_STATE
);
820 if (*PrivateDataSize
< Header
->PrivateDataSize
) {
821 *PrivateDataSize
= (UINTN
) Header
->PrivateDataSize
;
823 Status
= EFI_BUFFER_TOO_SMALL
;
825 *PrivateDataSize
= (UINTN
) Header
->PrivateDataSize
;
826 CopyMem (PrivateData
, Record
+ 1, *PrivateDataSize
);
827 Status
= EFI_SUCCESS
;
830 DEBUG ((EFI_D_ERROR
, "Ftw: GetLasetWrite() success\n"));