2 DiskIo driver that lays on every BlockIo protocol in the system.
3 DiskIo converts a block oriented device to a byte oriented device.
5 Disk access may have to handle unaligned request about sector boundaries.
7 UnderRun - The first byte is not on a sector boundary or the read request is
8 less than a sector in length.
9 Aligned - A read of N contiguous sectors.
10 OverRun - The last byte is not on a sector boundary.
12 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
13 SPDX-License-Identifier: BSD-2-Clause-Patent
20 // Driver binding protocol implementation for DiskIo driver.
22 EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding
= {
23 DiskIoDriverBindingSupported
,
24 DiskIoDriverBindingStart
,
25 DiskIoDriverBindingStop
,
32 // Template for DiskIo private data structure.
33 // The pointer to BlockIo protocol interface is assigned dynamically.
35 DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate
= {
36 DISK_IO_PRIVATE_DATA_SIGNATURE
,
38 EFI_DISK_IO_PROTOCOL_REVISION
,
43 EFI_DISK_IO2_PROTOCOL_REVISION
,
52 Test to see if this driver supports ControllerHandle.
54 @param This Protocol instance pointer.
55 @param ControllerHandle Handle of device to test
56 @param RemainingDevicePath Optional parameter use to pick a specific child
59 @retval EFI_SUCCESS This driver supports this device
60 @retval EFI_ALREADY_STARTED This driver is already running on this device
61 @retval other This driver does not support this device
66 DiskIoDriverBindingSupported (
67 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
68 IN EFI_HANDLE ControllerHandle
,
69 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
73 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
76 // Open the IO Abstraction(s) needed to perform the supported test.
78 Status
= gBS
->OpenProtocol (
80 &gEfiBlockIoProtocolGuid
,
82 This
->DriverBindingHandle
,
84 EFI_OPEN_PROTOCOL_BY_DRIVER
86 if (EFI_ERROR (Status
)) {
91 // Close the I/O Abstraction(s) used to perform the supported test.
95 &gEfiBlockIoProtocolGuid
,
96 This
->DriverBindingHandle
,
103 Start this driver on ControllerHandle by opening a Block IO protocol and
104 installing a Disk IO protocol on ControllerHandle.
106 @param This Protocol instance pointer.
107 @param ControllerHandle Handle of device to bind driver to
108 @param RemainingDevicePath Optional parameter use to pick a specific child
111 @retval EFI_SUCCESS This driver is added to ControllerHandle
112 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
113 @retval other This driver does not support this device
118 DiskIoDriverBindingStart (
119 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
120 IN EFI_HANDLE ControllerHandle
,
121 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
125 DISK_IO_PRIVATE_DATA
*Instance
;
130 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
133 // Connect to the Block IO and Block IO2 interface on ControllerHandle.
135 Status
= gBS
->OpenProtocol (
137 &gEfiBlockIoProtocolGuid
,
138 (VOID
**)&gDiskIoPrivateDataTemplate
.BlockIo
,
139 This
->DriverBindingHandle
,
141 EFI_OPEN_PROTOCOL_BY_DRIVER
143 if (EFI_ERROR (Status
)) {
147 Status
= gBS
->OpenProtocol (
149 &gEfiBlockIo2ProtocolGuid
,
150 (VOID
**)&gDiskIoPrivateDataTemplate
.BlockIo2
,
151 This
->DriverBindingHandle
,
153 EFI_OPEN_PROTOCOL_BY_DRIVER
155 if (EFI_ERROR (Status
)) {
156 gDiskIoPrivateDataTemplate
.BlockIo2
= NULL
;
160 // Initialize the Disk IO device instance.
162 Instance
= AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA
), &gDiskIoPrivateDataTemplate
);
163 if (Instance
== NULL
) {
164 Status
= EFI_OUT_OF_RESOURCES
;
169 // The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.
172 (Instance
->BlockIo2
== NULL
) ||
173 ((Instance
->BlockIo
->Media
->IoAlign
== Instance
->BlockIo2
->Media
->IoAlign
) &&
174 (Instance
->BlockIo
->Media
->BlockSize
== Instance
->BlockIo2
->Media
->BlockSize
)
178 InitializeListHead (&Instance
->TaskQueue
);
179 EfiInitializeLock (&Instance
->TaskQueueLock
, TPL_NOTIFY
);
180 Instance
->SharedWorkingBuffer
= AllocateAlignedPages (
181 EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum
) * Instance
->BlockIo
->Media
->BlockSize
),
182 Instance
->BlockIo
->Media
->IoAlign
184 if (Instance
->SharedWorkingBuffer
== NULL
) {
185 Status
= EFI_OUT_OF_RESOURCES
;
190 // Install protocol interfaces for the Disk IO device.
192 if (Instance
->BlockIo2
!= NULL
) {
193 Status
= gBS
->InstallMultipleProtocolInterfaces (
195 &gEfiDiskIoProtocolGuid
,
197 &gEfiDiskIo2ProtocolGuid
,
202 Status
= gBS
->InstallMultipleProtocolInterfaces (
204 &gEfiDiskIoProtocolGuid
,
211 if (EFI_ERROR (Status
)) {
212 if ((Instance
!= NULL
) && (Instance
->SharedWorkingBuffer
!= NULL
)) {
214 Instance
->SharedWorkingBuffer
,
215 EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum
) * Instance
->BlockIo
->Media
->BlockSize
)
219 if (Instance
!= NULL
) {
225 &gEfiBlockIoProtocolGuid
,
226 This
->DriverBindingHandle
,
232 gBS
->RestoreTPL (OldTpl
);
237 Stop this driver on ControllerHandle by removing Disk IO protocol and closing
238 the Block IO protocol on ControllerHandle.
240 @param This Protocol instance pointer.
241 @param ControllerHandle Handle of device to stop driver on
242 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
243 children is zero stop the entire bus driver.
244 @param ChildHandleBuffer List of Child Handles to Stop.
246 @retval EFI_SUCCESS This driver is removed ControllerHandle
247 @retval other This driver was not removed from this device
252 DiskIoDriverBindingStop (
253 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
254 IN EFI_HANDLE ControllerHandle
,
255 IN UINTN NumberOfChildren
,
256 IN EFI_HANDLE
*ChildHandleBuffer
260 EFI_DISK_IO_PROTOCOL
*DiskIo
;
261 EFI_DISK_IO2_PROTOCOL
*DiskIo2
;
262 DISK_IO_PRIVATE_DATA
*Instance
;
266 // Get our context back.
268 Status
= gBS
->OpenProtocol (
270 &gEfiDiskIoProtocolGuid
,
272 This
->DriverBindingHandle
,
274 EFI_OPEN_PROTOCOL_GET_PROTOCOL
276 if (EFI_ERROR (Status
)) {
280 Status
= gBS
->OpenProtocol (
282 &gEfiDiskIo2ProtocolGuid
,
284 This
->DriverBindingHandle
,
286 EFI_OPEN_PROTOCOL_GET_PROTOCOL
288 if (EFI_ERROR (Status
)) {
292 Instance
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo
);
294 if (DiskIo2
!= NULL
) {
296 // Call BlockIo2::Reset() to terminate any in-flight non-blocking I/O requests
298 ASSERT (Instance
->BlockIo2
!= NULL
);
299 Status
= Instance
->BlockIo2
->Reset (Instance
->BlockIo2
, FALSE
);
300 if (EFI_ERROR (Status
)) {
304 Status
= gBS
->UninstallMultipleProtocolInterfaces (
306 &gEfiDiskIoProtocolGuid
,
308 &gEfiDiskIo2ProtocolGuid
,
313 Status
= gBS
->UninstallMultipleProtocolInterfaces (
315 &gEfiDiskIoProtocolGuid
,
321 if (!EFI_ERROR (Status
)) {
323 EfiAcquireLock (&Instance
->TaskQueueLock
);
324 AllTaskDone
= IsListEmpty (&Instance
->TaskQueue
);
325 EfiReleaseLock (&Instance
->TaskQueueLock
);
326 } while (!AllTaskDone
);
329 Instance
->SharedWorkingBuffer
,
330 EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum
) * Instance
->BlockIo
->Media
->BlockSize
)
333 Status
= gBS
->CloseProtocol (
335 &gEfiBlockIoProtocolGuid
,
336 This
->DriverBindingHandle
,
339 ASSERT_EFI_ERROR (Status
);
340 if (DiskIo2
!= NULL
) {
341 Status
= gBS
->CloseProtocol (
343 &gEfiBlockIo2ProtocolGuid
,
344 This
->DriverBindingHandle
,
347 ASSERT_EFI_ERROR (Status
);
357 Destroy the sub task.
359 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
360 @param Subtask Subtask.
362 @return LIST_ENTRY * Pointer to the next link of subtask.
365 DiskIoDestroySubtask (
366 IN DISK_IO_PRIVATE_DATA
*Instance
,
367 IN DISK_IO_SUBTASK
*Subtask
372 if (Subtask
->Task
!= NULL
) {
373 EfiAcquireLock (&Subtask
->Task
->SubtasksLock
);
376 Link
= RemoveEntryList (&Subtask
->Link
);
377 if (Subtask
->Task
!= NULL
) {
378 EfiReleaseLock (&Subtask
->Task
->SubtasksLock
);
381 if (!Subtask
->Blocking
) {
382 if (Subtask
->WorkingBuffer
!= NULL
) {
384 Subtask
->WorkingBuffer
,
385 Subtask
->Length
< Instance
->BlockIo
->Media
->BlockSize
386 ? EFI_SIZE_TO_PAGES (Instance
->BlockIo
->Media
->BlockSize
)
387 : EFI_SIZE_TO_PAGES (Subtask
->Length
)
391 if (Subtask
->BlockIo2Token
.Event
!= NULL
) {
392 gBS
->CloseEvent (Subtask
->BlockIo2Token
.Event
);
402 The callback for the BlockIo2 ReadBlocksEx/WriteBlocksEx.
403 @param Event Event whose notification function is being invoked.
404 @param Context The pointer to the notification function's context,
405 which points to the DISK_IO_SUBTASK instance.
409 DiskIo2OnReadWriteComplete (
414 DISK_IO_SUBTASK
*Subtask
;
416 EFI_STATUS TransactionStatus
;
417 DISK_IO_PRIVATE_DATA
*Instance
;
419 Subtask
= (DISK_IO_SUBTASK
*)Context
;
420 TransactionStatus
= Subtask
->BlockIo2Token
.TransactionStatus
;
421 Task
= Subtask
->Task
;
422 Instance
= Task
->Instance
;
424 ASSERT (Subtask
->Signature
== DISK_IO_SUBTASK_SIGNATURE
);
425 ASSERT (Instance
->Signature
== DISK_IO_PRIVATE_DATA_SIGNATURE
);
426 ASSERT (Task
->Signature
== DISK_IO2_TASK_SIGNATURE
);
428 if ((Subtask
->WorkingBuffer
!= NULL
) && !EFI_ERROR (TransactionStatus
) &&
429 (Task
->Token
!= NULL
) && !Subtask
->Write
432 CopyMem (Subtask
->Buffer
, Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Length
);
435 DiskIoDestroySubtask (Instance
, Subtask
);
437 if (EFI_ERROR (TransactionStatus
) || IsListEmpty (&Task
->Subtasks
)) {
438 if (Task
->Token
!= NULL
) {
440 // Signal error status once the subtask is failed.
441 // Or signal the last status once the last subtask is finished.
443 Task
->Token
->TransactionStatus
= TransactionStatus
;
444 gBS
->SignalEvent (Task
->Token
->Event
);
447 // Mark token to NULL indicating the Task is a dead task.
457 @param Write TRUE: Write request; FALSE: Read request.
458 @param Lba The starting logical block address to read from on the device.
459 @param Offset The starting byte offset to read from the LBA.
460 @param Length The number of bytes to read from the device.
461 @param WorkingBuffer The aligned buffer to hold the data for reading or writing.
462 @param Buffer The buffer to hold the data for reading or writing.
463 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
465 @return A pointer to the created subtask.
468 DiskIoCreateSubtask (
473 IN VOID
*WorkingBuffer OPTIONAL
,
478 DISK_IO_SUBTASK
*Subtask
;
481 Subtask
= AllocateZeroPool (sizeof (DISK_IO_SUBTASK
));
482 if (Subtask
== NULL
) {
486 Subtask
->Signature
= DISK_IO_SUBTASK_SIGNATURE
;
487 Subtask
->Write
= Write
;
489 Subtask
->Offset
= Offset
;
490 Subtask
->Length
= Length
;
491 Subtask
->WorkingBuffer
= WorkingBuffer
;
492 Subtask
->Buffer
= Buffer
;
493 Subtask
->Blocking
= Blocking
;
495 Status
= gBS
->CreateEvent (
498 DiskIo2OnReadWriteComplete
,
500 &Subtask
->BlockIo2Token
.Event
502 if (EFI_ERROR (Status
)) {
510 " %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
523 Create the subtask list.
525 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
526 @param Write TRUE: Write request; FALSE: Read request.
527 @param Offset The starting byte offset to read from the device.
528 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
529 @param Buffer A pointer to the buffer for the data.
530 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
531 @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing.
532 @param Subtasks The subtask list header.
534 @retval TRUE The subtask list is created successfully.
535 @retval FALSE The subtask list is not created.
538 DiskIoCreateSubtaskList (
539 IN DISK_IO_PRIVATE_DATA
*Instance
,
545 IN VOID
*SharedWorkingBuffer
,
546 IN OUT LIST_ENTRY
*Subtasks
557 UINTN DataBufferSize
;
558 DISK_IO_SUBTASK
*Subtask
;
562 DEBUG ((DEBUG_BLKIO
, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset
, BufferSize
, Buffer
));
564 BlockSize
= Instance
->BlockIo
->Media
->BlockSize
;
565 IoAlign
= Instance
->BlockIo
->Media
->IoAlign
;
570 Lba
= DivU64x32Remainder (Offset
, BlockSize
, &UnderRun
);
571 BufferPtr
= (UINT8
*)Buffer
;
574 // Special handling for zero BufferSize
576 if (BufferSize
== 0) {
577 Subtask
= DiskIoCreateSubtask (Write
, Lba
, UnderRun
, 0, NULL
, BufferPtr
, Blocking
);
578 if (Subtask
== NULL
) {
582 InsertTailList (Subtasks
, &Subtask
->Link
);
587 Length
= MIN (BlockSize
- UnderRun
, BufferSize
);
589 WorkingBuffer
= SharedWorkingBuffer
;
591 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize
), IoAlign
);
592 if (WorkingBuffer
== NULL
) {
599 // A half write operation can be splitted to a blocking block-read and half write operation
600 // This can simplify the sub task processing logic
602 Subtask
= DiskIoCreateSubtask (FALSE
, Lba
, 0, BlockSize
, NULL
, WorkingBuffer
, TRUE
);
603 if (Subtask
== NULL
) {
607 InsertTailList (Subtasks
, &Subtask
->Link
);
610 Subtask
= DiskIoCreateSubtask (Write
, Lba
, UnderRun
, Length
, WorkingBuffer
, BufferPtr
, Blocking
);
611 if (Subtask
== NULL
) {
615 InsertTailList (Subtasks
, &Subtask
->Link
);
619 BufferSize
-= Length
;
623 OverRunLba
= Lba
+ DivU64x32Remainder (BufferSize
, BlockSize
, &OverRun
);
624 BufferSize
-= OverRun
;
628 WorkingBuffer
= SharedWorkingBuffer
;
630 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize
), IoAlign
);
631 if (WorkingBuffer
== NULL
) {
638 // A half write operation can be splitted to a blocking block-read and half write operation
639 // This can simplify the sub task processing logic
641 Subtask
= DiskIoCreateSubtask (FALSE
, OverRunLba
, 0, BlockSize
, NULL
, WorkingBuffer
, TRUE
);
642 if (Subtask
== NULL
) {
646 InsertTailList (Subtasks
, &Subtask
->Link
);
649 Subtask
= DiskIoCreateSubtask (Write
, OverRunLba
, 0, OverRun
, WorkingBuffer
, BufferPtr
+ BufferSize
, Blocking
);
650 if (Subtask
== NULL
) {
654 InsertTailList (Subtasks
, &Subtask
->Link
);
657 if (OverRunLba
> Lba
) {
659 // If the DiskIo maps directly to a BlockIo device do the read.
661 if (ALIGN_POINTER (BufferPtr
, IoAlign
) == BufferPtr
) {
662 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, BufferSize
, NULL
, BufferPtr
, Blocking
);
663 if (Subtask
== NULL
) {
667 InsertTailList (Subtasks
, &Subtask
->Link
);
669 BufferPtr
+= BufferSize
;
670 Offset
+= BufferSize
;
671 BufferSize
-= BufferSize
;
675 // Use the allocated buffer instead of the original buffer
676 // to avoid alignment issue.
678 for ( ; Lba
< OverRunLba
; Lba
+= PcdGet32 (PcdDiskIoDataBufferBlockNum
)) {
679 DataBufferSize
= MIN (BufferSize
, PcdGet32 (PcdDiskIoDataBufferBlockNum
) * BlockSize
);
681 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, DataBufferSize
, SharedWorkingBuffer
, BufferPtr
, Blocking
);
682 if (Subtask
== NULL
) {
686 InsertTailList (Subtasks
, &Subtask
->Link
);
688 BufferPtr
+= DataBufferSize
;
689 Offset
+= DataBufferSize
;
690 BufferSize
-= DataBufferSize
;
693 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), IoAlign
);
694 if (WorkingBuffer
== NULL
) {
696 // If there is not enough memory, downgrade to blocking access
698 DEBUG ((DEBUG_VERBOSE
, "DiskIo: No enough memory so downgrade to blocking access\n"));
699 if (!DiskIoCreateSubtaskList (Instance
, Write
, Offset
, BufferSize
, BufferPtr
, TRUE
, SharedWorkingBuffer
, Subtasks
)) {
703 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, BufferSize
, WorkingBuffer
, BufferPtr
, Blocking
);
704 if (Subtask
== NULL
) {
708 InsertTailList (Subtasks
, &Subtask
->Link
);
711 BufferPtr
+= BufferSize
;
712 Offset
+= BufferSize
;
713 BufferSize
-= BufferSize
;
718 ASSERT (BufferSize
== 0);
724 // Remove all the subtasks.
726 for (Link
= GetFirstNode (Subtasks
); !IsNull (Subtasks
, Link
); ) {
727 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
728 Link
= DiskIoDestroySubtask (Instance
, Subtask
);
735 Terminate outstanding asynchronous requests to a device.
737 @param This Indicates a pointer to the calling context.
739 @retval EFI_SUCCESS All outstanding requests were successfully terminated.
740 @retval EFI_DEVICE_ERROR The device reported an error while performing the cancel
746 IN EFI_DISK_IO2_PROTOCOL
*This
749 DISK_IO_PRIVATE_DATA
*Instance
;
753 Instance
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
);
755 EfiAcquireLock (&Instance
->TaskQueueLock
);
757 for (Link
= GetFirstNode (&Instance
->TaskQueue
)
758 ; !IsNull (&Instance
->TaskQueue
, Link
)
759 ; Link
= GetNextNode (&Instance
->TaskQueue
, Link
)
762 Task
= CR (Link
, DISK_IO2_TASK
, Link
, DISK_IO2_TASK_SIGNATURE
);
764 if (Task
->Token
!= NULL
) {
765 Task
->Token
->TransactionStatus
= EFI_ABORTED
;
766 gBS
->SignalEvent (Task
->Token
->Event
);
768 // Set Token to NULL so that the further BlockIo2 responses will be ignored
774 EfiReleaseLock (&Instance
->TaskQueueLock
);
780 Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks.
782 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
784 @retval TRUE The Instance->TaskQueue is empty after the completed tasks are removed.
785 @retval FALSE The Instance->TaskQueue is not empty after the completed tasks are removed.
788 DiskIo2RemoveCompletedTask (
789 IN DISK_IO_PRIVATE_DATA
*Instance
798 EfiAcquireLock (&Instance
->TaskQueueLock
);
799 for (Link
= GetFirstNode (&Instance
->TaskQueue
); !IsNull (&Instance
->TaskQueue
, Link
); ) {
800 Task
= CR (Link
, DISK_IO2_TASK
, Link
, DISK_IO2_TASK_SIGNATURE
);
801 if (IsListEmpty (&Task
->Subtasks
)) {
802 Link
= RemoveEntryList (&Task
->Link
);
803 ASSERT (Task
->Token
== NULL
);
806 Link
= GetNextNode (&Instance
->TaskQueue
, Link
);
811 EfiReleaseLock (&Instance
->TaskQueueLock
);
817 Common routine to access the disk.
819 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
820 @param Write TRUE: Write operation; FALSE: Read operation.
821 @param MediaId ID of the medium to access.
822 @param Offset The starting byte offset on the logical block I/O device to access.
823 @param Token A pointer to the token associated with the transaction.
824 If this field is NULL, synchronous/blocking IO is performed.
825 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
826 @param Buffer A pointer to the destination buffer for the data.
827 The caller is responsible either having implicit or explicit ownership of the buffer.
830 DiskIo2ReadWriteDisk (
831 IN DISK_IO_PRIVATE_DATA
*Instance
,
835 IN EFI_DISK_IO2_TOKEN
*Token
,
841 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
842 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
843 EFI_BLOCK_IO_MEDIA
*Media
;
845 LIST_ENTRY
*NextLink
;
847 DISK_IO_SUBTASK
*Subtask
;
851 BOOLEAN SubtaskBlocking
;
852 LIST_ENTRY
*SubtasksPtr
;
855 BlockIo
= Instance
->BlockIo
;
856 BlockIo2
= Instance
->BlockIo2
;
857 Media
= BlockIo
->Media
;
858 Status
= EFI_SUCCESS
;
859 Blocking
= (BOOLEAN
)((Token
== NULL
) || (Token
->Event
== NULL
));
863 // Wait till pending async task is completed.
865 while (!DiskIo2RemoveCompletedTask (Instance
)) {
868 SubtasksPtr
= &Subtasks
;
870 DiskIo2RemoveCompletedTask (Instance
);
871 Task
= AllocatePool (sizeof (DISK_IO2_TASK
));
873 return EFI_OUT_OF_RESOURCES
;
876 EfiAcquireLock (&Instance
->TaskQueueLock
);
877 InsertTailList (&Instance
->TaskQueue
, &Task
->Link
);
878 EfiReleaseLock (&Instance
->TaskQueueLock
);
880 Task
->Signature
= DISK_IO2_TASK_SIGNATURE
;
881 Task
->Instance
= Instance
;
883 EfiInitializeLock (&Task
->SubtasksLock
, TPL_NOTIFY
);
885 SubtasksPtr
= &Task
->Subtasks
;
888 InitializeListHead (SubtasksPtr
);
889 if (!DiskIoCreateSubtaskList (Instance
, Write
, Offset
, BufferSize
, Buffer
, Blocking
, Instance
->SharedWorkingBuffer
, SubtasksPtr
)) {
894 return EFI_OUT_OF_RESOURCES
;
897 ASSERT (!IsListEmpty (SubtasksPtr
));
899 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
900 for ( Link
= GetFirstNode (SubtasksPtr
), NextLink
= GetNextNode (SubtasksPtr
, Link
)
901 ; !IsNull (SubtasksPtr
, Link
)
902 ; Link
= NextLink
, NextLink
= GetNextNode (SubtasksPtr
, NextLink
)
905 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
906 Subtask
->Task
= Task
;
907 SubtaskBlocking
= Subtask
->Blocking
;
909 ASSERT ((Subtask
->Length
% Media
->BlockSize
== 0) || (Subtask
->Length
< Media
->BlockSize
));
911 if (Subtask
->Write
) {
915 if (Subtask
->WorkingBuffer
!= NULL
) {
917 // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
919 CopyMem (Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Buffer
, Subtask
->Length
);
922 if (SubtaskBlocking
) {
923 Status
= BlockIo
->WriteBlocks (
927 (Subtask
->Length
% Media
->BlockSize
== 0) ? Subtask
->Length
: Media
->BlockSize
,
928 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
931 Status
= BlockIo2
->WriteBlocksEx (
935 &Subtask
->BlockIo2Token
,
936 (Subtask
->Length
% Media
->BlockSize
== 0) ? Subtask
->Length
: Media
->BlockSize
,
937 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
944 if (SubtaskBlocking
) {
945 Status
= BlockIo
->ReadBlocks (
949 (Subtask
->Length
% Media
->BlockSize
== 0) ? Subtask
->Length
: Media
->BlockSize
,
950 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
952 if (!EFI_ERROR (Status
) && (Subtask
->WorkingBuffer
!= NULL
)) {
953 CopyMem (Subtask
->Buffer
, Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Length
);
956 Status
= BlockIo2
->ReadBlocksEx (
960 &Subtask
->BlockIo2Token
,
961 (Subtask
->Length
% Media
->BlockSize
== 0) ? Subtask
->Length
: Media
->BlockSize
,
962 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
967 if (SubtaskBlocking
|| EFI_ERROR (Status
)) {
969 // Make sure the subtask list only contains non-blocking subtasks.
970 // Remove failed non-blocking subtasks as well because the callback won't be called.
972 DiskIoDestroySubtask (Instance
, Subtask
);
975 if (EFI_ERROR (Status
)) {
980 gBS
->RaiseTPL (TPL_NOTIFY
);
983 // Remove all the remaining subtasks when failure.
984 // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
986 if (EFI_ERROR (Status
)) {
987 while (!IsNull (SubtasksPtr
, NextLink
)) {
988 Subtask
= CR (NextLink
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
989 NextLink
= DiskIoDestroySubtask (Instance
, Subtask
);
994 // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
995 // so the subtasks list might be empty at this point.
997 if (!Blocking
&& IsListEmpty (SubtasksPtr
)) {
998 EfiAcquireLock (&Instance
->TaskQueueLock
);
999 RemoveEntryList (&Task
->Link
);
1000 EfiReleaseLock (&Instance
->TaskQueueLock
);
1002 if (!EFI_ERROR (Status
) && (Task
->Token
!= NULL
)) {
1004 // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
1005 // It it's not, that means the non-blocking request was downgraded to blocking request.
1007 DEBUG ((DEBUG_VERBOSE
, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
1008 Task
->Token
->TransactionStatus
= Status
;
1009 gBS
->SignalEvent (Task
->Token
->Event
);
1015 gBS
->RestoreTPL (OldTpl
);
1021 Reads a specified number of bytes from a device.
1023 @param This Indicates a pointer to the calling context.
1024 @param MediaId ID of the medium to be read.
1025 @param Offset The starting byte offset on the logical block I/O device to read from.
1026 @param Token A pointer to the token associated with the transaction.
1027 If this field is NULL, synchronous/blocking IO is performed.
1028 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
1029 @param Buffer A pointer to the destination buffer for the data.
1030 The caller is responsible either having implicit or explicit ownership of the buffer.
1032 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device.
1033 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1034 Event will be signaled upon completion.
1035 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1036 @retval EFI_NO_MEDIA There is no medium in the device.
1037 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
1038 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
1039 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1045 IN EFI_DISK_IO2_PROTOCOL
*This
,
1048 IN OUT EFI_DISK_IO2_TOKEN
*Token
,
1049 IN UINTN BufferSize
,
1053 return DiskIo2ReadWriteDisk (
1054 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
),
1065 Writes a specified number of bytes to a device.
1067 @param This Indicates a pointer to the calling context.
1068 @param MediaId ID of the medium to be written.
1069 @param Offset The starting byte offset on the logical block I/O device to write to.
1070 @param Token A pointer to the token associated with the transaction.
1071 If this field is NULL, synchronous/blocking IO is performed.
1072 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
1073 @param Buffer A pointer to the buffer containing the data to be written.
1075 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to the device.
1076 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1077 Event will be signaled upon completion.
1078 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1079 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
1080 @retval EFI_NO_MEDIA There is no medium in the device.
1081 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
1082 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
1083 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1088 DiskIo2WriteDiskEx (
1089 IN EFI_DISK_IO2_PROTOCOL
*This
,
1092 IN OUT EFI_DISK_IO2_TOKEN
*Token
,
1093 IN UINTN BufferSize
,
1097 return DiskIo2ReadWriteDisk (
1098 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
),
1109 The callback for the BlockIo2 FlushBlocksEx.
1110 @param Event Event whose notification function is being invoked.
1111 @param Context The pointer to the notification function's context,
1112 which points to the DISK_IO2_FLUSH_TASK instance.
1116 DiskIo2OnFlushComplete (
1121 DISK_IO2_FLUSH_TASK
*Task
;
1123 gBS
->CloseEvent (Event
);
1125 Task
= (DISK_IO2_FLUSH_TASK
*)Context
;
1126 ASSERT (Task
->Signature
== DISK_IO2_FLUSH_TASK_SIGNATURE
);
1127 Task
->Token
->TransactionStatus
= Task
->BlockIo2Token
.TransactionStatus
;
1128 gBS
->SignalEvent (Task
->Token
->Event
);
1134 Flushes all modified data to the physical device.
1136 @param This Indicates a pointer to the calling context.
1137 @param Token A pointer to the token associated with the transaction.
1138 If this field is NULL, synchronous/blocking IO is performed.
1140 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device.
1141 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1142 Event will be signaled upon completion.
1143 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1144 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
1145 @retval EFI_NO_MEDIA There is no medium in the device.
1146 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1150 DiskIo2FlushDiskEx (
1151 IN EFI_DISK_IO2_PROTOCOL
*This
,
1152 IN OUT EFI_DISK_IO2_TOKEN
*Token
1156 DISK_IO2_FLUSH_TASK
*Task
;
1157 DISK_IO_PRIVATE_DATA
*Private
;
1159 Private
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
);
1161 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1162 Task
= AllocatePool (sizeof (DISK_IO2_FLUSH_TASK
));
1164 return EFI_OUT_OF_RESOURCES
;
1167 Status
= gBS
->CreateEvent (
1170 DiskIo2OnFlushComplete
,
1172 &Task
->BlockIo2Token
.Event
1174 if (EFI_ERROR (Status
)) {
1179 Task
->Signature
= DISK_IO2_FLUSH_TASK_SIGNATURE
;
1180 Task
->Token
= Token
;
1181 Status
= Private
->BlockIo2
->FlushBlocksEx (Private
->BlockIo2
, &Task
->BlockIo2Token
);
1182 if (EFI_ERROR (Status
)) {
1183 gBS
->CloseEvent (Task
->BlockIo2Token
.Event
);
1187 Status
= Private
->BlockIo2
->FlushBlocksEx (Private
->BlockIo2
, NULL
);
1194 Read BufferSize bytes from Offset into Buffer.
1195 Reads may support reads that are not aligned on
1196 sector boundaries. There are three cases:
1197 UnderRun - The first byte is not on a sector boundary or the read request is
1198 less than a sector in length.
1199 Aligned - A read of N contiguous sectors.
1200 OverRun - The last byte is not on a sector boundary.
1202 @param This Protocol instance pointer.
1203 @param MediaId Id of the media, changes every time the media is replaced.
1204 @param Offset The starting byte offset to read from
1205 @param BufferSize Size of Buffer
1206 @param Buffer Buffer containing read data
1208 @retval EFI_SUCCESS The data was read correctly from the device.
1209 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
1210 @retval EFI_NO_MEDIA There is no media in the device.
1211 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1212 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
1213 valid for the device.
1219 IN EFI_DISK_IO_PROTOCOL
*This
,
1222 IN UINTN BufferSize
,
1226 return DiskIo2ReadWriteDisk (
1227 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This
),
1238 Writes BufferSize bytes from Buffer into Offset.
1239 Writes may require a read modify write to support writes that are not
1240 aligned on sector boundaries. There are three cases:
1241 UnderRun - The first byte is not on a sector boundary or the write request
1242 is less than a sector in length. Read modify write is required.
1243 Aligned - A write of N contiguous sectors.
1244 OverRun - The last byte is not on a sector boundary. Read modified write
1247 @param This Protocol instance pointer.
1248 @param MediaId Id of the media, changes every time the media is replaced.
1249 @param Offset The starting byte offset to read from
1250 @param BufferSize Size of Buffer
1251 @param Buffer Buffer containing read data
1253 @retval EFI_SUCCESS The data was written correctly to the device.
1254 @retval EFI_WRITE_PROTECTED The device can not be written to.
1255 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1256 @retval EFI_NO_MEDIA There is no media in the device.
1257 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1258 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
1259 valid for the device.
1265 IN EFI_DISK_IO_PROTOCOL
*This
,
1268 IN UINTN BufferSize
,
1272 return DiskIo2ReadWriteDisk (
1273 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This
),
1284 The user Entry Point for module DiskIo. The user code starts with this function.
1286 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1287 @param[in] SystemTable A pointer to the EFI System Table.
1289 @retval EFI_SUCCESS The entry point is executed successfully.
1290 @retval other Some error occurs when executing this entry point.
1296 IN EFI_HANDLE ImageHandle
,
1297 IN EFI_SYSTEM_TABLE
*SystemTable
1303 // Install driver model protocol(s).
1305 Status
= EfiLibInstallDriverBindingComponentName2 (
1308 &gDiskIoDriverBinding
,
1310 &gDiskIoComponentName
,
1311 &gDiskIoComponentName2
1313 ASSERT_EFI_ERROR (Status
);