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 - 2016, Intel Corporation. All rights reserved.<BR>
13 This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
26 // Driver binding protocol implementation for DiskIo driver.
28 EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding
= {
29 DiskIoDriverBindingSupported
,
30 DiskIoDriverBindingStart
,
31 DiskIoDriverBindingStop
,
38 // Template for DiskIo private data structure.
39 // The pointer to BlockIo protocol interface is assigned dynamically.
41 DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate
= {
42 DISK_IO_PRIVATE_DATA_SIGNATURE
,
44 EFI_DISK_IO_PROTOCOL_REVISION
,
49 EFI_DISK_IO2_PROTOCOL_REVISION
,
58 Test to see if this driver supports ControllerHandle.
60 @param This Protocol instance pointer.
61 @param ControllerHandle Handle of device to test
62 @param RemainingDevicePath Optional parameter use to pick a specific child
65 @retval EFI_SUCCESS This driver supports this device
66 @retval EFI_ALREADY_STARTED This driver is already running on this device
67 @retval other This driver does not support this device
72 DiskIoDriverBindingSupported (
73 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
74 IN EFI_HANDLE ControllerHandle
,
75 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
79 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
82 // Open the IO Abstraction(s) needed to perform the supported test.
84 Status
= gBS
->OpenProtocol (
86 &gEfiBlockIoProtocolGuid
,
88 This
->DriverBindingHandle
,
90 EFI_OPEN_PROTOCOL_BY_DRIVER
92 if (EFI_ERROR (Status
)) {
97 // Close the I/O Abstraction(s) used to perform the supported test.
101 &gEfiBlockIoProtocolGuid
,
102 This
->DriverBindingHandle
,
110 Start this driver on ControllerHandle by opening a Block IO protocol and
111 installing a Disk IO protocol on ControllerHandle.
113 @param This Protocol instance pointer.
114 @param ControllerHandle Handle of device to bind driver to
115 @param RemainingDevicePath Optional parameter use to pick a specific child
118 @retval EFI_SUCCESS This driver is added to ControllerHandle
119 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
120 @retval other This driver does not support this device
125 DiskIoDriverBindingStart (
126 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
127 IN EFI_HANDLE ControllerHandle
,
128 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
132 DISK_IO_PRIVATE_DATA
*Instance
;
137 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
140 // Connect to the Block IO and Block IO2 interface on ControllerHandle.
142 Status
= gBS
->OpenProtocol (
144 &gEfiBlockIoProtocolGuid
,
145 (VOID
**) &gDiskIoPrivateDataTemplate
.BlockIo
,
146 This
->DriverBindingHandle
,
148 EFI_OPEN_PROTOCOL_BY_DRIVER
150 if (EFI_ERROR (Status
)) {
154 Status
= gBS
->OpenProtocol (
156 &gEfiBlockIo2ProtocolGuid
,
157 (VOID
**) &gDiskIoPrivateDataTemplate
.BlockIo2
,
158 This
->DriverBindingHandle
,
160 EFI_OPEN_PROTOCOL_BY_DRIVER
162 if (EFI_ERROR (Status
)) {
163 gDiskIoPrivateDataTemplate
.BlockIo2
= NULL
;
167 // Initialize the Disk IO device instance.
169 Instance
= AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA
), &gDiskIoPrivateDataTemplate
);
170 if (Instance
== NULL
) {
171 Status
= EFI_OUT_OF_RESOURCES
;
176 // The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.
178 ASSERT ((Instance
->BlockIo2
== NULL
) ||
179 ((Instance
->BlockIo
->Media
->IoAlign
== Instance
->BlockIo2
->Media
->IoAlign
) &&
180 (Instance
->BlockIo
->Media
->BlockSize
== Instance
->BlockIo2
->Media
->BlockSize
)
183 InitializeListHead (&Instance
->TaskQueue
);
184 EfiInitializeLock (&Instance
->TaskQueueLock
, TPL_NOTIFY
);
185 Instance
->SharedWorkingBuffer
= AllocateAlignedPages (
186 EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum
) * Instance
->BlockIo
->Media
->BlockSize
),
187 Instance
->BlockIo
->Media
->IoAlign
189 if (Instance
->SharedWorkingBuffer
== NULL
) {
190 Status
= EFI_OUT_OF_RESOURCES
;
195 // Install protocol interfaces for the Disk IO device.
197 if (Instance
->BlockIo2
!= NULL
) {
198 Status
= gBS
->InstallMultipleProtocolInterfaces (
200 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIo
,
201 &gEfiDiskIo2ProtocolGuid
, &Instance
->DiskIo2
,
205 Status
= gBS
->InstallMultipleProtocolInterfaces (
207 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIo
,
213 if (EFI_ERROR (Status
)) {
214 if (Instance
!= NULL
&& Instance
->SharedWorkingBuffer
!= NULL
) {
216 Instance
->SharedWorkingBuffer
,
217 EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum
) * Instance
->BlockIo
->Media
->BlockSize
)
221 if (Instance
!= NULL
) {
227 &gEfiBlockIoProtocolGuid
,
228 This
->DriverBindingHandle
,
234 gBS
->RestoreTPL (OldTpl
);
239 Stop this driver on ControllerHandle by removing Disk IO protocol and closing
240 the Block IO protocol on ControllerHandle.
242 @param This Protocol instance pointer.
243 @param ControllerHandle Handle of device to stop driver on
244 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
245 children is zero stop the entire bus driver.
246 @param ChildHandleBuffer List of Child Handles to Stop.
248 @retval EFI_SUCCESS This driver is removed ControllerHandle
249 @retval other This driver was not removed from this device
254 DiskIoDriverBindingStop (
255 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
256 IN EFI_HANDLE ControllerHandle
,
257 IN UINTN NumberOfChildren
,
258 IN EFI_HANDLE
*ChildHandleBuffer
262 EFI_DISK_IO_PROTOCOL
*DiskIo
;
263 EFI_DISK_IO2_PROTOCOL
*DiskIo2
;
264 DISK_IO_PRIVATE_DATA
*Instance
;
268 // Get our context back.
270 Status
= gBS
->OpenProtocol (
272 &gEfiDiskIoProtocolGuid
,
274 This
->DriverBindingHandle
,
276 EFI_OPEN_PROTOCOL_GET_PROTOCOL
278 if (EFI_ERROR (Status
)) {
281 Status
= gBS
->OpenProtocol (
283 &gEfiDiskIo2ProtocolGuid
,
285 This
->DriverBindingHandle
,
287 EFI_OPEN_PROTOCOL_GET_PROTOCOL
289 if (EFI_ERROR (Status
)) {
293 Instance
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo
);
295 if (DiskIo2
!= NULL
) {
297 // Call BlockIo2::Reset() to terminate any in-flight non-blocking I/O requests
299 ASSERT (Instance
->BlockIo2
!= NULL
);
300 Status
= Instance
->BlockIo2
->Reset (Instance
->BlockIo2
, FALSE
);
301 if (EFI_ERROR (Status
)) {
304 Status
= gBS
->UninstallMultipleProtocolInterfaces (
306 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIo
,
307 &gEfiDiskIo2ProtocolGuid
, &Instance
->DiskIo2
,
311 Status
= gBS
->UninstallMultipleProtocolInterfaces (
313 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIo
,
317 if (!EFI_ERROR (Status
)) {
320 EfiAcquireLock (&Instance
->TaskQueueLock
);
321 AllTaskDone
= IsListEmpty (&Instance
->TaskQueue
);
322 EfiReleaseLock (&Instance
->TaskQueueLock
);
323 } while (!AllTaskDone
);
326 Instance
->SharedWorkingBuffer
,
327 EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum
) * Instance
->BlockIo
->Media
->BlockSize
)
330 Status
= gBS
->CloseProtocol (
332 &gEfiBlockIoProtocolGuid
,
333 This
->DriverBindingHandle
,
336 ASSERT_EFI_ERROR (Status
);
337 if (DiskIo2
!= NULL
) {
338 Status
= gBS
->CloseProtocol (
340 &gEfiBlockIo2ProtocolGuid
,
341 This
->DriverBindingHandle
,
344 ASSERT_EFI_ERROR (Status
);
355 Destroy the sub task.
357 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
358 @param Subtask Subtask.
360 @return LIST_ENTRY * Pointer to the next link of subtask.
363 DiskIoDestroySubtask (
364 IN DISK_IO_PRIVATE_DATA
*Instance
,
365 IN DISK_IO_SUBTASK
*Subtask
370 if (Subtask
->Task
!= NULL
) {
371 EfiAcquireLock (&Subtask
->Task
->SubtasksLock
);
373 Link
= RemoveEntryList (&Subtask
->Link
);
374 if (Subtask
->Task
!= NULL
) {
375 EfiReleaseLock (&Subtask
->Task
->SubtasksLock
);
378 if (!Subtask
->Blocking
) {
379 if (Subtask
->WorkingBuffer
!= NULL
) {
381 Subtask
->WorkingBuffer
,
382 Subtask
->Length
< Instance
->BlockIo
->Media
->BlockSize
383 ? EFI_SIZE_TO_PAGES (Instance
->BlockIo
->Media
->BlockSize
)
384 : EFI_SIZE_TO_PAGES (Subtask
->Length
)
387 if (Subtask
->BlockIo2Token
.Event
!= NULL
) {
388 gBS
->CloseEvent (Subtask
->BlockIo2Token
.Event
);
397 The callback for the BlockIo2 ReadBlocksEx/WriteBlocksEx.
398 @param Event Event whose notification function is being invoked.
399 @param Context The pointer to the notification function's context,
400 which points to the DISK_IO_SUBTASK instance.
404 DiskIo2OnReadWriteComplete (
409 DISK_IO_SUBTASK
*Subtask
;
411 EFI_STATUS TransactionStatus
;
412 DISK_IO_PRIVATE_DATA
*Instance
;
414 Subtask
= (DISK_IO_SUBTASK
*) Context
;
415 TransactionStatus
= Subtask
->BlockIo2Token
.TransactionStatus
;
416 Task
= Subtask
->Task
;
417 Instance
= Task
->Instance
;
419 ASSERT (Subtask
->Signature
== DISK_IO_SUBTASK_SIGNATURE
);
420 ASSERT (Instance
->Signature
== DISK_IO_PRIVATE_DATA_SIGNATURE
);
421 ASSERT (Task
->Signature
== DISK_IO2_TASK_SIGNATURE
);
423 if ((Subtask
->WorkingBuffer
!= NULL
) && !EFI_ERROR (TransactionStatus
) &&
424 (Task
->Token
!= NULL
) && !Subtask
->Write
426 CopyMem (Subtask
->Buffer
, Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Length
);
429 DiskIoDestroySubtask (Instance
, Subtask
);
431 if (EFI_ERROR (TransactionStatus
) || IsListEmpty (&Task
->Subtasks
)) {
432 if (Task
->Token
!= NULL
) {
434 // Signal error status once the subtask is failed.
435 // Or signal the last status once the last subtask is finished.
437 Task
->Token
->TransactionStatus
= TransactionStatus
;
438 gBS
->SignalEvent (Task
->Token
->Event
);
441 // Mark token to NULL indicating the Task is a dead task.
451 @param Write TRUE: Write request; FALSE: Read request.
452 @param Lba The starting logical block address to read from on the device.
453 @param Offset The starting byte offset to read from the LBA.
454 @param Length The number of bytes to read from the device.
455 @param WorkingBuffer The aligned buffer to hold the data for reading or writing.
456 @param Buffer The buffer to hold the data for reading or writing.
457 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
459 @return A pointer to the created subtask.
462 DiskIoCreateSubtask (
467 IN VOID
*WorkingBuffer
, OPTIONAL
472 DISK_IO_SUBTASK
*Subtask
;
475 Subtask
= AllocateZeroPool (sizeof (DISK_IO_SUBTASK
));
476 if (Subtask
== NULL
) {
479 Subtask
->Signature
= DISK_IO_SUBTASK_SIGNATURE
;
480 Subtask
->Write
= Write
;
482 Subtask
->Offset
= Offset
;
483 Subtask
->Length
= Length
;
484 Subtask
->WorkingBuffer
= WorkingBuffer
;
485 Subtask
->Buffer
= Buffer
;
486 Subtask
->Blocking
= Blocking
;
488 Status
= gBS
->CreateEvent (
491 DiskIo2OnReadWriteComplete
,
493 &Subtask
->BlockIo2Token
.Event
495 if (EFI_ERROR (Status
)) {
502 " %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
503 Write
? 'W': 'R', Lba
, Offset
, Length
, WorkingBuffer
, Buffer
510 Create the subtask list.
512 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
513 @param Write TRUE: Write request; FALSE: Read request.
514 @param Offset The starting byte offset to read from the device.
515 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
516 @param Buffer A pointer to the buffer for the data.
517 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
518 @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing.
519 @param Subtasks The subtask list header.
521 @retval TRUE The subtask list is created successfully.
522 @retval FALSE The subtask list is not created.
525 DiskIoCreateSubtaskList (
526 IN DISK_IO_PRIVATE_DATA
*Instance
,
532 IN VOID
*SharedWorkingBuffer
,
533 IN OUT LIST_ENTRY
*Subtasks
544 UINTN DataBufferSize
;
545 DISK_IO_SUBTASK
*Subtask
;
549 DEBUG ((EFI_D_BLKIO
, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset
, BufferSize
, Buffer
));
551 BlockSize
= Instance
->BlockIo
->Media
->BlockSize
;
552 IoAlign
= Instance
->BlockIo
->Media
->IoAlign
;
557 Lba
= DivU64x32Remainder (Offset
, BlockSize
, &UnderRun
);
558 BufferPtr
= (UINT8
*) Buffer
;
561 // Special handling for zero BufferSize
563 if (BufferSize
== 0) {
564 Subtask
= DiskIoCreateSubtask (Write
, Lba
, UnderRun
, 0, NULL
, BufferPtr
, Blocking
);
565 if (Subtask
== NULL
) {
568 InsertTailList (Subtasks
, &Subtask
->Link
);
573 Length
= MIN (BlockSize
- UnderRun
, BufferSize
);
575 WorkingBuffer
= SharedWorkingBuffer
;
577 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize
), IoAlign
);
578 if (WorkingBuffer
== NULL
) {
584 // A half write operation can be splitted to a blocking block-read and half write operation
585 // This can simplify the sub task processing logic
587 Subtask
= DiskIoCreateSubtask (FALSE
, Lba
, 0, BlockSize
, NULL
, WorkingBuffer
, TRUE
);
588 if (Subtask
== NULL
) {
591 InsertTailList (Subtasks
, &Subtask
->Link
);
594 Subtask
= DiskIoCreateSubtask (Write
, Lba
, UnderRun
, Length
, WorkingBuffer
, BufferPtr
, Blocking
);
595 if (Subtask
== NULL
) {
598 InsertTailList (Subtasks
, &Subtask
->Link
);
602 BufferSize
-= Length
;
606 OverRunLba
= Lba
+ DivU64x32Remainder (BufferSize
, BlockSize
, &OverRun
);
607 BufferSize
-= OverRun
;
611 WorkingBuffer
= SharedWorkingBuffer
;
613 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize
), IoAlign
);
614 if (WorkingBuffer
== NULL
) {
620 // A half write operation can be splitted to a blocking block-read and half write operation
621 // This can simplify the sub task processing logic
623 Subtask
= DiskIoCreateSubtask (FALSE
, OverRunLba
, 0, BlockSize
, NULL
, WorkingBuffer
, TRUE
);
624 if (Subtask
== NULL
) {
627 InsertTailList (Subtasks
, &Subtask
->Link
);
630 Subtask
= DiskIoCreateSubtask (Write
, OverRunLba
, 0, OverRun
, WorkingBuffer
, BufferPtr
+ BufferSize
, Blocking
);
631 if (Subtask
== NULL
) {
634 InsertTailList (Subtasks
, &Subtask
->Link
);
637 if (OverRunLba
> Lba
) {
639 // If the DiskIo maps directly to a BlockIo device do the read.
641 if (ALIGN_POINTER (BufferPtr
, IoAlign
) == BufferPtr
) {
642 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, BufferSize
, NULL
, BufferPtr
, Blocking
);
643 if (Subtask
== NULL
) {
646 InsertTailList (Subtasks
, &Subtask
->Link
);
648 BufferPtr
+= BufferSize
;
649 Offset
+= BufferSize
;
650 BufferSize
-= BufferSize
;
655 // Use the allocated buffer instead of the original buffer
656 // to avoid alignment issue.
658 for (; Lba
< OverRunLba
; Lba
+= PcdGet32 (PcdDiskIoDataBufferBlockNum
)) {
659 DataBufferSize
= MIN (BufferSize
, PcdGet32 (PcdDiskIoDataBufferBlockNum
) * BlockSize
);
661 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, DataBufferSize
, SharedWorkingBuffer
, BufferPtr
, Blocking
);
662 if (Subtask
== NULL
) {
665 InsertTailList (Subtasks
, &Subtask
->Link
);
667 BufferPtr
+= DataBufferSize
;
668 Offset
+= DataBufferSize
;
669 BufferSize
-= DataBufferSize
;
672 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), IoAlign
);
673 if (WorkingBuffer
== NULL
) {
675 // If there is not enough memory, downgrade to blocking access
677 DEBUG ((EFI_D_VERBOSE
, "DiskIo: No enough memory so downgrade to blocking access\n"));
678 if (!DiskIoCreateSubtaskList (Instance
, Write
, Offset
, BufferSize
, BufferPtr
, TRUE
, SharedWorkingBuffer
, Subtasks
)) {
682 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, BufferSize
, WorkingBuffer
, BufferPtr
, Blocking
);
683 if (Subtask
== NULL
) {
686 InsertTailList (Subtasks
, &Subtask
->Link
);
689 BufferPtr
+= BufferSize
;
690 Offset
+= BufferSize
;
691 BufferSize
-= BufferSize
;
696 ASSERT (BufferSize
== 0);
702 // Remove all the subtasks.
704 for (Link
= GetFirstNode (Subtasks
); !IsNull (Subtasks
, Link
); ) {
705 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
706 Link
= DiskIoDestroySubtask (Instance
, Subtask
);
712 Terminate outstanding asynchronous requests to a device.
714 @param This Indicates a pointer to the calling context.
716 @retval EFI_SUCCESS All outstanding requests were successfully terminated.
717 @retval EFI_DEVICE_ERROR The device reported an error while performing the cancel
723 IN EFI_DISK_IO2_PROTOCOL
*This
726 DISK_IO_PRIVATE_DATA
*Instance
;
730 Instance
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
);
732 EfiAcquireLock (&Instance
->TaskQueueLock
);
734 for (Link
= GetFirstNode (&Instance
->TaskQueue
)
735 ; !IsNull (&Instance
->TaskQueue
, Link
)
736 ; Link
= GetNextNode (&Instance
->TaskQueue
, Link
)
738 Task
= CR (Link
, DISK_IO2_TASK
, Link
, DISK_IO2_TASK_SIGNATURE
);
740 if (Task
->Token
!= NULL
) {
741 Task
->Token
->TransactionStatus
= EFI_ABORTED
;
742 gBS
->SignalEvent (Task
->Token
->Event
);
744 // Set Token to NULL so that the further BlockIo2 responses will be ignored
750 EfiReleaseLock (&Instance
->TaskQueueLock
);
756 Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks.
758 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
760 @retval TRUE The Instance->TaskQueue is empty after the completed tasks are removed.
761 @retval FALSE The Instance->TaskQueue is not empty after the completed tasks are removed.
764 DiskIo2RemoveCompletedTask (
765 IN DISK_IO_PRIVATE_DATA
*Instance
774 EfiAcquireLock (&Instance
->TaskQueueLock
);
775 for (Link
= GetFirstNode (&Instance
->TaskQueue
); !IsNull (&Instance
->TaskQueue
, Link
); ) {
776 Task
= CR (Link
, DISK_IO2_TASK
, Link
, DISK_IO2_TASK_SIGNATURE
);
777 if (IsListEmpty (&Task
->Subtasks
)) {
778 Link
= RemoveEntryList (&Task
->Link
);
779 ASSERT (Task
->Token
== NULL
);
782 Link
= GetNextNode (&Instance
->TaskQueue
, Link
);
786 EfiReleaseLock (&Instance
->TaskQueueLock
);
792 Common routine to access the disk.
794 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
795 @param Write TRUE: Write operation; FALSE: Read operation.
796 @param MediaId ID of the medium to access.
797 @param Offset The starting byte offset on the logical block I/O device to access.
798 @param Token A pointer to the token associated with the transaction.
799 If this field is NULL, synchronous/blocking IO is performed.
800 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
801 @param Buffer A pointer to the destination buffer for the data.
802 The caller is responsible either having implicit or explicit ownership of the buffer.
805 DiskIo2ReadWriteDisk (
806 IN DISK_IO_PRIVATE_DATA
*Instance
,
810 IN EFI_DISK_IO2_TOKEN
*Token
,
816 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
817 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
818 EFI_BLOCK_IO_MEDIA
*Media
;
820 LIST_ENTRY
*NextLink
;
822 DISK_IO_SUBTASK
*Subtask
;
826 BOOLEAN SubtaskBlocking
;
827 LIST_ENTRY
*SubtasksPtr
;
830 BlockIo
= Instance
->BlockIo
;
831 BlockIo2
= Instance
->BlockIo2
;
832 Media
= BlockIo
->Media
;
833 Status
= EFI_SUCCESS
;
834 Blocking
= (BOOLEAN
) ((Token
== NULL
) || (Token
->Event
== NULL
));
838 // Wait till pending async task is completed.
840 while (!DiskIo2RemoveCompletedTask (Instance
));
842 SubtasksPtr
= &Subtasks
;
844 DiskIo2RemoveCompletedTask (Instance
);
845 Task
= AllocatePool (sizeof (DISK_IO2_TASK
));
847 return EFI_OUT_OF_RESOURCES
;
850 EfiAcquireLock (&Instance
->TaskQueueLock
);
851 InsertTailList (&Instance
->TaskQueue
, &Task
->Link
);
852 EfiReleaseLock (&Instance
->TaskQueueLock
);
854 Task
->Signature
= DISK_IO2_TASK_SIGNATURE
;
855 Task
->Instance
= Instance
;
857 EfiInitializeLock (&Task
->SubtasksLock
, TPL_NOTIFY
);
859 SubtasksPtr
= &Task
->Subtasks
;
862 InitializeListHead (SubtasksPtr
);
863 if (!DiskIoCreateSubtaskList (Instance
, Write
, Offset
, BufferSize
, Buffer
, Blocking
, Instance
->SharedWorkingBuffer
, SubtasksPtr
)) {
867 return EFI_OUT_OF_RESOURCES
;
869 ASSERT (!IsListEmpty (SubtasksPtr
));
871 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
872 for ( Link
= GetFirstNode (SubtasksPtr
), NextLink
= GetNextNode (SubtasksPtr
, Link
)
873 ; !IsNull (SubtasksPtr
, Link
)
874 ; Link
= NextLink
, NextLink
= GetNextNode (SubtasksPtr
, NextLink
)
876 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
877 Subtask
->Task
= Task
;
878 SubtaskBlocking
= Subtask
->Blocking
;
880 ASSERT ((Subtask
->Length
% Media
->BlockSize
== 0) || (Subtask
->Length
< Media
->BlockSize
));
882 if (Subtask
->Write
) {
886 if (Subtask
->WorkingBuffer
!= NULL
) {
888 // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
890 CopyMem (Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Buffer
, Subtask
->Length
);
893 if (SubtaskBlocking
) {
894 Status
= BlockIo
->WriteBlocks (
898 (Subtask
->Length
% Media
->BlockSize
== 0) ? Subtask
->Length
: Media
->BlockSize
,
899 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
902 Status
= BlockIo2
->WriteBlocksEx (
906 &Subtask
->BlockIo2Token
,
907 (Subtask
->Length
% Media
->BlockSize
== 0) ? Subtask
->Length
: Media
->BlockSize
,
908 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
916 if (SubtaskBlocking
) {
917 Status
= BlockIo
->ReadBlocks (
921 (Subtask
->Length
% Media
->BlockSize
== 0) ? Subtask
->Length
: Media
->BlockSize
,
922 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
924 if (!EFI_ERROR (Status
) && (Subtask
->WorkingBuffer
!= NULL
)) {
925 CopyMem (Subtask
->Buffer
, Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Length
);
928 Status
= BlockIo2
->ReadBlocksEx (
932 &Subtask
->BlockIo2Token
,
933 (Subtask
->Length
% Media
->BlockSize
== 0) ? Subtask
->Length
: Media
->BlockSize
,
934 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
939 if (SubtaskBlocking
|| EFI_ERROR (Status
)) {
941 // Make sure the subtask list only contains non-blocking subtasks.
942 // Remove failed non-blocking subtasks as well because the callback won't be called.
944 DiskIoDestroySubtask (Instance
, Subtask
);
947 if (EFI_ERROR (Status
)) {
952 gBS
->RaiseTPL (TPL_NOTIFY
);
955 // Remove all the remaining subtasks when failure.
956 // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
958 if (EFI_ERROR (Status
)) {
959 while (!IsNull (SubtasksPtr
, NextLink
)) {
960 Subtask
= CR (NextLink
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
961 NextLink
= DiskIoDestroySubtask (Instance
, Subtask
);
966 // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
967 // so the subtasks list might be empty at this point.
969 if (!Blocking
&& IsListEmpty (SubtasksPtr
)) {
970 EfiAcquireLock (&Instance
->TaskQueueLock
);
971 RemoveEntryList (&Task
->Link
);
972 EfiReleaseLock (&Instance
->TaskQueueLock
);
974 if (!EFI_ERROR (Status
) && (Task
->Token
!= NULL
)) {
976 // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
977 // It it's not, that means the non-blocking request was downgraded to blocking request.
979 DEBUG ((EFI_D_VERBOSE
, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
980 Task
->Token
->TransactionStatus
= Status
;
981 gBS
->SignalEvent (Task
->Token
->Event
);
987 gBS
->RestoreTPL (OldTpl
);
993 Reads a specified number of bytes from a device.
995 @param This Indicates a pointer to the calling context.
996 @param MediaId ID of the medium to be read.
997 @param Offset The starting byte offset on the logical block I/O device to read from.
998 @param Token A pointer to the token associated with the transaction.
999 If this field is NULL, synchronous/blocking IO is performed.
1000 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
1001 @param Buffer A pointer to the destination buffer for the data.
1002 The caller is responsible either having implicit or explicit ownership of the buffer.
1004 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device.
1005 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1006 Event will be signaled upon completion.
1007 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1008 @retval EFI_NO_MEDIA There is no medium in the device.
1009 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
1010 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
1011 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1017 IN EFI_DISK_IO2_PROTOCOL
*This
,
1020 IN OUT EFI_DISK_IO2_TOKEN
*Token
,
1021 IN UINTN BufferSize
,
1025 return DiskIo2ReadWriteDisk (
1026 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
),
1027 FALSE
, MediaId
, Offset
, Token
, BufferSize
, (UINT8
*) Buffer
1032 Writes a specified number of bytes to a device.
1034 @param This Indicates a pointer to the calling context.
1035 @param MediaId ID of the medium to be written.
1036 @param Offset The starting byte offset on the logical block I/O device to write to.
1037 @param Token A pointer to the token associated with the transaction.
1038 If this field is NULL, synchronous/blocking IO is performed.
1039 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
1040 @param Buffer A pointer to the buffer containing the data to be written.
1042 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to the device.
1043 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1044 Event will be signaled upon completion.
1045 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1046 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
1047 @retval EFI_NO_MEDIA There is no medium in the device.
1048 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
1049 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
1050 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1055 DiskIo2WriteDiskEx (
1056 IN EFI_DISK_IO2_PROTOCOL
*This
,
1059 IN OUT EFI_DISK_IO2_TOKEN
*Token
,
1060 IN UINTN BufferSize
,
1064 return DiskIo2ReadWriteDisk (
1065 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
),
1066 TRUE
, MediaId
, Offset
, Token
, BufferSize
, (UINT8
*) Buffer
1071 The callback for the BlockIo2 FlushBlocksEx.
1072 @param Event Event whose notification function is being invoked.
1073 @param Context The pointer to the notification function's context,
1074 which points to the DISK_IO2_FLUSH_TASK instance.
1078 DiskIo2OnFlushComplete (
1083 DISK_IO2_FLUSH_TASK
*Task
;
1085 gBS
->CloseEvent (Event
);
1087 Task
= (DISK_IO2_FLUSH_TASK
*) Context
;
1088 ASSERT (Task
->Signature
== DISK_IO2_FLUSH_TASK_SIGNATURE
);
1089 Task
->Token
->TransactionStatus
= Task
->BlockIo2Token
.TransactionStatus
;
1090 gBS
->SignalEvent (Task
->Token
->Event
);
1096 Flushes all modified data to the physical device.
1098 @param This Indicates a pointer to the calling context.
1099 @param Token A pointer to the token associated with the transaction.
1100 If this field is NULL, synchronous/blocking IO is performed.
1102 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device.
1103 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1104 Event will be signaled upon completion.
1105 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1106 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
1107 @retval EFI_NO_MEDIA There is no medium in the device.
1108 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1112 DiskIo2FlushDiskEx (
1113 IN EFI_DISK_IO2_PROTOCOL
*This
,
1114 IN OUT EFI_DISK_IO2_TOKEN
*Token
1118 DISK_IO2_FLUSH_TASK
*Task
;
1119 DISK_IO_PRIVATE_DATA
*Private
;
1121 Private
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
);
1123 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1124 Task
= AllocatePool (sizeof (DISK_IO2_FLUSH_TASK
));
1126 return EFI_OUT_OF_RESOURCES
;
1129 Status
= gBS
->CreateEvent (
1132 DiskIo2OnFlushComplete
,
1134 &Task
->BlockIo2Token
.Event
1136 if (EFI_ERROR (Status
)) {
1140 Task
->Signature
= DISK_IO2_FLUSH_TASK_SIGNATURE
;
1141 Task
->Token
= Token
;
1142 Status
= Private
->BlockIo2
->FlushBlocksEx (Private
->BlockIo2
, &Task
->BlockIo2Token
);
1143 if (EFI_ERROR (Status
)) {
1144 gBS
->CloseEvent (Task
->BlockIo2Token
.Event
);
1148 Status
= Private
->BlockIo2
->FlushBlocksEx (Private
->BlockIo2
, NULL
);
1155 Read BufferSize bytes from Offset into Buffer.
1156 Reads may support reads that are not aligned on
1157 sector boundaries. There are three cases:
1158 UnderRun - The first byte is not on a sector boundary or the read request is
1159 less than a sector in length.
1160 Aligned - A read of N contiguous sectors.
1161 OverRun - The last byte is not on a sector boundary.
1163 @param This Protocol instance pointer.
1164 @param MediaId Id of the media, changes every time the media is replaced.
1165 @param Offset The starting byte offset to read from
1166 @param BufferSize Size of Buffer
1167 @param Buffer Buffer containing read data
1169 @retval EFI_SUCCESS The data was read correctly from the device.
1170 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
1171 @retval EFI_NO_MEDIA There is no media in the device.
1172 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1173 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
1174 valid for the device.
1180 IN EFI_DISK_IO_PROTOCOL
*This
,
1183 IN UINTN BufferSize
,
1187 return DiskIo2ReadWriteDisk (
1188 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This
),
1189 FALSE
, MediaId
, Offset
, NULL
, BufferSize
, (UINT8
*) Buffer
1195 Writes BufferSize bytes from Buffer into Offset.
1196 Writes may require a read modify write to support writes that are not
1197 aligned on sector boundaries. There are three cases:
1198 UnderRun - The first byte is not on a sector boundary or the write request
1199 is less than a sector in length. Read modify write is required.
1200 Aligned - A write of N contiguous sectors.
1201 OverRun - The last byte is not on a sector boundary. Read modified write
1204 @param This Protocol instance pointer.
1205 @param MediaId Id of the media, changes every time the media is replaced.
1206 @param Offset The starting byte offset to read from
1207 @param BufferSize Size of Buffer
1208 @param Buffer Buffer containing read data
1210 @retval EFI_SUCCESS The data was written correctly to the device.
1211 @retval EFI_WRITE_PROTECTED The device can not be written to.
1212 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1213 @retval EFI_NO_MEDIA There is no media in the device.
1214 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1215 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
1216 valid for the device.
1222 IN EFI_DISK_IO_PROTOCOL
*This
,
1225 IN UINTN BufferSize
,
1229 return DiskIo2ReadWriteDisk (
1230 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This
),
1231 TRUE
, MediaId
, Offset
, NULL
, BufferSize
, (UINT8
*) Buffer
1236 The user Entry Point for module DiskIo. The user code starts with this function.
1238 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1239 @param[in] SystemTable A pointer to the EFI System Table.
1241 @retval EFI_SUCCESS The entry point is executed successfully.
1242 @retval other Some error occurs when executing this entry point.
1248 IN EFI_HANDLE ImageHandle
,
1249 IN EFI_SYSTEM_TABLE
*SystemTable
1255 // Install driver model protocol(s).
1257 Status
= EfiLibInstallDriverBindingComponentName2 (
1260 &gDiskIoDriverBinding
,
1262 &gDiskIoComponentName
,
1263 &gDiskIoComponentName2
1265 ASSERT_EFI_ERROR (Status
);