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
;
134 EFI_BLOCK_IO_MEDIA
*Media
;
138 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
141 // Connect to the Block IO and Block IO2 interface on ControllerHandle.
143 Status
= gBS
->OpenProtocol (
145 &gEfiBlockIoProtocolGuid
,
146 (VOID
**) &gDiskIoPrivateDataTemplate
.BlockIo
,
147 This
->DriverBindingHandle
,
149 EFI_OPEN_PROTOCOL_BY_DRIVER
151 if (EFI_ERROR (Status
)) {
155 Status
= gBS
->OpenProtocol (
157 &gEfiBlockIo2ProtocolGuid
,
158 (VOID
**) &gDiskIoPrivateDataTemplate
.BlockIo2
,
159 This
->DriverBindingHandle
,
161 EFI_OPEN_PROTOCOL_BY_DRIVER
163 if (EFI_ERROR (Status
)) {
164 gDiskIoPrivateDataTemplate
.BlockIo2
= NULL
;
168 // Initialize the Disk IO device instance.
170 Instance
= AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA
), &gDiskIoPrivateDataTemplate
);
171 if (Instance
== NULL
) {
172 Status
= EFI_OUT_OF_RESOURCES
;
176 Media
= Instance
->BlockIo
->Media
;
179 // The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.
181 ASSERT ((Instance
->BlockIo2
== NULL
) ||
182 ((Instance
->BlockIo
->Media
->IoAlign
== Instance
->BlockIo2
->Media
->IoAlign
) &&
183 (Instance
->BlockIo
->Media
->BlockSize
== Instance
->BlockIo2
->Media
->BlockSize
)
186 InitializeListHead (&Instance
->TaskQueue
);
187 EfiInitializeLock (&Instance
->TaskQueueLock
, TPL_NOTIFY
);
188 Instance
->SharedWorkingBuffer
= AllocateAlignedPages (
189 EFI_SIZE_TO_PAGES (DATA_BUFFER_BLOCK_NUM
* Instance
->BlockIo
->Media
->BlockSize
),
190 Instance
->BlockIo
->Media
->IoAlign
192 if (Instance
->SharedWorkingBuffer
== NULL
) {
193 Status
= EFI_OUT_OF_RESOURCES
;
198 // Install protocol interfaces for the Disk IO device.
200 if (Instance
->BlockIo2
!= NULL
) {
201 Status
= gBS
->InstallMultipleProtocolInterfaces (
203 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIo
,
204 &gEfiDiskIo2ProtocolGuid
, &Instance
->DiskIo2
,
208 Status
= gBS
->InstallMultipleProtocolInterfaces (
210 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIo
,
216 if (EFI_ERROR (Status
)) {
217 if (Instance
!= NULL
&& Instance
->SharedWorkingBuffer
!= NULL
) {
219 Instance
->SharedWorkingBuffer
,
220 EFI_SIZE_TO_PAGES (DATA_BUFFER_BLOCK_NUM
* Instance
->BlockIo
->Media
->BlockSize
)
224 if (Instance
!= NULL
) {
230 &gEfiBlockIoProtocolGuid
,
231 This
->DriverBindingHandle
,
237 gBS
->RestoreTPL (OldTpl
);
242 Stop this driver on ControllerHandle by removing Disk IO protocol and closing
243 the Block IO protocol on ControllerHandle.
245 @param This Protocol instance pointer.
246 @param ControllerHandle Handle of device to stop driver on
247 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
248 children is zero stop the entire bus driver.
249 @param ChildHandleBuffer List of Child Handles to Stop.
251 @retval EFI_SUCCESS This driver is removed ControllerHandle
252 @retval other This driver was not removed from this device
257 DiskIoDriverBindingStop (
258 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
259 IN EFI_HANDLE ControllerHandle
,
260 IN UINTN NumberOfChildren
,
261 IN EFI_HANDLE
*ChildHandleBuffer
265 EFI_DISK_IO_PROTOCOL
*DiskIo
;
266 EFI_DISK_IO2_PROTOCOL
*DiskIo2
;
267 DISK_IO_PRIVATE_DATA
*Instance
;
271 // Get our context back.
273 Status
= gBS
->OpenProtocol (
275 &gEfiDiskIoProtocolGuid
,
277 This
->DriverBindingHandle
,
279 EFI_OPEN_PROTOCOL_GET_PROTOCOL
281 if (EFI_ERROR (Status
)) {
284 Status
= gBS
->OpenProtocol (
286 &gEfiDiskIo2ProtocolGuid
,
288 This
->DriverBindingHandle
,
290 EFI_OPEN_PROTOCOL_GET_PROTOCOL
292 if (EFI_ERROR (Status
)) {
296 Instance
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo
);
298 if (DiskIo2
!= NULL
) {
300 // Call BlockIo2::Reset() to terminate any in-flight non-blocking I/O requests
302 ASSERT (Instance
->BlockIo2
!= NULL
);
303 Status
= Instance
->BlockIo2
->Reset (Instance
->BlockIo2
, FALSE
);
304 if (EFI_ERROR (Status
)) {
307 Status
= gBS
->UninstallMultipleProtocolInterfaces (
309 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIo
,
310 &gEfiDiskIo2ProtocolGuid
, &Instance
->DiskIo2
,
314 Status
= gBS
->UninstallMultipleProtocolInterfaces (
316 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIo
,
320 if (!EFI_ERROR (Status
)) {
323 EfiAcquireLock (&Instance
->TaskQueueLock
);
324 AllTaskDone
= IsListEmpty (&Instance
->TaskQueue
);
325 EfiReleaseLock (&Instance
->TaskQueueLock
);
326 } while (!AllTaskDone
);
329 Instance
->SharedWorkingBuffer
,
330 EFI_SIZE_TO_PAGES (DATA_BUFFER_BLOCK_NUM
* Instance
->BlockIo
->Media
->BlockSize
)
333 Status
= gBS
->CloseProtocol (
335 &gEfiBlockIoProtocolGuid
,
336 This
->DriverBindingHandle
,
339 ASSERT_EFI_ERROR (Status
);
340 if (DiskIo2
!= NULL
) {
341 Status
= gBS
->CloseProtocol (
343 &gEfiBlockIo2ProtocolGuid
,
344 This
->DriverBindingHandle
,
347 ASSERT_EFI_ERROR (Status
);
358 Destroy the sub task.
360 @param Subtask Subtask.
362 @return LIST_ENTRY * Pointer to the next link of subtask.
365 DiskIoDestroySubtask (
366 IN DISK_IO_PRIVATE_DATA
*Instance
,
367 IN DISK_IO_SUBTASK
*Subtask
371 Link
= RemoveEntryList (&Subtask
->Link
);
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 gBS
->CloseEvent (Event
);
410 Subtask
= (DISK_IO_SUBTASK
*) Context
;
411 TransactionStatus
= Subtask
->BlockIo2Token
.TransactionStatus
;
412 Task
= Subtask
->Task
;
413 Instance
= Task
->Instance
;
415 ASSERT (Subtask
->Signature
== DISK_IO_SUBTASK_SIGNATURE
);
416 ASSERT (Instance
->Signature
== DISK_IO_PRIVATE_DATA_SIGNATURE
);
417 ASSERT (Task
->Signature
== DISK_IO2_TASK_SIGNATURE
);
419 if (Subtask
->WorkingBuffer
!= NULL
) {
420 if (!EFI_ERROR (TransactionStatus
) && (Task
->Token
!= NULL
) && !Subtask
->Write
) {
421 CopyMem (Subtask
->Buffer
, Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Length
);
425 // The WorkingBuffer of blocking subtask either points to SharedWorkingBuffer
426 // or will be used by non-blocking subtask which will be freed below.
428 if (!Subtask
->Blocking
) {
430 Subtask
->WorkingBuffer
,
431 Subtask
->Length
< Instance
->BlockIo
->Media
->BlockSize
432 ? EFI_SIZE_TO_PAGES (Instance
->BlockIo
->Media
->BlockSize
)
433 : EFI_SIZE_TO_PAGES (Subtask
->Length
)
437 RemoveEntryList (&Subtask
->Link
);
440 if (EFI_ERROR (TransactionStatus
) || IsListEmpty (&Task
->Subtasks
)) {
441 if (Task
->Token
!= NULL
) {
443 // Signal error status once the subtask is failed.
444 // Or signal the last status once the last subtask is finished.
446 Task
->Token
->TransactionStatus
= TransactionStatus
;
447 gBS
->SignalEvent (Task
->Token
->Event
);
450 // Mark token to NULL
456 if (IsListEmpty (&Task
->Subtasks
)) {
457 EfiAcquireLock (&Instance
->TaskQueueLock
);
458 RemoveEntryList (&Task
->Link
);
459 EfiReleaseLock (&Instance
->TaskQueueLock
);
468 @param Write TRUE: Write request; FALSE: Read request.
469 @param Lba The starting logical block address to read from on the device.
470 @param Offset The starting byte offset to read from the LBA.
471 @param Length The number of bytes to read from the device.
472 @param WorkingBuffer The aligned buffer to hold the data for reading or writing.
473 @param Buffer The buffer to hold the data for reading or writing.
474 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
476 @return A pointer to the created subtask.
479 DiskIoCreateSubtask (
484 IN VOID
*WorkingBuffer
, OPTIONAL
489 DISK_IO_SUBTASK
*Subtask
;
492 Subtask
= AllocateZeroPool (sizeof (DISK_IO_SUBTASK
));
493 if (Subtask
== NULL
) {
496 Subtask
->Signature
= DISK_IO_SUBTASK_SIGNATURE
;
497 Subtask
->Write
= Write
;
499 Subtask
->Offset
= Offset
;
500 Subtask
->Length
= Length
;
501 Subtask
->WorkingBuffer
= WorkingBuffer
;
502 Subtask
->Buffer
= Buffer
;
503 Subtask
->Blocking
= Blocking
;
505 Status
= gBS
->CreateEvent (
508 DiskIo2OnReadWriteComplete
,
510 &Subtask
->BlockIo2Token
.Event
512 if (EFI_ERROR (Status
)) {
519 " %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
520 Write
? 'W': 'R', Lba
, Offset
, Length
, WorkingBuffer
, Buffer
527 Create the subtask list.
529 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
530 @param Write TRUE: Write request; FALSE: Read request.
531 @param Offset The starting byte offset to read from the device.
532 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
533 @param Buffer A pointer to the buffer for the data.
534 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
535 @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing.
536 @param Subtasks The subtask list header.
538 @retval TRUE The subtask list is created successfully.
539 @retval FALSE The subtask list is not created.
542 DiskIoCreateSubtaskList (
543 IN DISK_IO_PRIVATE_DATA
*Instance
,
549 IN VOID
*SharedWorkingBuffer
,
550 IN OUT LIST_ENTRY
*Subtasks
561 UINTN DataBufferSize
;
562 DISK_IO_SUBTASK
*Subtask
;
566 DEBUG ((EFI_D_BLKIO
, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset
, BufferSize
, Buffer
));
568 BlockSize
= Instance
->BlockIo
->Media
->BlockSize
;
569 IoAlign
= Instance
->BlockIo
->Media
->IoAlign
;
574 Lba
= DivU64x32Remainder (Offset
, BlockSize
, &UnderRun
);
575 BufferPtr
= (UINT8
*) Buffer
;
578 // Special handling for zero BufferSize
580 if (BufferSize
== 0) {
581 Subtask
= DiskIoCreateSubtask (Write
, Lba
, UnderRun
, 0, NULL
, BufferPtr
, Blocking
);
582 if (Subtask
== NULL
) {
585 InsertTailList (Subtasks
, &Subtask
->Link
);
590 Length
= MIN (BlockSize
- UnderRun
, BufferSize
);
592 WorkingBuffer
= SharedWorkingBuffer
;
594 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize
), IoAlign
);
595 if (WorkingBuffer
== NULL
) {
601 // A half write operation can be splitted to a blocking block-read and half write operation
602 // This can simplify the sub task processing logic
604 Subtask
= DiskIoCreateSubtask (FALSE
, Lba
, 0, BlockSize
, NULL
, WorkingBuffer
, TRUE
);
605 if (Subtask
== NULL
) {
608 InsertTailList (Subtasks
, &Subtask
->Link
);
611 Subtask
= DiskIoCreateSubtask (Write
, Lba
, UnderRun
, Length
, WorkingBuffer
, BufferPtr
, Blocking
);
612 if (Subtask
== NULL
) {
615 InsertTailList (Subtasks
, &Subtask
->Link
);
619 BufferSize
-= Length
;
623 OverRunLba
= Lba
+ DivU64x32Remainder (BufferSize
, BlockSize
, &OverRun
);
624 BufferSize
-= OverRun
;
628 WorkingBuffer
= SharedWorkingBuffer
;
630 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize
), IoAlign
);
631 if (WorkingBuffer
== NULL
) {
637 // A half write operation can be splitted to a blocking block-read and half write operation
638 // This can simplify the sub task processing logic
640 Subtask
= DiskIoCreateSubtask (FALSE
, OverRunLba
, 0, BlockSize
, NULL
, WorkingBuffer
, TRUE
);
641 if (Subtask
== NULL
) {
644 InsertTailList (Subtasks
, &Subtask
->Link
);
647 Subtask
= DiskIoCreateSubtask (Write
, OverRunLba
, 0, OverRun
, WorkingBuffer
, BufferPtr
, Blocking
);
648 if (Subtask
== NULL
) {
651 InsertTailList (Subtasks
, &Subtask
->Link
);
654 if (OverRunLba
> Lba
) {
656 // If the DiskIo maps directly to a BlockIo device do the read.
658 if (ALIGN_POINTER (BufferPtr
, IoAlign
) == BufferPtr
) {
659 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, BufferSize
, NULL
, BufferPtr
, Blocking
);
660 if (Subtask
== NULL
) {
663 InsertTailList (Subtasks
, &Subtask
->Link
);
665 BufferPtr
+= BufferSize
;
666 Offset
+= BufferSize
;
667 BufferSize
-= BufferSize
;
672 // Use the allocated buffer instead of the original buffer
673 // to avoid alignment issue.
675 for (; Lba
< OverRunLba
; Lba
+= DATA_BUFFER_BLOCK_NUM
) {
676 DataBufferSize
= MIN (BufferSize
, DATA_BUFFER_BLOCK_NUM
* BlockSize
);
678 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, DataBufferSize
, SharedWorkingBuffer
, BufferPtr
, Blocking
);
679 if (Subtask
== NULL
) {
682 InsertTailList (Subtasks
, &Subtask
->Link
);
684 BufferPtr
+= DataBufferSize
;
685 Offset
+= DataBufferSize
;
686 BufferSize
-= DataBufferSize
;
689 WorkingBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), IoAlign
);
690 if (WorkingBuffer
== NULL
) {
692 // If there is not enough memory, downgrade to blocking access
694 DEBUG ((EFI_D_VERBOSE
, "DiskIo: No enough memory so downgrade to blocking access\n"));
695 if (!DiskIoCreateSubtaskList (Instance
, Write
, Offset
, BufferSize
, BufferPtr
, TRUE
, SharedWorkingBuffer
, Subtasks
)) {
699 Subtask
= DiskIoCreateSubtask (Write
, Lba
, 0, BufferSize
, WorkingBuffer
, BufferPtr
, Blocking
);
700 if (Subtask
== NULL
) {
703 InsertTailList (Subtasks
, &Subtask
->Link
);
706 BufferPtr
+= BufferSize
;
707 Offset
+= BufferSize
;
708 BufferSize
-= BufferSize
;
713 ASSERT (BufferSize
== 0);
719 // Remove all the subtasks.
721 for (Link
= GetFirstNode (Subtasks
); !IsNull (Subtasks
, Link
); ) {
722 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
723 Link
= DiskIoDestroySubtask (Instance
, Subtask
);
729 Terminate outstanding asynchronous requests to a device.
731 @param This Indicates a pointer to the calling context.
733 @retval EFI_SUCCESS All outstanding requests were successfully terminated.
734 @retval EFI_DEVICE_ERROR The device reported an error while performing the cancel
740 IN EFI_DISK_IO2_PROTOCOL
*This
743 DISK_IO_PRIVATE_DATA
*Instance
;
747 Instance
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
);
749 EfiAcquireLock (&Instance
->TaskQueueLock
);
751 for (Link
= GetFirstNode (&Instance
->TaskQueue
)
752 ; !IsNull (&Instance
->TaskQueue
, Link
)
753 ; Link
= GetNextNode (&Instance
->TaskQueue
, Link
)
755 Task
= CR (Link
, DISK_IO2_TASK
, Link
, DISK_IO2_TASK_SIGNATURE
);
757 if (Task
->Token
!= NULL
) {
758 Task
->Token
->TransactionStatus
= EFI_ABORTED
;
759 gBS
->SignalEvent (Task
->Token
->Event
);
761 // Set Token to NULL so that the further BlockIo2 responses will be ignored
767 EfiReleaseLock (&Instance
->TaskQueueLock
);
773 Common routine to access the disk.
775 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
776 @param Write TRUE: Write operation; FALSE: Read operation.
777 @param MediaId ID of the medium to access.
778 @param Offset The starting byte offset on the logical block I/O device to access.
779 @param Token A pointer to the token associated with the transaction.
780 If this field is NULL, synchronous/blocking IO is performed.
781 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
782 @param Buffer A pointer to the destination buffer for the data.
783 The caller is responsible either having implicit or explicit ownership of the buffer.
786 DiskIo2ReadWriteDisk (
787 IN DISK_IO_PRIVATE_DATA
*Instance
,
791 IN EFI_DISK_IO2_TOKEN
*Token
,
797 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
798 EFI_BLOCK_IO2_PROTOCOL
*BlockIo2
;
799 EFI_BLOCK_IO_MEDIA
*Media
;
802 DISK_IO_SUBTASK
*Subtask
;
804 BOOLEAN TaskQueueEmpty
;
807 LIST_ENTRY
*SubtasksPtr
;
810 BlockIo
= Instance
->BlockIo
;
811 BlockIo2
= Instance
->BlockIo2
;
812 Media
= BlockIo
->Media
;
813 Status
= EFI_SUCCESS
;
814 Blocking
= ((Token
== NULL
) || (Token
->Event
== NULL
));
816 if (Media
->MediaId
!= MediaId
) {
817 return EFI_MEDIA_CHANGED
;
820 if (Write
&& Media
->ReadOnly
) {
821 return EFI_WRITE_PROTECTED
;
826 // Wait till pending async task is completed.
829 EfiAcquireLock (&Instance
->TaskQueueLock
);
830 TaskQueueEmpty
= IsListEmpty (&Instance
->TaskQueue
);
831 EfiReleaseLock (&Instance
->TaskQueueLock
);
832 } while (!TaskQueueEmpty
);
834 SubtasksPtr
= &Subtasks
;
836 Task
= AllocatePool (sizeof (DISK_IO2_TASK
));
838 return EFI_OUT_OF_RESOURCES
;
841 EfiAcquireLock (&Instance
->TaskQueueLock
);
842 InsertTailList (&Instance
->TaskQueue
, &Task
->Link
);
843 EfiReleaseLock (&Instance
->TaskQueueLock
);
845 Task
->Signature
= DISK_IO2_TASK_SIGNATURE
;
846 Task
->Instance
= Instance
;
849 SubtasksPtr
= &Task
->Subtasks
;
852 InitializeListHead (SubtasksPtr
);
853 if (!DiskIoCreateSubtaskList (Instance
, Write
, Offset
, BufferSize
, Buffer
, Blocking
, Instance
->SharedWorkingBuffer
, SubtasksPtr
)) {
857 return EFI_OUT_OF_RESOURCES
;
859 ASSERT (!IsListEmpty (SubtasksPtr
));
861 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
862 for (Link
= GetFirstNode (SubtasksPtr
); !IsNull (SubtasksPtr
, Link
); Link
= GetNextNode (SubtasksPtr
, Link
)) {
863 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
865 if (!Subtask
->Blocking
) {
866 Subtask
->Task
= Task
;
869 if (Subtask
->Write
) {
873 if (Subtask
->WorkingBuffer
!= NULL
) {
875 // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
877 CopyMem (Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Buffer
, Subtask
->Length
);
880 if (Subtask
->Blocking
) {
881 Status
= BlockIo
->WriteBlocks (
885 Subtask
->Length
< Media
->BlockSize
? Media
->BlockSize
: Subtask
->Length
,
886 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
889 Status
= BlockIo2
->WriteBlocksEx (
893 &Subtask
->BlockIo2Token
,
894 Subtask
->Length
< Media
->BlockSize
? Media
->BlockSize
: Subtask
->Length
,
895 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
903 if (Subtask
->Blocking
) {
904 Status
= BlockIo
->ReadBlocks (
908 Subtask
->Length
< Media
->BlockSize
? Media
->BlockSize
: Subtask
->Length
,
909 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
911 if (!EFI_ERROR (Status
) && (Subtask
->WorkingBuffer
!= NULL
)) {
912 CopyMem (Subtask
->Buffer
, Subtask
->WorkingBuffer
+ Subtask
->Offset
, Subtask
->Length
);
915 Status
= BlockIo2
->ReadBlocksEx (
919 &Subtask
->BlockIo2Token
,
920 Subtask
->Length
< Media
->BlockSize
? Media
->BlockSize
: Subtask
->Length
,
921 (Subtask
->WorkingBuffer
!= NULL
) ? Subtask
->WorkingBuffer
: Subtask
->Buffer
926 if (EFI_ERROR (Status
)) {
931 gBS
->RaiseTPL (TPL_NOTIFY
);
934 // Remove all the remaining subtasks when failure.
935 // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
937 if (EFI_ERROR (Status
)) {
938 while (!IsNull (SubtasksPtr
, Link
)) {
939 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
940 Link
= DiskIoDestroySubtask (Instance
, Subtask
);
945 // Remove all the blocking subtasks because the non-blocking callback only removes the non-blocking subtask.
947 for (Link
= GetFirstNode (SubtasksPtr
); !IsNull (SubtasksPtr
, Link
); ) {
948 Subtask
= CR (Link
, DISK_IO_SUBTASK
, Link
, DISK_IO_SUBTASK_SIGNATURE
);
949 if (Subtask
->Blocking
) {
950 Link
= DiskIoDestroySubtask (Instance
, Subtask
);
952 Link
= GetNextNode (SubtasksPtr
, Link
);
957 // It's possible that the callback runs before raising TPL to NOTIFY,
958 // so the subtasks list only contains blocking subtask.
959 // Remove the Task after the blocking subtasks are removed in above.
961 if (!Blocking
&& IsListEmpty (SubtasksPtr
)) {
962 EfiAcquireLock (&Instance
->TaskQueueLock
);
963 RemoveEntryList (&Task
->Link
);
964 EfiReleaseLock (&Instance
->TaskQueueLock
);
966 if (Task
->Token
!= NULL
) {
968 // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
969 // It it's not, that means the non-blocking request was downgraded to blocking request.
971 DEBUG ((EFI_D_VERBOSE
, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
972 Task
->Token
->TransactionStatus
= Status
;
973 gBS
->SignalEvent (Task
->Token
->Event
);
979 gBS
->RestoreTPL (OldTpl
);
985 Reads a specified number of bytes from a device.
987 @param This Indicates a pointer to the calling context.
988 @param MediaId ID of the medium to be read.
989 @param Offset The starting byte offset on the logical block I/O device to read from.
990 @param Token A pointer to the token associated with the transaction.
991 If this field is NULL, synchronous/blocking IO is performed.
992 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
993 @param Buffer A pointer to the destination buffer for the data.
994 The caller is responsible either having implicit or explicit ownership of the buffer.
996 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device.
997 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
998 Event will be signaled upon completion.
999 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1000 @retval EFI_NO_MEDIA There is no medium in the device.
1001 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
1002 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
1003 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1009 IN EFI_DISK_IO2_PROTOCOL
*This
,
1012 IN OUT EFI_DISK_IO2_TOKEN
*Token
,
1013 IN UINTN BufferSize
,
1017 return DiskIo2ReadWriteDisk (
1018 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
),
1019 FALSE
, MediaId
, Offset
, Token
, BufferSize
, (UINT8
*) Buffer
1024 Writes a specified number of bytes to a device.
1026 @param This Indicates a pointer to the calling context.
1027 @param MediaId ID of the medium to be written.
1028 @param Offset The starting byte offset on the logical block I/O device to write to.
1029 @param Token A pointer to the token associated with the transaction.
1030 If this field is NULL, synchronous/blocking IO is performed.
1031 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
1032 @param Buffer A pointer to the buffer containing the data to be written.
1034 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to the device.
1035 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1036 Event will be signaled upon completion.
1037 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1038 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
1039 @retval EFI_NO_MEDIA There is no medium in the device.
1040 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
1041 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
1042 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1047 DiskIo2WriteDiskEx (
1048 IN EFI_DISK_IO2_PROTOCOL
*This
,
1051 IN OUT EFI_DISK_IO2_TOKEN
*Token
,
1052 IN UINTN BufferSize
,
1056 return DiskIo2ReadWriteDisk (
1057 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
),
1058 TRUE
, MediaId
, Offset
, Token
, BufferSize
, (UINT8
*) Buffer
1063 The callback for the BlockIo2 FlushBlocksEx.
1064 @param Event Event whose notification function is being invoked.
1065 @param Context The pointer to the notification function's context,
1066 which points to the DISK_IO2_FLUSH_TASK instance.
1070 DiskIo2OnFlushComplete (
1075 DISK_IO2_FLUSH_TASK
*Task
;
1077 gBS
->CloseEvent (Event
);
1079 Task
= (DISK_IO2_FLUSH_TASK
*) Context
;
1080 ASSERT (Task
->Signature
== DISK_IO2_FLUSH_TASK_SIGNATURE
);
1081 Task
->Token
->TransactionStatus
= Task
->BlockIo2Token
.TransactionStatus
;
1082 gBS
->SignalEvent (Task
->Token
->Event
);
1086 Flushes all modified data to the physical device.
1088 @param This Indicates a pointer to the calling context.
1089 @param Token A pointer to the token associated with the transaction.
1090 If this field is NULL, synchronous/blocking IO is performed.
1092 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device.
1093 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1094 Event will be signaled upon completion.
1095 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1096 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
1097 @retval EFI_NO_MEDIA There is no medium in the device.
1098 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1102 DiskIo2FlushDiskEx (
1103 IN EFI_DISK_IO2_PROTOCOL
*This
,
1104 IN OUT EFI_DISK_IO2_TOKEN
*Token
1108 DISK_IO2_FLUSH_TASK
*Task
;
1109 DISK_IO_PRIVATE_DATA
*Private
;
1111 Private
= DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This
);
1113 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1114 Task
= AllocatePool (sizeof (DISK_IO2_FLUSH_TASK
));
1116 return EFI_OUT_OF_RESOURCES
;
1119 Status
= gBS
->CreateEvent (
1122 DiskIo2OnFlushComplete
,
1124 &Task
->BlockIo2Token
.Event
1126 if (EFI_ERROR (Status
)) {
1130 Task
->Signature
= DISK_IO2_FLUSH_TASK_SIGNATURE
;
1131 Status
= Private
->BlockIo2
->FlushBlocksEx (Private
->BlockIo2
, &Task
->BlockIo2Token
);
1132 if (EFI_ERROR (Status
)) {
1133 gBS
->CloseEvent (Task
->BlockIo2Token
.Event
);
1137 Status
= Private
->BlockIo2
->FlushBlocksEx (Private
->BlockIo2
, NULL
);
1144 Read BufferSize bytes from Offset into Buffer.
1145 Reads may support reads that are not aligned on
1146 sector boundaries. There are three cases:
1147 UnderRun - The first byte is not on a sector boundary or the read request is
1148 less than a sector in length.
1149 Aligned - A read of N contiguous sectors.
1150 OverRun - The last byte is not on a sector boundary.
1152 @param This Protocol instance pointer.
1153 @param MediaId Id of the media, changes every time the media is replaced.
1154 @param Offset The starting byte offset to read from
1155 @param BufferSize Size of Buffer
1156 @param Buffer Buffer containing read data
1158 @retval EFI_SUCCESS The data was read correctly from the device.
1159 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
1160 @retval EFI_NO_MEDIA There is no media in the device.
1161 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1162 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
1163 valid for the device.
1169 IN EFI_DISK_IO_PROTOCOL
*This
,
1172 IN UINTN BufferSize
,
1176 return DiskIo2ReadWriteDisk (
1177 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This
),
1178 FALSE
, MediaId
, Offset
, NULL
, BufferSize
, (UINT8
*) Buffer
1184 Writes BufferSize bytes from Buffer into Offset.
1185 Writes may require a read modify write to support writes that are not
1186 aligned on sector boundaries. There are three cases:
1187 UnderRun - The first byte is not on a sector boundary or the write request
1188 is less than a sector in length. Read modify write is required.
1189 Aligned - A write of N contiguous sectors.
1190 OverRun - The last byte is not on a sector boundary. Read modified write
1193 @param This Protocol instance pointer.
1194 @param MediaId Id of the media, changes every time the media is replaced.
1195 @param Offset The starting byte offset to read from
1196 @param BufferSize Size of Buffer
1197 @param Buffer Buffer containing read data
1199 @retval EFI_SUCCESS The data was written correctly to the device.
1200 @retval EFI_WRITE_PROTECTED The device can not be written to.
1201 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1202 @retval EFI_NO_MEDIA There is no media in the device.
1203 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1204 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
1205 valid for the device.
1211 IN EFI_DISK_IO_PROTOCOL
*This
,
1214 IN UINTN BufferSize
,
1218 return DiskIo2ReadWriteDisk (
1219 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This
),
1220 TRUE
, MediaId
, Offset
, NULL
, BufferSize
, (UINT8
*) Buffer
1225 The user Entry Point for module DiskIo. The user code starts with this function.
1227 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1228 @param[in] SystemTable A pointer to the EFI System Table.
1230 @retval EFI_SUCCESS The entry point is executed successfully.
1231 @retval other Some error occurs when executing this entry point.
1237 IN EFI_HANDLE ImageHandle
,
1238 IN EFI_SYSTEM_TABLE
*SystemTable
1244 // Install driver model protocol(s).
1246 Status
= EfiLibInstallDriverBindingComponentName2 (
1249 &gDiskIoDriverBinding
,
1251 &gDiskIoComponentName
,
1252 &gDiskIoComponentName2
1254 ASSERT_EFI_ERROR (Status
);