TianoCore EDK2 master
Loading...
Searching...
No Matches
DiskIo.c
Go to the documentation of this file.
1
17#include "DiskIo.h"
18
19//
20// Driver binding protocol implementation for DiskIo driver.
21//
22EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
26 0xa,
27 NULL,
28 NULL
29};
30
31//
32// Template for DiskIo private data structure.
33// The pointer to BlockIo protocol interface is assigned dynamically.
34//
35DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate = {
36 DISK_IO_PRIVATE_DATA_SIGNATURE,
37 {
38 EFI_DISK_IO_PROTOCOL_REVISION,
41 },
42 {
43 EFI_DISK_IO2_PROTOCOL_REVISION,
48 }
49};
50
65EFIAPI
68 IN EFI_HANDLE ControllerHandle,
69 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
70 )
71{
72 EFI_STATUS Status;
73 EFI_BLOCK_IO_PROTOCOL *BlockIo;
74
75 //
76 // Open the IO Abstraction(s) needed to perform the supported test.
77 //
78 Status = gBS->OpenProtocol (
79 ControllerHandle,
80 &gEfiBlockIoProtocolGuid,
81 (VOID **)&BlockIo,
82 This->DriverBindingHandle,
83 ControllerHandle,
84 EFI_OPEN_PROTOCOL_BY_DRIVER
85 );
86 if (EFI_ERROR (Status)) {
87 return Status;
88 }
89
90 //
91 // Close the I/O Abstraction(s) used to perform the supported test.
92 //
93 gBS->CloseProtocol (
94 ControllerHandle,
95 &gEfiBlockIoProtocolGuid,
96 This->DriverBindingHandle,
97 ControllerHandle
98 );
99 return EFI_SUCCESS;
100}
101
117EFIAPI
120 IN EFI_HANDLE ControllerHandle,
121 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
122 )
123{
124 EFI_STATUS Status;
125 DISK_IO_PRIVATE_DATA *Instance;
126 EFI_TPL OldTpl;
127
128 Instance = NULL;
129
130 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
131
132 //
133 // Connect to the Block IO and Block IO2 interface on ControllerHandle.
134 //
135 Status = gBS->OpenProtocol (
136 ControllerHandle,
137 &gEfiBlockIoProtocolGuid,
138 (VOID **)&gDiskIoPrivateDataTemplate.BlockIo,
139 This->DriverBindingHandle,
140 ControllerHandle,
141 EFI_OPEN_PROTOCOL_BY_DRIVER
142 );
143 if (EFI_ERROR (Status)) {
144 goto ErrorExit1;
145 }
146
147 Status = gBS->OpenProtocol (
148 ControllerHandle,
149 &gEfiBlockIo2ProtocolGuid,
150 (VOID **)&gDiskIoPrivateDataTemplate.BlockIo2,
151 This->DriverBindingHandle,
152 ControllerHandle,
153 EFI_OPEN_PROTOCOL_BY_DRIVER
154 );
155 if (EFI_ERROR (Status)) {
156 gDiskIoPrivateDataTemplate.BlockIo2 = NULL;
157 }
158
159 //
160 // Initialize the Disk IO device instance.
161 //
162 Instance = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);
163 if (Instance == NULL) {
164 Status = EFI_OUT_OF_RESOURCES;
165 goto ErrorExit;
166 }
167
168 //
169 // The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.
170 //
171 ASSERT (
172 (Instance->BlockIo2 == NULL) ||
173 ((Instance->BlockIo->Media->IoAlign == Instance->BlockIo2->Media->IoAlign) &&
174 (Instance->BlockIo->Media->BlockSize == Instance->BlockIo2->Media->BlockSize)
175 )
176 );
177
178 InitializeListHead (&Instance->TaskQueue);
179 EfiInitializeLock (&Instance->TaskQueueLock, TPL_NOTIFY);
180 Instance->SharedWorkingBuffer = AllocateAlignedPages (
181 EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize),
182 Instance->BlockIo->Media->IoAlign
183 );
184 if (Instance->SharedWorkingBuffer == NULL) {
185 Status = EFI_OUT_OF_RESOURCES;
186 goto ErrorExit;
187 }
188
189 //
190 // Install protocol interfaces for the Disk IO device.
191 //
192 if (Instance->BlockIo2 != NULL) {
193 Status = gBS->InstallMultipleProtocolInterfaces (
194 &ControllerHandle,
195 &gEfiDiskIoProtocolGuid,
196 &Instance->DiskIo,
197 &gEfiDiskIo2ProtocolGuid,
198 &Instance->DiskIo2,
199 NULL
200 );
201 } else {
202 Status = gBS->InstallMultipleProtocolInterfaces (
203 &ControllerHandle,
204 &gEfiDiskIoProtocolGuid,
205 &Instance->DiskIo,
206 NULL
207 );
208 }
209
210ErrorExit:
211 if (EFI_ERROR (Status)) {
212 if ((Instance != NULL) && (Instance->SharedWorkingBuffer != NULL)) {
214 Instance->SharedWorkingBuffer,
215 EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
216 );
217 }
218
219 if (Instance != NULL) {
220 FreePool (Instance);
221 }
222
223 gBS->CloseProtocol (
224 ControllerHandle,
225 &gEfiBlockIoProtocolGuid,
226 This->DriverBindingHandle,
227 ControllerHandle
228 );
229 }
230
231ErrorExit1:
232 gBS->RestoreTPL (OldTpl);
233 return Status;
234}
235
251EFIAPI
254 IN EFI_HANDLE ControllerHandle,
255 IN UINTN NumberOfChildren,
256 IN EFI_HANDLE *ChildHandleBuffer
257 )
258{
259 EFI_STATUS Status;
260 EFI_DISK_IO_PROTOCOL *DiskIo;
261 EFI_DISK_IO2_PROTOCOL *DiskIo2;
262 DISK_IO_PRIVATE_DATA *Instance;
263 BOOLEAN AllTaskDone;
264
265 //
266 // Get our context back.
267 //
268 Status = gBS->OpenProtocol (
269 ControllerHandle,
270 &gEfiDiskIoProtocolGuid,
271 (VOID **)&DiskIo,
272 This->DriverBindingHandle,
273 ControllerHandle,
274 EFI_OPEN_PROTOCOL_GET_PROTOCOL
275 );
276 if (EFI_ERROR (Status)) {
277 return Status;
278 }
279
280 Status = gBS->OpenProtocol (
281 ControllerHandle,
282 &gEfiDiskIo2ProtocolGuid,
283 (VOID **)&DiskIo2,
284 This->DriverBindingHandle,
285 ControllerHandle,
286 EFI_OPEN_PROTOCOL_GET_PROTOCOL
287 );
288 if (EFI_ERROR (Status)) {
289 DiskIo2 = NULL;
290 }
291
292 Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo);
293
294 if (DiskIo2 != NULL) {
295 //
296 // Call BlockIo2::Reset() to terminate any in-flight non-blocking I/O requests
297 //
298 ASSERT (Instance->BlockIo2 != NULL);
299 Status = Instance->BlockIo2->Reset (Instance->BlockIo2, FALSE);
300 if (EFI_ERROR (Status)) {
301 return Status;
302 }
303
304 Status = gBS->UninstallMultipleProtocolInterfaces (
305 ControllerHandle,
306 &gEfiDiskIoProtocolGuid,
307 &Instance->DiskIo,
308 &gEfiDiskIo2ProtocolGuid,
309 &Instance->DiskIo2,
310 NULL
311 );
312 } else {
313 Status = gBS->UninstallMultipleProtocolInterfaces (
314 ControllerHandle,
315 &gEfiDiskIoProtocolGuid,
316 &Instance->DiskIo,
317 NULL
318 );
319 }
320
321 if (!EFI_ERROR (Status)) {
322 do {
323 EfiAcquireLock (&Instance->TaskQueueLock);
324 AllTaskDone = IsListEmpty (&Instance->TaskQueue);
325 EfiReleaseLock (&Instance->TaskQueueLock);
326 } while (!AllTaskDone);
327
329 Instance->SharedWorkingBuffer,
330 EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
331 );
332
333 Status = gBS->CloseProtocol (
334 ControllerHandle,
335 &gEfiBlockIoProtocolGuid,
336 This->DriverBindingHandle,
337 ControllerHandle
338 );
339 ASSERT_EFI_ERROR (Status);
340 if (DiskIo2 != NULL) {
341 Status = gBS->CloseProtocol (
342 ControllerHandle,
343 &gEfiBlockIo2ProtocolGuid,
344 This->DriverBindingHandle,
345 ControllerHandle
346 );
347 ASSERT_EFI_ERROR (Status);
348 }
349
350 FreePool (Instance);
351 }
352
353 return Status;
354}
355
366 IN DISK_IO_PRIVATE_DATA *Instance,
367 IN DISK_IO_SUBTASK *Subtask
368 )
369{
370 LIST_ENTRY *Link;
371
372 if (Subtask->Task != NULL) {
373 EfiAcquireLock (&Subtask->Task->SubtasksLock);
374 }
375
376 Link = RemoveEntryList (&Subtask->Link);
377 if (Subtask->Task != NULL) {
378 EfiReleaseLock (&Subtask->Task->SubtasksLock);
379 }
380
381 if (!Subtask->Blocking) {
382 if (Subtask->WorkingBuffer != NULL) {
384 Subtask->WorkingBuffer,
385 Subtask->Length < Instance->BlockIo->Media->BlockSize
386 ? EFI_SIZE_TO_PAGES (Instance->BlockIo->Media->BlockSize)
387 : EFI_SIZE_TO_PAGES (Subtask->Length)
388 );
389 }
390
391 if (Subtask->BlockIo2Token.Event != NULL) {
392 gBS->CloseEvent (Subtask->BlockIo2Token.Event);
393 }
394 }
395
396 FreePool (Subtask);
397
398 return Link;
399}
400
407VOID
408EFIAPI
410 IN EFI_EVENT Event,
411 IN VOID *Context
412 )
413{
414 DISK_IO_SUBTASK *Subtask;
415 DISK_IO2_TASK *Task;
416 EFI_STATUS TransactionStatus;
417 DISK_IO_PRIVATE_DATA *Instance;
418
419 Subtask = (DISK_IO_SUBTASK *)Context;
420 TransactionStatus = Subtask->BlockIo2Token.TransactionStatus;
421 Task = Subtask->Task;
422 Instance = Task->Instance;
423
424 ASSERT (Subtask->Signature == DISK_IO_SUBTASK_SIGNATURE);
425 ASSERT (Instance->Signature == DISK_IO_PRIVATE_DATA_SIGNATURE);
426 ASSERT (Task->Signature == DISK_IO2_TASK_SIGNATURE);
427
428 if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) &&
429 (Task->Token != NULL) && !Subtask->Write
430 )
431 {
432 CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
433 }
434
435 DiskIoDestroySubtask (Instance, Subtask);
436
437 if (EFI_ERROR (TransactionStatus) || IsListEmpty (&Task->Subtasks)) {
438 if (Task->Token != NULL) {
439 //
440 // Signal error status once the subtask is failed.
441 // Or signal the last status once the last subtask is finished.
442 //
443 Task->Token->TransactionStatus = TransactionStatus;
444 gBS->SignalEvent (Task->Token->Event);
445
446 //
447 // Mark token to NULL indicating the Task is a dead task.
448 //
449 Task->Token = NULL;
450 }
451 }
452}
453
469 IN BOOLEAN Write,
470 IN UINT64 Lba,
471 IN UINT32 Offset,
472 IN UINTN Length,
473 IN VOID *WorkingBuffer OPTIONAL,
474 IN VOID *Buffer,
475 IN BOOLEAN Blocking
476 )
477{
478 DISK_IO_SUBTASK *Subtask;
479 EFI_STATUS Status;
480
481 Subtask = AllocateZeroPool (sizeof (DISK_IO_SUBTASK));
482 if (Subtask == NULL) {
483 return NULL;
484 }
485
486 Subtask->Signature = DISK_IO_SUBTASK_SIGNATURE;
487 Subtask->Write = Write;
488 Subtask->Lba = Lba;
489 Subtask->Offset = Offset;
490 Subtask->Length = Length;
491 Subtask->WorkingBuffer = WorkingBuffer;
492 Subtask->Buffer = Buffer;
493 Subtask->Blocking = Blocking;
494 if (!Blocking) {
495 Status = gBS->CreateEvent (
496 EVT_NOTIFY_SIGNAL,
497 TPL_NOTIFY,
499 Subtask,
500 &Subtask->BlockIo2Token.Event
501 );
502 if (EFI_ERROR (Status)) {
503 FreePool (Subtask);
504 return NULL;
505 }
506 }
507
508 DEBUG ((
509 DEBUG_BLKIO,
510 " %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
511 Write ? 'W' : 'R',
512 Lba,
513 Offset,
514 Length,
515 WorkingBuffer,
516 Buffer
517 ));
518
519 return Subtask;
520}
521
537BOOLEAN
539 IN DISK_IO_PRIVATE_DATA *Instance,
540 IN BOOLEAN Write,
541 IN UINT64 Offset,
542 IN UINTN BufferSize,
543 IN VOID *Buffer,
544 IN BOOLEAN Blocking,
545 IN VOID *SharedWorkingBuffer,
546 IN OUT LIST_ENTRY *Subtasks
547 )
548{
549 UINT32 BlockSize;
550 UINT32 IoAlign;
551 UINT64 Lba;
552 UINT64 OverRunLba;
553 UINT32 UnderRun;
554 UINT32 OverRun;
555 UINT8 *BufferPtr;
556 UINTN Length;
557 UINTN DataBufferSize;
558 DISK_IO_SUBTASK *Subtask;
559 VOID *WorkingBuffer;
560 LIST_ENTRY *Link;
561
562 DEBUG ((DEBUG_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));
563
564 BlockSize = Instance->BlockIo->Media->BlockSize;
565 IoAlign = Instance->BlockIo->Media->IoAlign;
566 if (IoAlign == 0) {
567 IoAlign = 1;
568 }
569
570 Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);
571 BufferPtr = (UINT8 *)Buffer;
572
573 //
574 // Special handling for zero BufferSize
575 //
576 if (BufferSize == 0) {
577 Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, 0, NULL, BufferPtr, Blocking);
578 if (Subtask == NULL) {
579 goto Done;
580 }
581
582 InsertTailList (Subtasks, &Subtask->Link);
583 return TRUE;
584 }
585
586 if (UnderRun != 0) {
587 Length = MIN (BlockSize - UnderRun, BufferSize);
588 if (Blocking) {
589 WorkingBuffer = SharedWorkingBuffer;
590 } else {
591 WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
592 if (WorkingBuffer == NULL) {
593 goto Done;
594 }
595 }
596
597 if (Write) {
598 //
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
601 //
602 Subtask = DiskIoCreateSubtask (FALSE, Lba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
603 if (Subtask == NULL) {
604 goto Done;
605 }
606
607 InsertTailList (Subtasks, &Subtask->Link);
608 }
609
610 Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, Length, WorkingBuffer, BufferPtr, Blocking);
611 if (Subtask == NULL) {
612 goto Done;
613 }
614
615 InsertTailList (Subtasks, &Subtask->Link);
616
617 BufferPtr += Length;
618 Offset += Length;
619 BufferSize -= Length;
620 Lba++;
621 }
622
623 OverRunLba = Lba + DivU64x32Remainder (BufferSize, BlockSize, &OverRun);
624 BufferSize -= OverRun;
625
626 if (OverRun != 0) {
627 if (Blocking) {
628 WorkingBuffer = SharedWorkingBuffer;
629 } else {
630 WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
631 if (WorkingBuffer == NULL) {
632 goto Done;
633 }
634 }
635
636 if (Write) {
637 //
638 // A half write operation can be splitted to a blocking block-read and half write operation
639 // This can simplify the sub task processing logic
640 //
641 Subtask = DiskIoCreateSubtask (FALSE, OverRunLba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
642 if (Subtask == NULL) {
643 goto Done;
644 }
645
646 InsertTailList (Subtasks, &Subtask->Link);
647 }
648
649 Subtask = DiskIoCreateSubtask (Write, OverRunLba, 0, OverRun, WorkingBuffer, BufferPtr + BufferSize, Blocking);
650 if (Subtask == NULL) {
651 goto Done;
652 }
653
654 InsertTailList (Subtasks, &Subtask->Link);
655 }
656
657 if (OverRunLba > Lba) {
658 //
659 // If the DiskIo maps directly to a BlockIo device do the read.
660 //
661 if (ALIGN_POINTER (BufferPtr, IoAlign) == BufferPtr) {
662 Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, NULL, BufferPtr, Blocking);
663 if (Subtask == NULL) {
664 goto Done;
665 }
666
667 InsertTailList (Subtasks, &Subtask->Link);
668
669 BufferPtr += BufferSize;
670 Offset += BufferSize;
671 BufferSize -= BufferSize;
672 } else {
673 if (Blocking) {
674 //
675 // Use the allocated buffer instead of the original buffer
676 // to avoid alignment issue.
677 //
678 for ( ; Lba < OverRunLba; Lba += PcdGet32 (PcdDiskIoDataBufferBlockNum)) {
679 DataBufferSize = MIN (BufferSize, PcdGet32 (PcdDiskIoDataBufferBlockNum) * BlockSize);
680
681 Subtask = DiskIoCreateSubtask (Write, Lba, 0, DataBufferSize, SharedWorkingBuffer, BufferPtr, Blocking);
682 if (Subtask == NULL) {
683 goto Done;
684 }
685
686 InsertTailList (Subtasks, &Subtask->Link);
687
688 BufferPtr += DataBufferSize;
689 Offset += DataBufferSize;
690 BufferSize -= DataBufferSize;
691 }
692 } else {
693 WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), IoAlign);
694 if (WorkingBuffer == NULL) {
695 //
696 // If there is not enough memory, downgrade to blocking access
697 //
698 DEBUG ((DEBUG_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n"));
699 if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, BufferPtr, TRUE, SharedWorkingBuffer, Subtasks)) {
700 goto Done;
701 }
702 } else {
703 Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, WorkingBuffer, BufferPtr, Blocking);
704 if (Subtask == NULL) {
705 goto Done;
706 }
707
708 InsertTailList (Subtasks, &Subtask->Link);
709 }
710
711 BufferPtr += BufferSize;
712 Offset += BufferSize;
713 BufferSize -= BufferSize;
714 }
715 }
716 }
717
718 ASSERT (BufferSize == 0);
719
720 return TRUE;
721
722Done:
723 //
724 // Remove all the subtasks.
725 //
726 for (Link = GetFirstNode (Subtasks); !IsNull (Subtasks, Link); ) {
727 Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
728 Link = DiskIoDestroySubtask (Instance, Subtask);
729 }
730
731 return FALSE;
732}
733
744EFIAPI
747 )
748{
749 DISK_IO_PRIVATE_DATA *Instance;
750 DISK_IO2_TASK *Task;
751 LIST_ENTRY *Link;
752
753 Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
754
755 EfiAcquireLock (&Instance->TaskQueueLock);
756
757 for (Link = GetFirstNode (&Instance->TaskQueue)
758 ; !IsNull (&Instance->TaskQueue, Link)
759 ; Link = GetNextNode (&Instance->TaskQueue, Link)
760 )
761 {
762 Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
763
764 if (Task->Token != NULL) {
765 Task->Token->TransactionStatus = EFI_ABORTED;
766 gBS->SignalEvent (Task->Token->Event);
767 //
768 // Set Token to NULL so that the further BlockIo2 responses will be ignored
769 //
770 Task->Token = NULL;
771 }
772 }
773
774 EfiReleaseLock (&Instance->TaskQueueLock);
775
776 return EFI_SUCCESS;
777}
778
787BOOLEAN
789 IN DISK_IO_PRIVATE_DATA *Instance
790 )
791{
792 BOOLEAN QueueEmpty;
793 LIST_ENTRY *Link;
794 DISK_IO2_TASK *Task;
795
796 QueueEmpty = TRUE;
797
798 EfiAcquireLock (&Instance->TaskQueueLock);
799 for (Link = GetFirstNode (&Instance->TaskQueue); !IsNull (&Instance->TaskQueue, Link); ) {
800 Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
801 if (IsListEmpty (&Task->Subtasks)) {
802 Link = RemoveEntryList (&Task->Link);
803 ASSERT (Task->Token == NULL);
804 FreePool (Task);
805 } else {
806 Link = GetNextNode (&Instance->TaskQueue, Link);
807 QueueEmpty = FALSE;
808 }
809 }
810
811 EfiReleaseLock (&Instance->TaskQueueLock);
812
813 return QueueEmpty;
814}
815
831 IN DISK_IO_PRIVATE_DATA *Instance,
832 IN BOOLEAN Write,
833 IN UINT32 MediaId,
834 IN UINT64 Offset,
835 IN EFI_DISK_IO2_TOKEN *Token,
836 IN UINTN BufferSize,
837 IN UINT8 *Buffer
838 )
839{
840 EFI_STATUS Status;
841 EFI_BLOCK_IO_PROTOCOL *BlockIo;
842 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
843 EFI_BLOCK_IO_MEDIA *Media;
844 LIST_ENTRY *Link;
845 LIST_ENTRY *NextLink;
846 LIST_ENTRY Subtasks;
847 DISK_IO_SUBTASK *Subtask;
848 DISK_IO2_TASK *Task;
849 EFI_TPL SubtaskPerformTpl;
850 EFI_TPL SubtaskLockTpl;
851 BOOLEAN Blocking;
852 BOOLEAN SubtaskBlocking;
853 LIST_ENTRY *SubtasksPtr;
854
855 Task = NULL;
856 BlockIo = Instance->BlockIo;
857 BlockIo2 = Instance->BlockIo2;
858 Media = BlockIo->Media;
859 Status = EFI_SUCCESS;
860 Blocking = (BOOLEAN)((Token == NULL) || (Token->Event == NULL));
861
862 if (Blocking) {
863 //
864 // Wait till pending async task is completed.
865 //
866 while (!DiskIo2RemoveCompletedTask (Instance)) {
867 }
868
869 SubtasksPtr = &Subtasks;
870 } else {
872 Task = AllocatePool (sizeof (DISK_IO2_TASK));
873 if (Task == NULL) {
874 return EFI_OUT_OF_RESOURCES;
875 }
876
877 EfiAcquireLock (&Instance->TaskQueueLock);
878 InsertTailList (&Instance->TaskQueue, &Task->Link);
879 EfiReleaseLock (&Instance->TaskQueueLock);
880
881 Task->Signature = DISK_IO2_TASK_SIGNATURE;
882 Task->Instance = Instance;
883 Task->Token = Token;
884 EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY);
885
886 SubtasksPtr = &Task->Subtasks;
887 }
888
889 InitializeListHead (SubtasksPtr);
890 if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, Buffer, Blocking, Instance->SharedWorkingBuffer, SubtasksPtr)) {
891 if (Task != NULL) {
892 FreePool (Task);
893 }
894
895 return EFI_OUT_OF_RESOURCES;
896 }
897
898 ASSERT (!IsListEmpty (SubtasksPtr));
899
900 SubtaskPerformTpl = gBS->RaiseTPL (TPL_CALLBACK);
901 for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link)
902 ; !IsNull (SubtasksPtr, Link)
903 ; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink)
904 )
905 {
906 Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
907 Subtask->Task = Task;
908 SubtaskBlocking = Subtask->Blocking;
909
910 ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize));
911
912 if (Subtask->Write) {
913 //
914 // Write
915 //
916 if (Subtask->WorkingBuffer != NULL) {
917 //
918 // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
919 //
920 CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);
921 }
922
923 if (SubtaskBlocking) {
924 Status = BlockIo->WriteBlocks (
925 BlockIo,
926 MediaId,
927 Subtask->Lba,
928 (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
929 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
930 );
931 } else {
932 Status = BlockIo2->WriteBlocksEx (
933 BlockIo2,
934 MediaId,
935 Subtask->Lba,
936 &Subtask->BlockIo2Token,
937 (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
938 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
939 );
940 }
941 } else {
942 //
943 // Read
944 //
945 if (SubtaskBlocking) {
946 Status = BlockIo->ReadBlocks (
947 BlockIo,
948 MediaId,
949 Subtask->Lba,
950 (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
951 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
952 );
953 if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {
954 CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
955 }
956 } else {
957 Status = BlockIo2->ReadBlocksEx (
958 BlockIo2,
959 MediaId,
960 Subtask->Lba,
961 &Subtask->BlockIo2Token,
962 (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
963 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
964 );
965 }
966 }
967
968 if (SubtaskBlocking || EFI_ERROR (Status)) {
969 //
970 // Make sure the subtask list only contains non-blocking subtasks.
971 // Remove failed non-blocking subtasks as well because the callback won't be called.
972 //
973 DiskIoDestroySubtask (Instance, Subtask);
974 }
975
976 if (EFI_ERROR (Status)) {
977 break;
978 }
979 }
980
981 SubtaskLockTpl = gBS->RaiseTPL (TPL_NOTIFY);
982
983 //
984 // Remove all the remaining subtasks when failure.
985 // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
986 //
987 if (EFI_ERROR (Status)) {
988 while (!IsNull (SubtasksPtr, NextLink)) {
989 Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
990 NextLink = DiskIoDestroySubtask (Instance, Subtask);
991 }
992 }
993
994 //
995 // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
996 // so the subtasks list might be empty at this point.
997 //
998 if (!Blocking && IsListEmpty (SubtasksPtr)) {
999 EfiAcquireLock (&Instance->TaskQueueLock);
1000 RemoveEntryList (&Task->Link);
1001 EfiReleaseLock (&Instance->TaskQueueLock);
1002
1003 if (!EFI_ERROR (Status) && (Task->Token != NULL)) {
1004 //
1005 // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
1006 // It it's not, that means the non-blocking request was downgraded to blocking request.
1007 //
1008 DEBUG ((DEBUG_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
1009 Task->Token->TransactionStatus = Status;
1010 gBS->SignalEvent (Task->Token->Event);
1011 }
1012
1013 FreePool (Task);
1014 }
1015
1016 gBS->RestoreTPL (SubtaskLockTpl);
1017 gBS->RestoreTPL (SubtaskPerformTpl);
1018
1019 return Status;
1020}
1021
1045EFIAPI
1048 IN UINT32 MediaId,
1049 IN UINT64 Offset,
1050 IN OUT EFI_DISK_IO2_TOKEN *Token,
1051 IN UINTN BufferSize,
1052 OUT VOID *Buffer
1053 )
1054{
1055 return DiskIo2ReadWriteDisk (
1056 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
1057 FALSE,
1058 MediaId,
1059 Offset,
1060 Token,
1061 BufferSize,
1062 (UINT8 *)Buffer
1063 );
1064}
1065
1089EFIAPI
1092 IN UINT32 MediaId,
1093 IN UINT64 Offset,
1094 IN OUT EFI_DISK_IO2_TOKEN *Token,
1095 IN UINTN BufferSize,
1096 IN VOID *Buffer
1097 )
1098{
1099 return DiskIo2ReadWriteDisk (
1100 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
1101 TRUE,
1102 MediaId,
1103 Offset,
1104 Token,
1105 BufferSize,
1106 (UINT8 *)Buffer
1107 );
1108}
1109
1116VOID
1117EFIAPI
1119 IN EFI_EVENT Event,
1120 IN VOID *Context
1121 )
1122{
1123 DISK_IO2_FLUSH_TASK *Task;
1124
1125 gBS->CloseEvent (Event);
1126
1127 Task = (DISK_IO2_FLUSH_TASK *)Context;
1128 ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);
1129 Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;
1130 gBS->SignalEvent (Task->Token->Event);
1131
1132 FreePool (Task);
1133}
1134
1151EFIAPI
1155 )
1156{
1157 EFI_STATUS Status;
1158 DISK_IO2_FLUSH_TASK *Task;
1159 DISK_IO_PRIVATE_DATA *Private;
1160
1161 Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
1162
1163 if ((Token != NULL) && (Token->Event != NULL)) {
1164 Task = AllocatePool (sizeof (DISK_IO2_FLUSH_TASK));
1165 if (Task == NULL) {
1166 return EFI_OUT_OF_RESOURCES;
1167 }
1168
1169 Status = gBS->CreateEvent (
1170 EVT_NOTIFY_SIGNAL,
1171 TPL_CALLBACK,
1173 Task,
1174 &Task->BlockIo2Token.Event
1175 );
1176 if (EFI_ERROR (Status)) {
1177 FreePool (Task);
1178 return Status;
1179 }
1180
1181 Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE;
1182 Task->Token = Token;
1183 Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);
1184 if (EFI_ERROR (Status)) {
1185 gBS->CloseEvent (Task->BlockIo2Token.Event);
1186 FreePool (Task);
1187 }
1188 } else {
1189 Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, NULL);
1190 }
1191
1192 return Status;
1193}
1194
1219EFIAPI
1222 IN UINT32 MediaId,
1223 IN UINT64 Offset,
1224 IN UINTN BufferSize,
1225 OUT VOID *Buffer
1226 )
1227{
1228 return DiskIo2ReadWriteDisk (
1229 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
1230 FALSE,
1231 MediaId,
1232 Offset,
1233 NULL,
1234 BufferSize,
1235 (UINT8 *)Buffer
1236 );
1237}
1238
1265EFIAPI
1268 IN UINT32 MediaId,
1269 IN UINT64 Offset,
1270 IN UINTN BufferSize,
1271 IN VOID *Buffer
1272 )
1273{
1274 return DiskIo2ReadWriteDisk (
1275 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
1276 TRUE,
1277 MediaId,
1278 Offset,
1279 NULL,
1280 BufferSize,
1281 (UINT8 *)Buffer
1282 );
1283}
1284
1296EFIAPI
1298 IN EFI_HANDLE ImageHandle,
1299 IN EFI_SYSTEM_TABLE *SystemTable
1300 )
1301{
1302 EFI_STATUS Status;
1303
1304 //
1305 // Install driver model protocol(s).
1306 //
1308 ImageHandle,
1309 SystemTable,
1310 &gDiskIoDriverBinding,
1311 ImageHandle,
1312 &gDiskIoComponentName,
1313 &gDiskIoComponentName2
1314 );
1315 ASSERT_EFI_ERROR (Status);
1316
1317 return Status;
1318}
UINT64 UINTN
BOOLEAN EFIAPI IsNull(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:443
BOOLEAN EFIAPI IsListEmpty(IN CONST LIST_ENTRY *ListHead)
Definition: LinkedList.c:403
LIST_ENTRY *EFIAPI GetNextNode(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:333
LIST_ENTRY *EFIAPI GetFirstNode(IN CONST LIST_ENTRY *List)
Definition: LinkedList.c:298
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
UINT64 EFIAPI DivU64x32Remainder(IN UINT64 Dividend, IN UINT32 Divisor, OUT UINT32 *Remainder OPTIONAL)
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
EFI_STATUS EFIAPI DiskIo2WriteDiskEx(IN EFI_DISK_IO2_PROTOCOL *This, IN UINT32 MediaId, IN UINT64 Offset, IN OUT EFI_DISK_IO2_TOKEN *Token, IN UINTN BufferSize, IN VOID *Buffer)
Definition: DiskIo.c:1090
EFI_STATUS EFIAPI InitializeDiskIo(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: DiskIo.c:1297
BOOLEAN DiskIo2RemoveCompletedTask(IN DISK_IO_PRIVATE_DATA *Instance)
Definition: DiskIo.c:788
EFI_STATUS EFIAPI DiskIo2ReadDiskEx(IN EFI_DISK_IO2_PROTOCOL *This, IN UINT32 MediaId, IN UINT64 Offset, IN OUT EFI_DISK_IO2_TOKEN *Token, IN UINTN BufferSize, OUT VOID *Buffer)
Definition: DiskIo.c:1046
VOID EFIAPI DiskIo2OnFlushComplete(IN EFI_EVENT Event, IN VOID *Context)
Definition: DiskIo.c:1118
EFI_STATUS EFIAPI DiskIoWriteDisk(IN EFI_DISK_IO_PROTOCOL *This, IN UINT32 MediaId, IN UINT64 Offset, IN UINTN BufferSize, IN VOID *Buffer)
Definition: DiskIo.c:1266
VOID EFIAPI DiskIo2OnReadWriteComplete(IN EFI_EVENT Event, IN VOID *Context)
Definition: DiskIo.c:409
EFI_STATUS EFIAPI DiskIo2Cancel(IN EFI_DISK_IO2_PROTOCOL *This)
Definition: DiskIo.c:745
EFI_STATUS EFIAPI DiskIoReadDisk(IN EFI_DISK_IO_PROTOCOL *This, IN UINT32 MediaId, IN UINT64 Offset, IN UINTN BufferSize, OUT VOID *Buffer)
Definition: DiskIo.c:1220
EFI_STATUS EFIAPI DiskIoDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer)
Definition: DiskIo.c:252
DISK_IO_SUBTASK * DiskIoCreateSubtask(IN BOOLEAN Write, IN UINT64 Lba, IN UINT32 Offset, IN UINTN Length, IN VOID *WorkingBuffer OPTIONAL, IN VOID *Buffer, IN BOOLEAN Blocking)
Definition: DiskIo.c:468
EFI_STATUS EFIAPI DiskIo2FlushDiskEx(IN EFI_DISK_IO2_PROTOCOL *This, IN OUT EFI_DISK_IO2_TOKEN *Token)
Definition: DiskIo.c:1152
BOOLEAN DiskIoCreateSubtaskList(IN DISK_IO_PRIVATE_DATA *Instance, IN BOOLEAN Write, IN UINT64 Offset, IN UINTN BufferSize, IN VOID *Buffer, IN BOOLEAN Blocking, IN VOID *SharedWorkingBuffer, IN OUT LIST_ENTRY *Subtasks)
Definition: DiskIo.c:538
LIST_ENTRY * DiskIoDestroySubtask(IN DISK_IO_PRIVATE_DATA *Instance, IN DISK_IO_SUBTASK *Subtask)
Definition: DiskIo.c:365
EFI_STATUS DiskIo2ReadWriteDisk(IN DISK_IO_PRIVATE_DATA *Instance, IN BOOLEAN Write, IN UINT32 MediaId, IN UINT64 Offset, IN EFI_DISK_IO2_TOKEN *Token, IN UINTN BufferSize, IN UINT8 *Buffer)
Definition: DiskIo.c:830
EFI_STATUS EFIAPI DiskIoDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
Definition: DiskIo.c:66
EFI_STATUS EFIAPI DiskIoDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
Definition: DiskIo.c:118
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
VOID EFIAPI FreeAlignedPages(IN VOID *Buffer, IN UINTN Pages)
VOID *EFIAPI AllocateCopyPool(IN UINTN AllocationSize, IN CONST VOID *Buffer)
#define NULL
Definition: Base.h:319
#define MIN(a, b)
Definition: Base.h:1007
#define ALIGN_POINTER(Pointer, Alignment)
Definition: Base.h:963
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define CR(Record, TYPE, Field, TestSignature)
Definition: DebugLib.h:659
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
VOID *EFIAPI AllocateAlignedPages(IN UINTN Pages, IN UINTN Alignment)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
UINTN EFI_TPL
Definition: UefiBaseType.h:41
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
VOID EFIAPI EfiReleaseLock(IN EFI_LOCK *Lock)
Definition: UefiLib.c:499
VOID EFIAPI EfiAcquireLock(IN EFI_LOCK *Lock)
Definition: UefiLib.c:434
EFI_LOCK *EFIAPI EfiInitializeLock(IN OUT EFI_LOCK *Lock, IN EFI_TPL Priority)
Definition: UefiLib.c:405
EFI_STATUS EFIAPI EfiLibInstallDriverBindingComponentName2(IN CONST EFI_HANDLE ImageHandle, IN CONST EFI_SYSTEM_TABLE *SystemTable, IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, IN EFI_HANDLE DriverBindingHandle, IN CONST EFI_COMPONENT_NAME_PROTOCOL *ComponentName OPTIONAL, IN CONST EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2 OPTIONAL)
EFI_BLOCK_IO_MEDIA * Media
Definition: BlockIo2.h:187
EFI_BLOCK_IO_MEDIA * Media
Definition: BlockIo.h:224
EFI_LOCK SubtasksLock
< link to other task
Definition: DiskIo.h:48
EFI_DISK_IO2_TOKEN * Token
< header of subtasks
Definition: DiskIo.h:50
UINT8 * Buffer
< NULL indicates using "Buffer" directly
Definition: DiskIo.h:75
EFI_EVENT Event
Definition: BlockIo2.h:34
EFI_STATUS TransactionStatus
Definition: BlockIo2.h:39
UINT32 BlockSize
Definition: BlockIo.h:167