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 - 2013, 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 (DATA_BUFFER_BLOCK_NUM
* 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 (DATA_BUFFER_BLOCK_NUM
* 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 (DATA_BUFFER_BLOCK_NUM
* 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
369 Link
= RemoveEntryList (&Subtask
->Link
);
370 if (!Subtask
->Blocking
) {
371 if (Subtask
->WorkingBuffer
!= NULL
) {
373 Subtask
->WorkingBuffer
,
374 Subtask
->Length
< Instance
->BlockIo
->Media
->BlockSize
375 ? EFI_SIZE_TO_PAGES (Instance
->BlockIo
->Media
->BlockSize
)
376 : EFI_SIZE_TO_PAGES (Subtask
->Length
)
379 if (Subtask
->BlockIo2Token
.Event
!= NULL
) {
380 gBS
->CloseEvent (Subtask
->BlockIo2Token
.Event
);
389 The callback for the BlockIo2 ReadBlocksEx/WriteBlocksEx.
390 @param Event Event whose notification function is being invoked.
391 @param Context The pointer to the notification function's context,
392 which points to the DISK_IO_SUBTASK instance.
396 DiskIo2OnReadWriteComplete (
401 DISK_IO_SUBTASK
*Subtask
;
403 EFI_STATUS TransactionStatus
;
404 DISK_IO_PRIVATE_DATA
*Instance
;
406 gBS
->CloseEvent (Event
);
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
) {
418 if (!EFI_ERROR (TransactionStatus
) && (Task
->Token
!= NULL
) && !Subtask
->Write
) {
419 CopyMem (Subtask
->Buffer
, Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Length
);
423 // The WorkingBuffer of blocking subtask either points to SharedWorkingBuffer
424 // or will be used by non-blocking subtask which will be freed below.
426 if (!Subtask
->Blocking
) {
428 Subtask
->WorkingBuffer
,
429 Subtask
->Length
< Instance
->BlockIo
->Media
->BlockSize
430 ? EFI_SIZE_TO_PAGES (Instance
->BlockIo
->Media
->BlockSize
)
431 : EFI_SIZE_TO_PAGES (Subtask
->Length
)
435 RemoveEntryList (&Subtask
->Link
);
438 if (EFI_ERROR (TransactionStatus
) || IsListEmpty (&Task
->Subtasks
)) {
439 if (Task
->Token
!= NULL
) {
441 // Signal error status once the subtask is failed.
442 // Or signal the last status once the last subtask is finished.
444 Task
->Token
->TransactionStatus
= TransactionStatus
;
445 gBS
->SignalEvent (Task
->Token
->Event
);
448 // Mark token to NULL
454 if (IsListEmpty (&Task
->Subtasks
)) {
455 EfiAcquireLock (&Instance
->TaskQueueLock
);
456 RemoveEntryList (&Task
->Link
);
457 EfiReleaseLock (&Instance
->TaskQueueLock
);
466 @param Write TRUE: Write request; FALSE: Read request.
467 @param Lba The starting logical block address to read from on the device.
468 @param Offset The starting byte offset to read from the LBA.
469 @param Length The number of bytes to read from the device.
470 @param WorkingBuffer The aligned buffer to hold the data for reading or writing.
471 @param Buffer The buffer to hold the data for reading or writing.
472 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
474 @return A pointer to the created subtask.
477 DiskIoCreateSubtask (
482 IN VOID
*WorkingBuffer
, OPTIONAL
487 DISK_IO_SUBTASK
*Subtask
;
490 Subtask
= AllocateZeroPool (sizeof (DISK_IO_SUBTASK
));
491 if (Subtask
== NULL
) {
494 Subtask
->Signature
= DISK_IO_SUBTASK_SIGNATURE
;
495 Subtask
->Write
= Write
;
497 Subtask
->Offset
= Offset
;
498 Subtask
->Length
= Length
;
499 Subtask
->WorkingBuffer
= WorkingBuffer
;
500 Subtask
->Buffer
= Buffer
;
501 Subtask
->Blocking
= Blocking
;
503 Status
= gBS
->CreateEvent (
506 DiskIo2OnReadWriteComplete
,
508 &Subtask
->BlockIo2Token
.Event
510 if (EFI_ERROR (Status
)) {
517 " %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
518 Write
? 'W': 'R', Lba
, Offset
, Length
, WorkingBuffer
, Buffer
525 Create the subtask list.
527 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
528 @param Write TRUE: Write request; FALSE: Read request.
529 @param Offset The starting byte offset to read from the device.
530 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
531 @param Buffer A pointer to the buffer for the data.
532 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
533 @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing.
534 @param Subtasks The subtask list header.
536 @retval TRUE The subtask list is created successfully.
537 @retval FALSE The subtask list is not created.
540 DiskIoCreateSubtaskList (
541 IN DISK_IO_PRIVATE_DATA
*Instance
,
547 IN VOID
*SharedWorkingBuffer
,
548 IN OUT LIST_ENTRY
*Subtasks
559 UINTN DataBufferSize
;
560 DISK_IO_SUBTASK
*Subtask
;
564 DEBUG ((EFI_D_BLKIO
, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset
, BufferSize
, Buffer
));
566 BlockSize
= Instance
->BlockIo
->Media
->BlockSize
;
567 IoAlign
= Instance
->BlockIo
->Media
->IoAlign
;
572 Lba
= DivU64x32Remainder (Offset
, BlockSize
, &UnderRun
);
573 BufferPtr
= (UINT8
*) Buffer
;
576 // Special handling for zero BufferSize
578 if (BufferSize
== 0) {
579 Subtask
= DiskIoCreateSubtask (Write
, Lba
, UnderRun
, 0, NULL
, BufferPtr
, Blocking
);
580 if (Subtask
== NULL
) {
583 InsertTailList (Subtasks
, &Subtask
->Link
);
588 Length
= MIN (BlockSize
- UnderRun
, BufferSize
);
590 WorkingBuffer
= SharedWorkingBuffer
;
592 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize
), IoAlign
);
593 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
) {
606 InsertTailList (Subtasks
, &Subtask
->Link
);
609 Subtask
= DiskIoCreateSubtask (Write
, Lba
, UnderRun
, Length
, WorkingBuffer
, BufferPtr
, Blocking
);
610 if (Subtask
== NULL
) {
613 InsertTailList (Subtasks
, &Subtask
->Link
);
617 BufferSize
-= Length
;
621 OverRunLba
= Lba
+ DivU64x32Remainder (BufferSize
, BlockSize
, &OverRun
);
622 BufferSize
-= OverRun
;
626 WorkingBuffer
= SharedWorkingBuffer
;
628 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize
), IoAlign
);
629 if (WorkingBuffer
== NULL
) {
635 // A half write operation can be splitted to a blocking block-read and half write operation
636 // This can simplify the sub task processing logic
638 Subtask
= DiskIoCreateSubtask (FALSE
, OverRunLba
, 0, BlockSize
, NULL
, WorkingBuffer
, TRUE
);
639 if (Subtask
== NULL
) {
642 InsertTailList (Subtasks
, &Subtask
->Link
);
645 Subtask
= DiskIoCreateSubtask (Write
, OverRunLba
, 0, OverRun
, WorkingBuffer
, BufferPtr
, Blocking
);
646 if (Subtask
== NULL
) {
649 InsertTailList (Subtasks
, &Subtask
->Link
);
652 if (OverRunLba
> Lba
) {
654 // If the DiskIo maps directly to a BlockIo device do the read.
656 if (ALIGN_POINTER (BufferPtr
, IoAlign
) == BufferPtr
) {
657 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, BufferSize
, NULL
, BufferPtr
, Blocking
);
658 if (Subtask
== NULL
) {
661 InsertTailList (Subtasks
, &Subtask
->Link
);
663 BufferPtr
+= BufferSize
;
664 Offset
+= BufferSize
;
665 BufferSize
-= BufferSize
;
670 // Use the allocated buffer instead of the original buffer
671 // to avoid alignment issue.
673 for (; Lba
< OverRunLba
; Lba
+= DATA_BUFFER_BLOCK_NUM
) {
674 DataBufferSize
= MIN (BufferSize
, DATA_BUFFER_BLOCK_NUM
* BlockSize
);
676 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, DataBufferSize
, SharedWorkingBuffer
, BufferPtr
, Blocking
);
677 if (Subtask
== NULL
) {
680 InsertTailList (Subtasks
, &Subtask
->Link
);
682 BufferPtr
+= DataBufferSize
;
683 Offset
+= DataBufferSize
;
684 BufferSize
-= DataBufferSize
;
687 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), IoAlign
);
688 if (WorkingBuffer
== NULL
) {
690 // If there is not enough memory, downgrade to blocking access
692 DEBUG ((EFI_D_VERBOSE
, "DiskIo: No enough memory so downgrade to blocking access\n"));
693 if (!DiskIoCreateSubtaskList (Instance
, Write
, Offset
, BufferSize
, BufferPtr
, TRUE
, SharedWorkingBuffer
, Subtasks
)) {
697 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, BufferSize
, WorkingBuffer
, BufferPtr
, Blocking
);
698 if (Subtask
== NULL
) {
701 InsertTailList (Subtasks
, &Subtask
->Link
);
704 BufferPtr
+= BufferSize
;
705 Offset
+= BufferSize
;
706 BufferSize
-= BufferSize
;
711 ASSERT (BufferSize
== 0);
717 // Remove all the subtasks.
719 for (Link
= GetFirstNode (Subtasks
); !IsNull (Subtasks
, Link
); ) {
720 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
721 Link
= DiskIoDestroySubtask (Instance
, Subtask
);
727 Terminate outstanding asynchronous requests to a device.
729 @param This Indicates a pointer to the calling context.
731 @retval EFI_SUCCESS All outstanding requests were successfully terminated.
732 @retval EFI_DEVICE_ERROR The device reported an error while performing the cancel
738 IN EFI_DISK_IO2_PROTOCOL
*This
741 DISK_IO_PRIVATE_DATA
*Instance
;
745 Instance
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
);
747 EfiAcquireLock (&Instance
->TaskQueueLock
);
749 for (Link
= GetFirstNode (&Instance
->TaskQueue
)
750 ; !IsNull (&Instance
->TaskQueue
, Link
)
751 ; Link
= GetNextNode (&Instance
->TaskQueue
, Link
)
753 Task
= CR (Link
, DISK_IO2_TASK
, Link
, DISK_IO2_TASK_SIGNATURE
);
755 if (Task
->Token
!= NULL
) {
756 Task
->Token
->TransactionStatus
= EFI_ABORTED
;
757 gBS
->SignalEvent (Task
->Token
->Event
);
759 // Set Token to NULL so that the further BlockIo2 responses will be ignored
765 EfiReleaseLock (&Instance
->TaskQueueLock
);
771 Common routine to access the disk.
773 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
774 @param Write TRUE: Write operation; FALSE: Read operation.
775 @param MediaId ID of the medium to access.
776 @param Offset The starting byte offset on the logical block I/O device to access.
777 @param Token A pointer to the token associated with the transaction.
778 If this field is NULL, synchronous/blocking IO is performed.
779 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
780 @param Buffer A pointer to the destination buffer for the data.
781 The caller is responsible either having implicit or explicit ownership of the buffer.
784 DiskIo2ReadWriteDisk (
785 IN DISK_IO_PRIVATE_DATA
*Instance
,
789 IN EFI_DISK_IO2_TOKEN
*Token
,
795 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
796 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
797 EFI_BLOCK_IO_MEDIA
*Media
;
800 DISK_IO_SUBTASK
*Subtask
;
802 BOOLEAN TaskQueueEmpty
;
805 LIST_ENTRY
*SubtasksPtr
;
808 BlockIo
= Instance
->BlockIo
;
809 BlockIo2
= Instance
->BlockIo2
;
810 Media
= BlockIo
->Media
;
811 Status
= EFI_SUCCESS
;
812 Blocking
= (BOOLEAN
) ((Token
== NULL
) || (Token
->Event
== NULL
));
814 if (Media
->MediaId
!= MediaId
) {
815 return EFI_MEDIA_CHANGED
;
818 if (Write
&& Media
->ReadOnly
) {
819 return EFI_WRITE_PROTECTED
;
824 // Wait till pending async task is completed.
827 EfiAcquireLock (&Instance
->TaskQueueLock
);
828 TaskQueueEmpty
= IsListEmpty (&Instance
->TaskQueue
);
829 EfiReleaseLock (&Instance
->TaskQueueLock
);
830 } while (!TaskQueueEmpty
);
832 SubtasksPtr
= &Subtasks
;
834 Task
= AllocatePool (sizeof (DISK_IO2_TASK
));
836 return EFI_OUT_OF_RESOURCES
;
839 EfiAcquireLock (&Instance
->TaskQueueLock
);
840 InsertTailList (&Instance
->TaskQueue
, &Task
->Link
);
841 EfiReleaseLock (&Instance
->TaskQueueLock
);
843 Task
->Signature
= DISK_IO2_TASK_SIGNATURE
;
844 Task
->Instance
= Instance
;
847 SubtasksPtr
= &Task
->Subtasks
;
850 InitializeListHead (SubtasksPtr
);
851 if (!DiskIoCreateSubtaskList (Instance
, Write
, Offset
, BufferSize
, Buffer
, Blocking
, Instance
->SharedWorkingBuffer
, SubtasksPtr
)) {
855 return EFI_OUT_OF_RESOURCES
;
857 ASSERT (!IsListEmpty (SubtasksPtr
));
859 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
860 for (Link
= GetFirstNode (SubtasksPtr
); !IsNull (SubtasksPtr
, Link
); Link
= GetNextNode (SubtasksPtr
, Link
)) {
861 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
863 if (!Subtask
->Blocking
) {
864 Subtask
->Task
= Task
;
867 if (Subtask
->Write
) {
871 if (Subtask
->WorkingBuffer
!= NULL
) {
873 // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
875 CopyMem (Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Buffer
, Subtask
->Length
);
878 if (Subtask
->Blocking
) {
879 Status
= BlockIo
->WriteBlocks (
883 Subtask
->Length
< Media
->BlockSize
? Media
->BlockSize
: Subtask
->Length
,
884 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
887 Status
= BlockIo2
->WriteBlocksEx (
891 &Subtask
->BlockIo2Token
,
892 Subtask
->Length
< Media
->BlockSize
? Media
->BlockSize
: Subtask
->Length
,
893 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
901 if (Subtask
->Blocking
) {
902 Status
= BlockIo
->ReadBlocks (
906 Subtask
->Length
< Media
->BlockSize
? Media
->BlockSize
: Subtask
->Length
,
907 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
909 if (!EFI_ERROR (Status
) && (Subtask
->WorkingBuffer
!= NULL
)) {
910 CopyMem (Subtask
->Buffer
, Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Length
);
913 Status
= BlockIo2
->ReadBlocksEx (
917 &Subtask
->BlockIo2Token
,
918 Subtask
->Length
< Media
->BlockSize
? Media
->BlockSize
: Subtask
->Length
,
919 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
924 if (EFI_ERROR (Status
)) {
929 gBS
->RaiseTPL (TPL_NOTIFY
);
932 // Remove all the remaining subtasks when failure.
933 // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
935 if (EFI_ERROR (Status
)) {
936 while (!IsNull (SubtasksPtr
, Link
)) {
937 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
938 Link
= DiskIoDestroySubtask (Instance
, Subtask
);
943 // Remove all the blocking subtasks because the non-blocking callback only removes the non-blocking subtask.
945 for (Link
= GetFirstNode (SubtasksPtr
); !IsNull (SubtasksPtr
, Link
); ) {
946 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
947 if (Subtask
->Blocking
) {
948 Link
= DiskIoDestroySubtask (Instance
, Subtask
);
950 Link
= GetNextNode (SubtasksPtr
, Link
);
955 // It's possible that the callback runs before raising TPL to NOTIFY,
956 // so the subtasks list only contains blocking subtask.
957 // Remove the Task after the blocking subtasks are removed in above.
959 if (!Blocking
&& IsListEmpty (SubtasksPtr
)) {
960 EfiAcquireLock (&Instance
->TaskQueueLock
);
961 RemoveEntryList (&Task
->Link
);
962 EfiReleaseLock (&Instance
->TaskQueueLock
);
964 if (Task
->Token
!= NULL
) {
966 // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
967 // It it's not, that means the non-blocking request was downgraded to blocking request.
969 DEBUG ((EFI_D_VERBOSE
, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
970 Task
->Token
->TransactionStatus
= Status
;
971 gBS
->SignalEvent (Task
->Token
->Event
);
977 gBS
->RestoreTPL (OldTpl
);
983 Reads a specified number of bytes from a device.
985 @param This Indicates a pointer to the calling context.
986 @param MediaId ID of the medium to be read.
987 @param Offset The starting byte offset on the logical block I/O device to read from.
988 @param Token A pointer to the token associated with the transaction.
989 If this field is NULL, synchronous/blocking IO is performed.
990 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
991 @param Buffer A pointer to the destination buffer for the data.
992 The caller is responsible either having implicit or explicit ownership of the buffer.
994 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device.
995 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
996 Event will be signaled upon completion.
997 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
998 @retval EFI_NO_MEDIA There is no medium in the device.
999 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
1000 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
1001 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1007 IN EFI_DISK_IO2_PROTOCOL
*This
,
1010 IN OUT EFI_DISK_IO2_TOKEN
*Token
,
1011 IN UINTN BufferSize
,
1015 return DiskIo2ReadWriteDisk (
1016 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
),
1017 FALSE
, MediaId
, Offset
, Token
, BufferSize
, (UINT8
*) Buffer
1022 Writes a specified number of bytes to a device.
1024 @param This Indicates a pointer to the calling context.
1025 @param MediaId ID of the medium to be written.
1026 @param Offset The starting byte offset on the logical block I/O device to write to.
1027 @param Token A pointer to the token associated with the transaction.
1028 If this field is NULL, synchronous/blocking IO is performed.
1029 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
1030 @param Buffer A pointer to the buffer containing the data to be written.
1032 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to 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_WRITE_PROTECTED The device cannot be written to.
1036 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
1037 @retval EFI_NO_MEDIA There is no medium in the device.
1038 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
1039 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
1040 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1045 DiskIo2WriteDiskEx (
1046 IN EFI_DISK_IO2_PROTOCOL
*This
,
1049 IN OUT EFI_DISK_IO2_TOKEN
*Token
,
1050 IN UINTN BufferSize
,
1054 return DiskIo2ReadWriteDisk (
1055 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
),
1056 TRUE
, MediaId
, Offset
, Token
, BufferSize
, (UINT8
*) Buffer
1061 The callback for the BlockIo2 FlushBlocksEx.
1062 @param Event Event whose notification function is being invoked.
1063 @param Context The pointer to the notification function's context,
1064 which points to the DISK_IO2_FLUSH_TASK instance.
1068 DiskIo2OnFlushComplete (
1073 DISK_IO2_FLUSH_TASK
*Task
;
1075 gBS
->CloseEvent (Event
);
1077 Task
= (DISK_IO2_FLUSH_TASK
*) Context
;
1078 ASSERT (Task
->Signature
== DISK_IO2_FLUSH_TASK_SIGNATURE
);
1079 Task
->Token
->TransactionStatus
= Task
->BlockIo2Token
.TransactionStatus
;
1080 gBS
->SignalEvent (Task
->Token
->Event
);
1084 Flushes all modified data to the physical device.
1086 @param This Indicates a pointer to the calling context.
1087 @param Token A pointer to the token associated with the transaction.
1088 If this field is NULL, synchronous/blocking IO is performed.
1090 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device.
1091 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1092 Event will be signaled upon completion.
1093 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1094 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
1095 @retval EFI_NO_MEDIA There is no medium in the device.
1096 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1100 DiskIo2FlushDiskEx (
1101 IN EFI_DISK_IO2_PROTOCOL
*This
,
1102 IN OUT EFI_DISK_IO2_TOKEN
*Token
1106 DISK_IO2_FLUSH_TASK
*Task
;
1107 DISK_IO_PRIVATE_DATA
*Private
;
1109 Private
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
);
1111 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1112 Task
= AllocatePool (sizeof (DISK_IO2_FLUSH_TASK
));
1114 return EFI_OUT_OF_RESOURCES
;
1117 Status
= gBS
->CreateEvent (
1120 DiskIo2OnFlushComplete
,
1122 &Task
->BlockIo2Token
.Event
1124 if (EFI_ERROR (Status
)) {
1128 Task
->Signature
= DISK_IO2_FLUSH_TASK_SIGNATURE
;
1129 Status
= Private
->BlockIo2
->FlushBlocksEx (Private
->BlockIo2
, &Task
->BlockIo2Token
);
1130 if (EFI_ERROR (Status
)) {
1131 gBS
->CloseEvent (Task
->BlockIo2Token
.Event
);
1135 Status
= Private
->BlockIo2
->FlushBlocksEx (Private
->BlockIo2
, NULL
);
1142 Read BufferSize bytes from Offset into Buffer.
1143 Reads may support reads that are not aligned on
1144 sector boundaries. There are three cases:
1145 UnderRun - The first byte is not on a sector boundary or the read request is
1146 less than a sector in length.
1147 Aligned - A read of N contiguous sectors.
1148 OverRun - The last byte is not on a sector boundary.
1150 @param This Protocol instance pointer.
1151 @param MediaId Id of the media, changes every time the media is replaced.
1152 @param Offset The starting byte offset to read from
1153 @param BufferSize Size of Buffer
1154 @param Buffer Buffer containing read data
1156 @retval EFI_SUCCESS The data was read correctly from the device.
1157 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
1158 @retval EFI_NO_MEDIA There is no media in the device.
1159 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1160 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
1161 valid for the device.
1167 IN EFI_DISK_IO_PROTOCOL
*This
,
1170 IN UINTN BufferSize
,
1174 return DiskIo2ReadWriteDisk (
1175 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This
),
1176 FALSE
, MediaId
, Offset
, NULL
, BufferSize
, (UINT8
*) Buffer
1182 Writes BufferSize bytes from Buffer into Offset.
1183 Writes may require a read modify write to support writes that are not
1184 aligned on sector boundaries. There are three cases:
1185 UnderRun - The first byte is not on a sector boundary or the write request
1186 is less than a sector in length. Read modify write is required.
1187 Aligned - A write of N contiguous sectors.
1188 OverRun - The last byte is not on a sector boundary. Read modified write
1191 @param This Protocol instance pointer.
1192 @param MediaId Id of the media, changes every time the media is replaced.
1193 @param Offset The starting byte offset to read from
1194 @param BufferSize Size of Buffer
1195 @param Buffer Buffer containing read data
1197 @retval EFI_SUCCESS The data was written correctly to the device.
1198 @retval EFI_WRITE_PROTECTED The device can not be written to.
1199 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1200 @retval EFI_NO_MEDIA There is no media in the device.
1201 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1202 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
1203 valid for the device.
1209 IN EFI_DISK_IO_PROTOCOL
*This
,
1212 IN UINTN BufferSize
,
1216 return DiskIo2ReadWriteDisk (
1217 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This
),
1218 TRUE
, MediaId
, Offset
, NULL
, BufferSize
, (UINT8
*) Buffer
1223 The user Entry Point for module DiskIo. The user code starts with this function.
1225 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1226 @param[in] SystemTable A pointer to the EFI System Table.
1228 @retval EFI_SUCCESS The entry point is executed successfully.
1229 @retval other Some error occurs when executing this entry point.
1235 IN EFI_HANDLE ImageHandle
,
1236 IN EFI_SYSTEM_TABLE
*SystemTable
1242 // Install driver model protocol(s).
1244 Status
= EfiLibInstallDriverBindingComponentName2 (
1247 &gDiskIoDriverBinding
,
1249 &gDiskIoComponentName
,
1250 &gDiskIoComponentName2
1252 ASSERT_EFI_ERROR (Status
);