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
,
104 Start this driver on ControllerHandle by opening a Block IO protocol and
105 installing a Disk IO protocol on ControllerHandle.
107 @param This Protocol instance pointer.
108 @param ControllerHandle Handle of device to bind driver to
109 @param RemainingDevicePath Optional parameter use to pick a specific child
112 @retval EFI_SUCCESS This driver is added to ControllerHandle
113 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
114 @retval other This driver does not support this device
119 DiskIoDriverBindingStart (
120 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
121 IN EFI_HANDLE ControllerHandle
,
122 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
126 DISK_IO_PRIVATE_DATA
*Instance
;
131 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
134 // Connect to the Block IO and Block IO2 interface on ControllerHandle.
136 Status
= gBS
->OpenProtocol (
138 &gEfiBlockIoProtocolGuid
,
139 (VOID
**) &gDiskIoPrivateDataTemplate
.BlockIo
,
140 This
->DriverBindingHandle
,
142 EFI_OPEN_PROTOCOL_BY_DRIVER
144 if (EFI_ERROR (Status
)) {
148 Status
= gBS
->OpenProtocol (
150 &gEfiBlockIo2ProtocolGuid
,
151 (VOID
**) &gDiskIoPrivateDataTemplate
.BlockIo2
,
152 This
->DriverBindingHandle
,
154 EFI_OPEN_PROTOCOL_BY_DRIVER
156 if (EFI_ERROR (Status
)) {
157 gDiskIoPrivateDataTemplate
.BlockIo2
= NULL
;
161 // Initialize the Disk IO device instance.
163 Instance
= AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA
), &gDiskIoPrivateDataTemplate
);
164 if (Instance
== NULL
) {
165 Status
= EFI_OUT_OF_RESOURCES
;
170 // The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.
172 ASSERT ((Instance
->BlockIo2
== NULL
) ||
173 ((Instance
->BlockIo
->Media
->IoAlign
== Instance
->BlockIo2
->Media
->IoAlign
) &&
174 (Instance
->BlockIo
->Media
->BlockSize
== Instance
->BlockIo2
->Media
->BlockSize
)
177 InitializeListHead (&Instance
->TaskQueue
);
178 EfiInitializeLock (&Instance
->TaskQueueLock
, TPL_NOTIFY
);
179 Instance
->SharedWorkingBuffer
= AllocateAlignedPages (
180 EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum
) * Instance
->BlockIo
->Media
->BlockSize
),
181 Instance
->BlockIo
->Media
->IoAlign
183 if (Instance
->SharedWorkingBuffer
== NULL
) {
184 Status
= EFI_OUT_OF_RESOURCES
;
189 // Install protocol interfaces for the Disk IO device.
191 if (Instance
->BlockIo2
!= NULL
) {
192 Status
= gBS
->InstallMultipleProtocolInterfaces (
194 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIo
,
195 &gEfiDiskIo2ProtocolGuid
, &Instance
->DiskIo2
,
199 Status
= gBS
->InstallMultipleProtocolInterfaces (
201 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIo
,
207 if (EFI_ERROR (Status
)) {
208 if (Instance
!= NULL
&& Instance
->SharedWorkingBuffer
!= NULL
) {
210 Instance
->SharedWorkingBuffer
,
211 EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum
) * Instance
->BlockIo
->Media
->BlockSize
)
215 if (Instance
!= NULL
) {
221 &gEfiBlockIoProtocolGuid
,
222 This
->DriverBindingHandle
,
228 gBS
->RestoreTPL (OldTpl
);
233 Stop this driver on ControllerHandle by removing Disk IO protocol and closing
234 the Block IO protocol on ControllerHandle.
236 @param This Protocol instance pointer.
237 @param ControllerHandle Handle of device to stop driver on
238 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
239 children is zero stop the entire bus driver.
240 @param ChildHandleBuffer List of Child Handles to Stop.
242 @retval EFI_SUCCESS This driver is removed ControllerHandle
243 @retval other This driver was not removed from this device
248 DiskIoDriverBindingStop (
249 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
250 IN EFI_HANDLE ControllerHandle
,
251 IN UINTN NumberOfChildren
,
252 IN EFI_HANDLE
*ChildHandleBuffer
256 EFI_DISK_IO_PROTOCOL
*DiskIo
;
257 EFI_DISK_IO2_PROTOCOL
*DiskIo2
;
258 DISK_IO_PRIVATE_DATA
*Instance
;
262 // Get our context back.
264 Status
= gBS
->OpenProtocol (
266 &gEfiDiskIoProtocolGuid
,
268 This
->DriverBindingHandle
,
270 EFI_OPEN_PROTOCOL_GET_PROTOCOL
272 if (EFI_ERROR (Status
)) {
275 Status
= gBS
->OpenProtocol (
277 &gEfiDiskIo2ProtocolGuid
,
279 This
->DriverBindingHandle
,
281 EFI_OPEN_PROTOCOL_GET_PROTOCOL
283 if (EFI_ERROR (Status
)) {
287 Instance
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo
);
289 if (DiskIo2
!= NULL
) {
291 // Call BlockIo2::Reset() to terminate any in-flight non-blocking I/O requests
293 ASSERT (Instance
->BlockIo2
!= NULL
);
294 Status
= Instance
->BlockIo2
->Reset (Instance
->BlockIo2
, FALSE
);
295 if (EFI_ERROR (Status
)) {
298 Status
= gBS
->UninstallMultipleProtocolInterfaces (
300 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIo
,
301 &gEfiDiskIo2ProtocolGuid
, &Instance
->DiskIo2
,
305 Status
= gBS
->UninstallMultipleProtocolInterfaces (
307 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIo
,
311 if (!EFI_ERROR (Status
)) {
314 EfiAcquireLock (&Instance
->TaskQueueLock
);
315 AllTaskDone
= IsListEmpty (&Instance
->TaskQueue
);
316 EfiReleaseLock (&Instance
->TaskQueueLock
);
317 } while (!AllTaskDone
);
320 Instance
->SharedWorkingBuffer
,
321 EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum
) * Instance
->BlockIo
->Media
->BlockSize
)
324 Status
= gBS
->CloseProtocol (
326 &gEfiBlockIoProtocolGuid
,
327 This
->DriverBindingHandle
,
330 ASSERT_EFI_ERROR (Status
);
331 if (DiskIo2
!= NULL
) {
332 Status
= gBS
->CloseProtocol (
334 &gEfiBlockIo2ProtocolGuid
,
335 This
->DriverBindingHandle
,
338 ASSERT_EFI_ERROR (Status
);
349 Destroy the sub task.
351 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
352 @param Subtask Subtask.
354 @return LIST_ENTRY * Pointer to the next link of subtask.
357 DiskIoDestroySubtask (
358 IN DISK_IO_PRIVATE_DATA
*Instance
,
359 IN DISK_IO_SUBTASK
*Subtask
364 if (Subtask
->Task
!= NULL
) {
365 EfiAcquireLock (&Subtask
->Task
->SubtasksLock
);
367 Link
= RemoveEntryList (&Subtask
->Link
);
368 if (Subtask
->Task
!= NULL
) {
369 EfiReleaseLock (&Subtask
->Task
->SubtasksLock
);
372 if (!Subtask
->Blocking
) {
373 if (Subtask
->WorkingBuffer
!= NULL
) {
375 Subtask
->WorkingBuffer
,
376 Subtask
->Length
< Instance
->BlockIo
->Media
->BlockSize
377 ? EFI_SIZE_TO_PAGES (Instance
->BlockIo
->Media
->BlockSize
)
378 : EFI_SIZE_TO_PAGES (Subtask
->Length
)
381 if (Subtask
->BlockIo2Token
.Event
!= NULL
) {
382 gBS
->CloseEvent (Subtask
->BlockIo2Token
.Event
);
391 The callback for the BlockIo2 ReadBlocksEx/WriteBlocksEx.
392 @param Event Event whose notification function is being invoked.
393 @param Context The pointer to the notification function's context,
394 which points to the DISK_IO_SUBTASK instance.
398 DiskIo2OnReadWriteComplete (
403 DISK_IO_SUBTASK
*Subtask
;
405 EFI_STATUS TransactionStatus
;
406 DISK_IO_PRIVATE_DATA
*Instance
;
408 Subtask
= (DISK_IO_SUBTASK
*) Context
;
409 TransactionStatus
= Subtask
->BlockIo2Token
.TransactionStatus
;
410 Task
= Subtask
->Task
;
411 Instance
= Task
->Instance
;
413 ASSERT (Subtask
->Signature
== DISK_IO_SUBTASK_SIGNATURE
);
414 ASSERT (Instance
->Signature
== DISK_IO_PRIVATE_DATA_SIGNATURE
);
415 ASSERT (Task
->Signature
== DISK_IO2_TASK_SIGNATURE
);
417 if ((Subtask
->WorkingBuffer
!= NULL
) && !EFI_ERROR (TransactionStatus
) &&
418 (Task
->Token
!= NULL
) && !Subtask
->Write
420 CopyMem (Subtask
->Buffer
, Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Length
);
423 DiskIoDestroySubtask (Instance
, Subtask
);
425 if (EFI_ERROR (TransactionStatus
) || IsListEmpty (&Task
->Subtasks
)) {
426 if (Task
->Token
!= NULL
) {
428 // Signal error status once the subtask is failed.
429 // Or signal the last status once the last subtask is finished.
431 Task
->Token
->TransactionStatus
= TransactionStatus
;
432 gBS
->SignalEvent (Task
->Token
->Event
);
435 // Mark token to NULL indicating the Task is a dead task.
445 @param Write TRUE: Write request; FALSE: Read request.
446 @param Lba The starting logical block address to read from on the device.
447 @param Offset The starting byte offset to read from the LBA.
448 @param Length The number of bytes to read from the device.
449 @param WorkingBuffer The aligned buffer to hold the data for reading or writing.
450 @param Buffer The buffer to hold the data for reading or writing.
451 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
453 @return A pointer to the created subtask.
456 DiskIoCreateSubtask (
461 IN VOID
*WorkingBuffer
, OPTIONAL
466 DISK_IO_SUBTASK
*Subtask
;
469 Subtask
= AllocateZeroPool (sizeof (DISK_IO_SUBTASK
));
470 if (Subtask
== NULL
) {
473 Subtask
->Signature
= DISK_IO_SUBTASK_SIGNATURE
;
474 Subtask
->Write
= Write
;
476 Subtask
->Offset
= Offset
;
477 Subtask
->Length
= Length
;
478 Subtask
->WorkingBuffer
= WorkingBuffer
;
479 Subtask
->Buffer
= Buffer
;
480 Subtask
->Blocking
= Blocking
;
482 Status
= gBS
->CreateEvent (
485 DiskIo2OnReadWriteComplete
,
487 &Subtask
->BlockIo2Token
.Event
489 if (EFI_ERROR (Status
)) {
496 " %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
497 Write
? 'W': 'R', Lba
, Offset
, Length
, WorkingBuffer
, Buffer
504 Create the subtask list.
506 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
507 @param Write TRUE: Write request; FALSE: Read request.
508 @param Offset The starting byte offset to read from the device.
509 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
510 @param Buffer A pointer to the buffer for the data.
511 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
512 @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing.
513 @param Subtasks The subtask list header.
515 @retval TRUE The subtask list is created successfully.
516 @retval FALSE The subtask list is not created.
519 DiskIoCreateSubtaskList (
520 IN DISK_IO_PRIVATE_DATA
*Instance
,
526 IN VOID
*SharedWorkingBuffer
,
527 IN OUT LIST_ENTRY
*Subtasks
538 UINTN DataBufferSize
;
539 DISK_IO_SUBTASK
*Subtask
;
543 DEBUG ((EFI_D_BLKIO
, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset
, BufferSize
, Buffer
));
545 BlockSize
= Instance
->BlockIo
->Media
->BlockSize
;
546 IoAlign
= Instance
->BlockIo
->Media
->IoAlign
;
551 Lba
= DivU64x32Remainder (Offset
, BlockSize
, &UnderRun
);
552 BufferPtr
= (UINT8
*) Buffer
;
555 // Special handling for zero BufferSize
557 if (BufferSize
== 0) {
558 Subtask
= DiskIoCreateSubtask (Write
, Lba
, UnderRun
, 0, NULL
, BufferPtr
, Blocking
);
559 if (Subtask
== NULL
) {
562 InsertTailList (Subtasks
, &Subtask
->Link
);
567 Length
= MIN (BlockSize
- UnderRun
, BufferSize
);
569 WorkingBuffer
= SharedWorkingBuffer
;
571 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize
), IoAlign
);
572 if (WorkingBuffer
== NULL
) {
578 // A half write operation can be splitted to a blocking block-read and half write operation
579 // This can simplify the sub task processing logic
581 Subtask
= DiskIoCreateSubtask (FALSE
, Lba
, 0, BlockSize
, NULL
, WorkingBuffer
, TRUE
);
582 if (Subtask
== NULL
) {
585 InsertTailList (Subtasks
, &Subtask
->Link
);
588 Subtask
= DiskIoCreateSubtask (Write
, Lba
, UnderRun
, Length
, WorkingBuffer
, BufferPtr
, Blocking
);
589 if (Subtask
== NULL
) {
592 InsertTailList (Subtasks
, &Subtask
->Link
);
596 BufferSize
-= Length
;
600 OverRunLba
= Lba
+ DivU64x32Remainder (BufferSize
, BlockSize
, &OverRun
);
601 BufferSize
-= OverRun
;
605 WorkingBuffer
= SharedWorkingBuffer
;
607 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize
), IoAlign
);
608 if (WorkingBuffer
== NULL
) {
614 // A half write operation can be splitted to a blocking block-read and half write operation
615 // This can simplify the sub task processing logic
617 Subtask
= DiskIoCreateSubtask (FALSE
, OverRunLba
, 0, BlockSize
, NULL
, WorkingBuffer
, TRUE
);
618 if (Subtask
== NULL
) {
621 InsertTailList (Subtasks
, &Subtask
->Link
);
624 Subtask
= DiskIoCreateSubtask (Write
, OverRunLba
, 0, OverRun
, WorkingBuffer
, BufferPtr
+ BufferSize
, Blocking
);
625 if (Subtask
== NULL
) {
628 InsertTailList (Subtasks
, &Subtask
->Link
);
631 if (OverRunLba
> Lba
) {
633 // If the DiskIo maps directly to a BlockIo device do the read.
635 if (ALIGN_POINTER (BufferPtr
, IoAlign
) == BufferPtr
) {
636 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, BufferSize
, NULL
, BufferPtr
, Blocking
);
637 if (Subtask
== NULL
) {
640 InsertTailList (Subtasks
, &Subtask
->Link
);
642 BufferPtr
+= BufferSize
;
643 Offset
+= BufferSize
;
644 BufferSize
-= BufferSize
;
649 // Use the allocated buffer instead of the original buffer
650 // to avoid alignment issue.
652 for (; Lba
< OverRunLba
; Lba
+= PcdGet32 (PcdDiskIoDataBufferBlockNum
)) {
653 DataBufferSize
= MIN (BufferSize
, PcdGet32 (PcdDiskIoDataBufferBlockNum
) * BlockSize
);
655 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, DataBufferSize
, SharedWorkingBuffer
, BufferPtr
, Blocking
);
656 if (Subtask
== NULL
) {
659 InsertTailList (Subtasks
, &Subtask
->Link
);
661 BufferPtr
+= DataBufferSize
;
662 Offset
+= DataBufferSize
;
663 BufferSize
-= DataBufferSize
;
666 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), IoAlign
);
667 if (WorkingBuffer
== NULL
) {
669 // If there is not enough memory, downgrade to blocking access
671 DEBUG ((EFI_D_VERBOSE
, "DiskIo: No enough memory so downgrade to blocking access\n"));
672 if (!DiskIoCreateSubtaskList (Instance
, Write
, Offset
, BufferSize
, BufferPtr
, TRUE
, SharedWorkingBuffer
, Subtasks
)) {
676 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, BufferSize
, WorkingBuffer
, BufferPtr
, Blocking
);
677 if (Subtask
== NULL
) {
680 InsertTailList (Subtasks
, &Subtask
->Link
);
683 BufferPtr
+= BufferSize
;
684 Offset
+= BufferSize
;
685 BufferSize
-= BufferSize
;
690 ASSERT (BufferSize
== 0);
696 // Remove all the subtasks.
698 for (Link
= GetFirstNode (Subtasks
); !IsNull (Subtasks
, Link
); ) {
699 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
700 Link
= DiskIoDestroySubtask (Instance
, Subtask
);
706 Terminate outstanding asynchronous requests to a device.
708 @param This Indicates a pointer to the calling context.
710 @retval EFI_SUCCESS All outstanding requests were successfully terminated.
711 @retval EFI_DEVICE_ERROR The device reported an error while performing the cancel
717 IN EFI_DISK_IO2_PROTOCOL
*This
720 DISK_IO_PRIVATE_DATA
*Instance
;
724 Instance
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
);
726 EfiAcquireLock (&Instance
->TaskQueueLock
);
728 for (Link
= GetFirstNode (&Instance
->TaskQueue
)
729 ; !IsNull (&Instance
->TaskQueue
, Link
)
730 ; Link
= GetNextNode (&Instance
->TaskQueue
, Link
)
732 Task
= CR (Link
, DISK_IO2_TASK
, Link
, DISK_IO2_TASK_SIGNATURE
);
734 if (Task
->Token
!= NULL
) {
735 Task
->Token
->TransactionStatus
= EFI_ABORTED
;
736 gBS
->SignalEvent (Task
->Token
->Event
);
738 // Set Token to NULL so that the further BlockIo2 responses will be ignored
744 EfiReleaseLock (&Instance
->TaskQueueLock
);
750 Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks.
752 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
754 @retval TRUE The Instance->TaskQueue is empty after the completed tasks are removed.
755 @retval FALSE The Instance->TaskQueue is not empty after the completed tasks are removed.
758 DiskIo2RemoveCompletedTask (
759 IN DISK_IO_PRIVATE_DATA
*Instance
768 EfiAcquireLock (&Instance
->TaskQueueLock
);
769 for (Link
= GetFirstNode (&Instance
->TaskQueue
); !IsNull (&Instance
->TaskQueue
, Link
); ) {
770 Task
= CR (Link
, DISK_IO2_TASK
, Link
, DISK_IO2_TASK_SIGNATURE
);
771 if (IsListEmpty (&Task
->Subtasks
)) {
772 Link
= RemoveEntryList (&Task
->Link
);
773 ASSERT (Task
->Token
== NULL
);
776 Link
= GetNextNode (&Instance
->TaskQueue
, Link
);
780 EfiReleaseLock (&Instance
->TaskQueueLock
);
786 Common routine to access the disk.
788 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
789 @param Write TRUE: Write operation; FALSE: Read operation.
790 @param MediaId ID of the medium to access.
791 @param Offset The starting byte offset on the logical block I/O device to access.
792 @param Token A pointer to the token associated with the transaction.
793 If this field is NULL, synchronous/blocking IO is performed.
794 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
795 @param Buffer A pointer to the destination buffer for the data.
796 The caller is responsible either having implicit or explicit ownership of the buffer.
799 DiskIo2ReadWriteDisk (
800 IN DISK_IO_PRIVATE_DATA
*Instance
,
804 IN EFI_DISK_IO2_TOKEN
*Token
,
810 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
811 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
812 EFI_BLOCK_IO_MEDIA
*Media
;
814 LIST_ENTRY
*NextLink
;
816 DISK_IO_SUBTASK
*Subtask
;
820 BOOLEAN SubtaskBlocking
;
821 LIST_ENTRY
*SubtasksPtr
;
824 BlockIo
= Instance
->BlockIo
;
825 BlockIo2
= Instance
->BlockIo2
;
826 Media
= BlockIo
->Media
;
827 Status
= EFI_SUCCESS
;
828 Blocking
= (BOOLEAN
) ((Token
== NULL
) || (Token
->Event
== NULL
));
832 // Wait till pending async task is completed.
834 while (!DiskIo2RemoveCompletedTask (Instance
));
836 SubtasksPtr
= &Subtasks
;
838 DiskIo2RemoveCompletedTask (Instance
);
839 Task
= AllocatePool (sizeof (DISK_IO2_TASK
));
841 return EFI_OUT_OF_RESOURCES
;
844 EfiAcquireLock (&Instance
->TaskQueueLock
);
845 InsertTailList (&Instance
->TaskQueue
, &Task
->Link
);
846 EfiReleaseLock (&Instance
->TaskQueueLock
);
848 Task
->Signature
= DISK_IO2_TASK_SIGNATURE
;
849 Task
->Instance
= Instance
;
851 EfiInitializeLock (&Task
->SubtasksLock
, TPL_NOTIFY
);
853 SubtasksPtr
= &Task
->Subtasks
;
856 InitializeListHead (SubtasksPtr
);
857 if (!DiskIoCreateSubtaskList (Instance
, Write
, Offset
, BufferSize
, Buffer
, Blocking
, Instance
->SharedWorkingBuffer
, SubtasksPtr
)) {
861 return EFI_OUT_OF_RESOURCES
;
863 ASSERT (!IsListEmpty (SubtasksPtr
));
865 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
866 for ( Link
= GetFirstNode (SubtasksPtr
), NextLink
= GetNextNode (SubtasksPtr
, Link
)
867 ; !IsNull (SubtasksPtr
, Link
)
868 ; Link
= NextLink
, NextLink
= GetNextNode (SubtasksPtr
, NextLink
)
870 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
871 Subtask
->Task
= Task
;
872 SubtaskBlocking
= Subtask
->Blocking
;
874 ASSERT ((Subtask
->Length
% Media
->BlockSize
== 0) || (Subtask
->Length
< Media
->BlockSize
));
876 if (Subtask
->Write
) {
880 if (Subtask
->WorkingBuffer
!= NULL
) {
882 // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
884 CopyMem (Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Buffer
, Subtask
->Length
);
887 if (SubtaskBlocking
) {
888 Status
= BlockIo
->WriteBlocks (
892 (Subtask
->Length
% Media
->BlockSize
== 0) ? Subtask
->Length
: Media
->BlockSize
,
893 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
896 Status
= BlockIo2
->WriteBlocksEx (
900 &Subtask
->BlockIo2Token
,
901 (Subtask
->Length
% Media
->BlockSize
== 0) ? Subtask
->Length
: Media
->BlockSize
,
902 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
910 if (SubtaskBlocking
) {
911 Status
= BlockIo
->ReadBlocks (
915 (Subtask
->Length
% Media
->BlockSize
== 0) ? Subtask
->Length
: Media
->BlockSize
,
916 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
918 if (!EFI_ERROR (Status
) && (Subtask
->WorkingBuffer
!= NULL
)) {
919 CopyMem (Subtask
->Buffer
, Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Length
);
922 Status
= BlockIo2
->ReadBlocksEx (
926 &Subtask
->BlockIo2Token
,
927 (Subtask
->Length
% Media
->BlockSize
== 0) ? Subtask
->Length
: Media
->BlockSize
,
928 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
933 if (SubtaskBlocking
|| EFI_ERROR (Status
)) {
935 // Make sure the subtask list only contains non-blocking subtasks.
936 // Remove failed non-blocking subtasks as well because the callback won't be called.
938 DiskIoDestroySubtask (Instance
, Subtask
);
941 if (EFI_ERROR (Status
)) {
946 gBS
->RaiseTPL (TPL_NOTIFY
);
949 // Remove all the remaining subtasks when failure.
950 // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
952 if (EFI_ERROR (Status
)) {
953 while (!IsNull (SubtasksPtr
, NextLink
)) {
954 Subtask
= CR (NextLink
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
955 NextLink
= DiskIoDestroySubtask (Instance
, Subtask
);
960 // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
961 // so the subtasks list might be empty at this point.
963 if (!Blocking
&& IsListEmpty (SubtasksPtr
)) {
964 EfiAcquireLock (&Instance
->TaskQueueLock
);
965 RemoveEntryList (&Task
->Link
);
966 EfiReleaseLock (&Instance
->TaskQueueLock
);
968 if (!EFI_ERROR (Status
) && (Task
->Token
!= NULL
)) {
970 // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
971 // It it's not, that means the non-blocking request was downgraded to blocking request.
973 DEBUG ((EFI_D_VERBOSE
, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
974 Task
->Token
->TransactionStatus
= Status
;
975 gBS
->SignalEvent (Task
->Token
->Event
);
981 gBS
->RestoreTPL (OldTpl
);
987 Reads a specified number of bytes from a device.
989 @param This Indicates a pointer to the calling context.
990 @param MediaId ID of the medium to be read.
991 @param Offset The starting byte offset on the logical block I/O device to read from.
992 @param Token A pointer to the token associated with the transaction.
993 If this field is NULL, synchronous/blocking IO is performed.
994 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
995 @param Buffer A pointer to the destination buffer for the data.
996 The caller is responsible either having implicit or explicit ownership of the buffer.
998 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device.
999 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1000 Event will be signaled upon completion.
1001 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1002 @retval EFI_NO_MEDIA There is no medium in the device.
1003 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
1004 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
1005 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1011 IN EFI_DISK_IO2_PROTOCOL
*This
,
1014 IN OUT EFI_DISK_IO2_TOKEN
*Token
,
1015 IN UINTN BufferSize
,
1019 return DiskIo2ReadWriteDisk (
1020 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
),
1021 FALSE
, MediaId
, Offset
, Token
, BufferSize
, (UINT8
*) Buffer
1026 Writes a specified number of bytes to a device.
1028 @param This Indicates a pointer to the calling context.
1029 @param MediaId ID of the medium to be written.
1030 @param Offset The starting byte offset on the logical block I/O device to write to.
1031 @param Token A pointer to the token associated with the transaction.
1032 If this field is NULL, synchronous/blocking IO is performed.
1033 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
1034 @param Buffer A pointer to the buffer containing the data to be written.
1036 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to the device.
1037 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1038 Event will be signaled upon completion.
1039 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1040 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
1041 @retval EFI_NO_MEDIA There is no medium in the device.
1042 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
1043 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
1044 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1049 DiskIo2WriteDiskEx (
1050 IN EFI_DISK_IO2_PROTOCOL
*This
,
1053 IN OUT EFI_DISK_IO2_TOKEN
*Token
,
1054 IN UINTN BufferSize
,
1058 return DiskIo2ReadWriteDisk (
1059 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
),
1060 TRUE
, MediaId
, Offset
, Token
, BufferSize
, (UINT8
*) Buffer
1065 The callback for the BlockIo2 FlushBlocksEx.
1066 @param Event Event whose notification function is being invoked.
1067 @param Context The pointer to the notification function's context,
1068 which points to the DISK_IO2_FLUSH_TASK instance.
1072 DiskIo2OnFlushComplete (
1077 DISK_IO2_FLUSH_TASK
*Task
;
1079 gBS
->CloseEvent (Event
);
1081 Task
= (DISK_IO2_FLUSH_TASK
*) Context
;
1082 ASSERT (Task
->Signature
== DISK_IO2_FLUSH_TASK_SIGNATURE
);
1083 Task
->Token
->TransactionStatus
= Task
->BlockIo2Token
.TransactionStatus
;
1084 gBS
->SignalEvent (Task
->Token
->Event
);
1090 Flushes all modified data to the physical device.
1092 @param This Indicates a pointer to the calling context.
1093 @param Token A pointer to the token associated with the transaction.
1094 If this field is NULL, synchronous/blocking IO is performed.
1096 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device.
1097 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1098 Event will be signaled upon completion.
1099 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1100 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
1101 @retval EFI_NO_MEDIA There is no medium in the device.
1102 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1106 DiskIo2FlushDiskEx (
1107 IN EFI_DISK_IO2_PROTOCOL
*This
,
1108 IN OUT EFI_DISK_IO2_TOKEN
*Token
1112 DISK_IO2_FLUSH_TASK
*Task
;
1113 DISK_IO_PRIVATE_DATA
*Private
;
1115 Private
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
);
1117 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1118 Task
= AllocatePool (sizeof (DISK_IO2_FLUSH_TASK
));
1120 return EFI_OUT_OF_RESOURCES
;
1123 Status
= gBS
->CreateEvent (
1126 DiskIo2OnFlushComplete
,
1128 &Task
->BlockIo2Token
.Event
1130 if (EFI_ERROR (Status
)) {
1134 Task
->Signature
= DISK_IO2_FLUSH_TASK_SIGNATURE
;
1135 Task
->Token
= Token
;
1136 Status
= Private
->BlockIo2
->FlushBlocksEx (Private
->BlockIo2
, &Task
->BlockIo2Token
);
1137 if (EFI_ERROR (Status
)) {
1138 gBS
->CloseEvent (Task
->BlockIo2Token
.Event
);
1142 Status
= Private
->BlockIo2
->FlushBlocksEx (Private
->BlockIo2
, NULL
);
1149 Read BufferSize bytes from Offset into Buffer.
1150 Reads may support reads that are not aligned on
1151 sector boundaries. There are three cases:
1152 UnderRun - The first byte is not on a sector boundary or the read request is
1153 less than a sector in length.
1154 Aligned - A read of N contiguous sectors.
1155 OverRun - The last byte is not on a sector boundary.
1157 @param This Protocol instance pointer.
1158 @param MediaId Id of the media, changes every time the media is replaced.
1159 @param Offset The starting byte offset to read from
1160 @param BufferSize Size of Buffer
1161 @param Buffer Buffer containing read data
1163 @retval EFI_SUCCESS The data was read correctly from the device.
1164 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
1165 @retval EFI_NO_MEDIA There is no media in the device.
1166 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1167 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
1168 valid for the device.
1174 IN EFI_DISK_IO_PROTOCOL
*This
,
1177 IN UINTN BufferSize
,
1181 return DiskIo2ReadWriteDisk (
1182 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This
),
1183 FALSE
, MediaId
, Offset
, NULL
, BufferSize
, (UINT8
*) Buffer
1189 Writes BufferSize bytes from Buffer into Offset.
1190 Writes may require a read modify write to support writes that are not
1191 aligned on sector boundaries. There are three cases:
1192 UnderRun - The first byte is not on a sector boundary or the write request
1193 is less than a sector in length. Read modify write is required.
1194 Aligned - A write of N contiguous sectors.
1195 OverRun - The last byte is not on a sector boundary. Read modified write
1198 @param This Protocol instance pointer.
1199 @param MediaId Id of the media, changes every time the media is replaced.
1200 @param Offset The starting byte offset to read from
1201 @param BufferSize Size of Buffer
1202 @param Buffer Buffer containing read data
1204 @retval EFI_SUCCESS The data was written correctly to the device.
1205 @retval EFI_WRITE_PROTECTED The device can not be written to.
1206 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1207 @retval EFI_NO_MEDIA There is no media in the device.
1208 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1209 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
1210 valid for the device.
1216 IN EFI_DISK_IO_PROTOCOL
*This
,
1219 IN UINTN BufferSize
,
1223 return DiskIo2ReadWriteDisk (
1224 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This
),
1225 TRUE
, MediaId
, Offset
, NULL
, BufferSize
, (UINT8
*) Buffer
1230 The user Entry Point for module DiskIo. The user code starts with this function.
1232 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1233 @param[in] SystemTable A pointer to the EFI System Table.
1235 @retval EFI_SUCCESS The entry point is executed successfully.
1236 @retval other Some error occurs when executing this entry point.
1242 IN EFI_HANDLE ImageHandle
,
1243 IN EFI_SYSTEM_TABLE
*SystemTable
1249 // Install driver model protocol(s).
1251 Status
= EfiLibInstallDriverBindingComponentName2 (
1254 &gDiskIoDriverBinding
,
1256 &gDiskIoComponentName
,
1257 &gDiskIoComponentName2
1259 ASSERT_EFI_ERROR (Status
);