• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   DiskIo driver that lays on every BlockIo protocol in the system.
3   DiskIo converts a block oriented device to a byte oriented device.
4 
5   Disk access may have to handle unaligned request about sector boundaries.
6   There are three cases:
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.
11 
12 Copyright (c) 2006 - 2014, 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
17 
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.
20 
21 **/
22 
23 #include "DiskIo.h"
24 
25 //
26 // Driver binding protocol implementation for DiskIo driver.
27 //
28 EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
29   DiskIoDriverBindingSupported,
30   DiskIoDriverBindingStart,
31   DiskIoDriverBindingStop,
32   0xa,
33   NULL,
34   NULL
35 };
36 
37 //
38 // Template for DiskIo private data structure.
39 // The pointer to BlockIo protocol interface is assigned dynamically.
40 //
41 DISK_IO_PRIVATE_DATA        gDiskIoPrivateDataTemplate = {
42   DISK_IO_PRIVATE_DATA_SIGNATURE,
43   {
44     EFI_DISK_IO_PROTOCOL_REVISION,
45     DiskIoReadDisk,
46     DiskIoWriteDisk
47   },
48   {
49     EFI_DISK_IO2_PROTOCOL_REVISION,
50     DiskIo2Cancel,
51     DiskIo2ReadDiskEx,
52     DiskIo2WriteDiskEx,
53     DiskIo2FlushDiskEx
54   }
55 };
56 
57 /**
58   Test to see if this driver supports ControllerHandle.
59 
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
63                               device to start.
64 
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
68 
69 **/
70 EFI_STATUS
71 EFIAPI
DiskIoDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)72 DiskIoDriverBindingSupported (
73   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
74   IN EFI_HANDLE                   ControllerHandle,
75   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
76   )
77 {
78   EFI_STATUS            Status;
79   EFI_BLOCK_IO_PROTOCOL *BlockIo;
80 
81   //
82   // Open the IO Abstraction(s) needed to perform the supported test.
83   //
84   Status = gBS->OpenProtocol (
85                   ControllerHandle,
86                   &gEfiBlockIoProtocolGuid,
87                   (VOID **) &BlockIo,
88                   This->DriverBindingHandle,
89                   ControllerHandle,
90                   EFI_OPEN_PROTOCOL_BY_DRIVER
91                   );
92   if (EFI_ERROR (Status)) {
93     return Status;
94   }
95 
96   //
97   // Close the I/O Abstraction(s) used to perform the supported test.
98   //
99   gBS->CloseProtocol (
100          ControllerHandle,
101          &gEfiBlockIoProtocolGuid,
102          This->DriverBindingHandle,
103          ControllerHandle
104          );
105   return EFI_SUCCESS;
106 }
107 
108 
109 /**
110   Start this driver on ControllerHandle by opening a Block IO protocol and
111   installing a Disk IO protocol on ControllerHandle.
112 
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
116                                device to start.
117 
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
121 
122 **/
123 EFI_STATUS
124 EFIAPI
DiskIoDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)125 DiskIoDriverBindingStart (
126   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
127   IN EFI_HANDLE                   ControllerHandle,
128   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
129   )
130 {
131   EFI_STATUS            Status;
132   DISK_IO_PRIVATE_DATA  *Instance;
133   EFI_TPL               OldTpl;
134 
135   Instance = NULL;
136 
137   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
138 
139   //
140   // Connect to the Block IO and Block IO2 interface on ControllerHandle.
141   //
142   Status = gBS->OpenProtocol (
143                   ControllerHandle,
144                   &gEfiBlockIoProtocolGuid,
145                   (VOID **) &gDiskIoPrivateDataTemplate.BlockIo,
146                   This->DriverBindingHandle,
147                   ControllerHandle,
148                   EFI_OPEN_PROTOCOL_BY_DRIVER
149                   );
150   if (EFI_ERROR (Status)) {
151     goto ErrorExit1;
152   }
153 
154   Status = gBS->OpenProtocol (
155                   ControllerHandle,
156                   &gEfiBlockIo2ProtocolGuid,
157                   (VOID **) &gDiskIoPrivateDataTemplate.BlockIo2,
158                   This->DriverBindingHandle,
159                   ControllerHandle,
160                   EFI_OPEN_PROTOCOL_BY_DRIVER
161                   );
162   if (EFI_ERROR (Status)) {
163     gDiskIoPrivateDataTemplate.BlockIo2 = NULL;
164   }
165 
166   //
167   // Initialize the Disk IO device instance.
168   //
169   Instance = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);
170   if (Instance == NULL) {
171     Status = EFI_OUT_OF_RESOURCES;
172     goto ErrorExit;
173   }
174 
175   //
176   // The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.
177   //
178   ASSERT ((Instance->BlockIo2 == NULL) ||
179           ((Instance->BlockIo->Media->IoAlign == Instance->BlockIo2->Media->IoAlign) &&
180            (Instance->BlockIo->Media->BlockSize == Instance->BlockIo2->Media->BlockSize)
181           ));
182 
183   InitializeListHead (&Instance->TaskQueue);
184   EfiInitializeLock (&Instance->TaskQueueLock, TPL_NOTIFY);
185   Instance->SharedWorkingBuffer = AllocateAlignedPages (
186                                     EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize),
187                                     Instance->BlockIo->Media->IoAlign
188                                     );
189   if (Instance->SharedWorkingBuffer == NULL) {
190     Status = EFI_OUT_OF_RESOURCES;
191     goto ErrorExit;
192   }
193 
194   //
195   // Install protocol interfaces for the Disk IO device.
196   //
197   if (Instance->BlockIo2 != NULL) {
198     Status = gBS->InstallMultipleProtocolInterfaces (
199                     &ControllerHandle,
200                     &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
201                     &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
202                     NULL
203                     );
204   } else {
205     Status = gBS->InstallMultipleProtocolInterfaces (
206                     &ControllerHandle,
207                     &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
208                     NULL
209                     );
210   }
211 
212 ErrorExit:
213   if (EFI_ERROR (Status)) {
214     if (Instance != NULL && Instance->SharedWorkingBuffer != NULL) {
215       FreeAlignedPages (
216         Instance->SharedWorkingBuffer,
217         EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
218         );
219     }
220 
221     if (Instance != NULL) {
222       FreePool (Instance);
223     }
224 
225     gBS->CloseProtocol (
226            ControllerHandle,
227            &gEfiBlockIoProtocolGuid,
228            This->DriverBindingHandle,
229            ControllerHandle
230            );
231   }
232 
233 ErrorExit1:
234   gBS->RestoreTPL (OldTpl);
235   return Status;
236 }
237 
238 /**
239   Stop this driver on ControllerHandle by removing Disk IO protocol and closing
240   the Block IO protocol on ControllerHandle.
241 
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.
247 
248   @retval EFI_SUCCESS       This driver is removed ControllerHandle
249   @retval other             This driver was not removed from this device
250 
251 **/
252 EFI_STATUS
253 EFIAPI
DiskIoDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)254 DiskIoDriverBindingStop (
255   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
256   IN  EFI_HANDLE                     ControllerHandle,
257   IN  UINTN                          NumberOfChildren,
258   IN  EFI_HANDLE                     *ChildHandleBuffer
259   )
260 {
261   EFI_STATUS            Status;
262   EFI_DISK_IO_PROTOCOL  *DiskIo;
263   EFI_DISK_IO2_PROTOCOL *DiskIo2;
264   DISK_IO_PRIVATE_DATA  *Instance;
265   BOOLEAN               AllTaskDone;
266 
267   //
268   // Get our context back.
269   //
270   Status = gBS->OpenProtocol (
271                   ControllerHandle,
272                   &gEfiDiskIoProtocolGuid,
273                   (VOID **) &DiskIo,
274                   This->DriverBindingHandle,
275                   ControllerHandle,
276                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
277                   );
278   if (EFI_ERROR (Status)) {
279     return Status;
280   }
281   Status = gBS->OpenProtocol (
282                   ControllerHandle,
283                   &gEfiDiskIo2ProtocolGuid,
284                   (VOID **) &DiskIo2,
285                   This->DriverBindingHandle,
286                   ControllerHandle,
287                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
288                   );
289   if (EFI_ERROR (Status)) {
290     DiskIo2 = NULL;
291   }
292 
293   Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo);
294 
295   if (DiskIo2 != NULL) {
296     //
297     // Call BlockIo2::Reset() to terminate any in-flight non-blocking I/O requests
298     //
299     ASSERT (Instance->BlockIo2 != NULL);
300     Status = Instance->BlockIo2->Reset (Instance->BlockIo2, FALSE);
301     if (EFI_ERROR (Status)) {
302       return Status;
303     }
304     Status = gBS->UninstallMultipleProtocolInterfaces (
305                     ControllerHandle,
306                     &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
307                     &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
308                     NULL
309                     );
310   } else {
311     Status = gBS->UninstallMultipleProtocolInterfaces (
312                     ControllerHandle,
313                     &gEfiDiskIoProtocolGuid,  &Instance->DiskIo,
314                     NULL
315                     );
316   }
317   if (!EFI_ERROR (Status)) {
318 
319     do {
320       EfiAcquireLock (&Instance->TaskQueueLock);
321       AllTaskDone = IsListEmpty (&Instance->TaskQueue);
322       EfiReleaseLock (&Instance->TaskQueueLock);
323     } while (!AllTaskDone);
324 
325     FreeAlignedPages (
326       Instance->SharedWorkingBuffer,
327       EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
328       );
329 
330     Status = gBS->CloseProtocol (
331                     ControllerHandle,
332                     &gEfiBlockIoProtocolGuid,
333                     This->DriverBindingHandle,
334                     ControllerHandle
335                     );
336     ASSERT_EFI_ERROR (Status);
337     if (DiskIo2 != NULL) {
338       Status = gBS->CloseProtocol (
339                       ControllerHandle,
340                       &gEfiBlockIo2ProtocolGuid,
341                       This->DriverBindingHandle,
342                       ControllerHandle
343                       );
344       ASSERT_EFI_ERROR (Status);
345     }
346 
347     FreePool (Instance);
348   }
349 
350   return Status;
351 }
352 
353 
354 /**
355   Destroy the sub task.
356 
357   @param Instance     Pointer to the DISK_IO_PRIVATE_DATA.
358   @param Subtask      Subtask.
359 
360   @return LIST_ENTRY *  Pointer to the next link of subtask.
361 **/
362 LIST_ENTRY *
DiskIoDestroySubtask(IN DISK_IO_PRIVATE_DATA * Instance,IN DISK_IO_SUBTASK * Subtask)363 DiskIoDestroySubtask (
364   IN DISK_IO_PRIVATE_DATA     *Instance,
365   IN DISK_IO_SUBTASK          *Subtask
366   )
367 {
368   LIST_ENTRY               *Link;
369 
370   if (Subtask->Task != NULL) {
371     EfiAcquireLock (&Subtask->Task->SubtasksLock);
372   }
373   Link = RemoveEntryList (&Subtask->Link);
374   if (Subtask->Task != NULL) {
375     EfiReleaseLock (&Subtask->Task->SubtasksLock);
376   }
377 
378   if (!Subtask->Blocking) {
379     if (Subtask->WorkingBuffer != NULL) {
380       FreeAlignedPages (
381         Subtask->WorkingBuffer,
382         Subtask->Length < Instance->BlockIo->Media->BlockSize
383         ? EFI_SIZE_TO_PAGES (Instance->BlockIo->Media->BlockSize)
384         : EFI_SIZE_TO_PAGES (Subtask->Length)
385         );
386     }
387     if (Subtask->BlockIo2Token.Event != NULL) {
388       gBS->CloseEvent (Subtask->BlockIo2Token.Event);
389     }
390   }
391   FreePool (Subtask);
392 
393   return Link;
394 }
395 
396 /**
397   The callback for the BlockIo2 ReadBlocksEx/WriteBlocksEx.
398   @param  Event                 Event whose notification function is being invoked.
399   @param  Context               The pointer to the notification function's context,
400                                 which points to the DISK_IO_SUBTASK instance.
401 **/
402 VOID
403 EFIAPI
DiskIo2OnReadWriteComplete(IN EFI_EVENT Event,IN VOID * Context)404 DiskIo2OnReadWriteComplete (
405   IN EFI_EVENT            Event,
406   IN VOID                 *Context
407   )
408 {
409   DISK_IO_SUBTASK       *Subtask;
410   DISK_IO2_TASK         *Task;
411   EFI_STATUS            TransactionStatus;
412   DISK_IO_PRIVATE_DATA  *Instance;
413 
414   Subtask           = (DISK_IO_SUBTASK *) Context;
415   TransactionStatus = Subtask->BlockIo2Token.TransactionStatus;
416   Task              = Subtask->Task;
417   Instance          = Task->Instance;
418 
419   ASSERT (Subtask->Signature  == DISK_IO_SUBTASK_SIGNATURE);
420   ASSERT (Instance->Signature == DISK_IO_PRIVATE_DATA_SIGNATURE);
421   ASSERT (Task->Signature     == DISK_IO2_TASK_SIGNATURE);
422 
423   if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) &&
424       (Task->Token != NULL) && !Subtask->Write
425      ) {
426     CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
427   }
428 
429   DiskIoDestroySubtask (Instance, Subtask);
430 
431   if (EFI_ERROR (TransactionStatus) || IsListEmpty (&Task->Subtasks)) {
432     if (Task->Token != NULL) {
433       //
434       // Signal error status once the subtask is failed.
435       // Or signal the last status once the last subtask is finished.
436       //
437       Task->Token->TransactionStatus = TransactionStatus;
438       gBS->SignalEvent (Task->Token->Event);
439 
440       //
441       // Mark token to NULL indicating the Task is a dead task.
442       //
443       Task->Token = NULL;
444     }
445   }
446 }
447 
448 /**
449   Create the subtask.
450 
451   @param Write         TRUE: Write request; FALSE: Read request.
452   @param Lba           The starting logical block address to read from on the device.
453   @param Offset        The starting byte offset to read from the LBA.
454   @param Length        The number of bytes to read from the device.
455   @param WorkingBuffer The aligned buffer to hold the data for reading or writing.
456   @param Buffer        The buffer to hold the data for reading or writing.
457   @param Blocking      TRUE: Blocking request; FALSE: Non-blocking request.
458 
459   @return A pointer to the created subtask.
460 **/
461 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)462 DiskIoCreateSubtask (
463   IN BOOLEAN          Write,
464   IN UINT64           Lba,
465   IN UINT32           Offset,
466   IN UINTN            Length,
467   IN VOID             *WorkingBuffer,  OPTIONAL
468   IN VOID             *Buffer,
469   IN BOOLEAN          Blocking
470   )
471 {
472   DISK_IO_SUBTASK       *Subtask;
473   EFI_STATUS            Status;
474 
475   Subtask = AllocateZeroPool (sizeof (DISK_IO_SUBTASK));
476   if (Subtask == NULL) {
477     return NULL;
478   }
479   Subtask->Signature     = DISK_IO_SUBTASK_SIGNATURE;
480   Subtask->Write         = Write;
481   Subtask->Lba           = Lba;
482   Subtask->Offset        = Offset;
483   Subtask->Length        = Length;
484   Subtask->WorkingBuffer = WorkingBuffer;
485   Subtask->Buffer        = Buffer;
486   Subtask->Blocking      = Blocking;
487   if (!Blocking) {
488     Status = gBS->CreateEvent (
489                     EVT_NOTIFY_SIGNAL,
490                     TPL_NOTIFY,
491                     DiskIo2OnReadWriteComplete,
492                     Subtask,
493                     &Subtask->BlockIo2Token.Event
494                     );
495     if (EFI_ERROR (Status)) {
496       FreePool (Subtask);
497       return NULL;
498     }
499   }
500   DEBUG ((
501     EFI_D_BLKIO,
502     "  %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
503     Write ? 'W': 'R', Lba, Offset, Length, WorkingBuffer, Buffer
504     ));
505 
506   return Subtask;
507 }
508 
509 /**
510   Create the subtask list.
511 
512   @param Instance            Pointer to the DISK_IO_PRIVATE_DATA.
513   @param Write               TRUE: Write request; FALSE: Read request.
514   @param Offset              The starting byte offset to read from the device.
515   @param BufferSize          The size in bytes of Buffer. The number of bytes to read from the device.
516   @param Buffer              A pointer to the buffer for the data.
517   @param Blocking            TRUE: Blocking request; FALSE: Non-blocking request.
518   @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing.
519   @param Subtasks            The subtask list header.
520 
521   @retval TRUE  The subtask list is created successfully.
522   @retval FALSE The subtask list is not created.
523 **/
524 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)525 DiskIoCreateSubtaskList (
526   IN DISK_IO_PRIVATE_DATA  *Instance,
527   IN BOOLEAN               Write,
528   IN UINT64                Offset,
529   IN UINTN                 BufferSize,
530   IN VOID                  *Buffer,
531   IN BOOLEAN               Blocking,
532   IN VOID                  *SharedWorkingBuffer,
533   IN OUT LIST_ENTRY        *Subtasks
534   )
535 {
536   UINT32                BlockSize;
537   UINT32                IoAlign;
538   UINT64                Lba;
539   UINT64                OverRunLba;
540   UINT32                UnderRun;
541   UINT32                OverRun;
542   UINT8                 *BufferPtr;
543   UINTN                 Length;
544   UINTN                 DataBufferSize;
545   DISK_IO_SUBTASK       *Subtask;
546   VOID                  *WorkingBuffer;
547   LIST_ENTRY            *Link;
548 
549   DEBUG ((EFI_D_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));
550 
551   BlockSize = Instance->BlockIo->Media->BlockSize;
552   IoAlign   = Instance->BlockIo->Media->IoAlign;
553   if (IoAlign == 0) {
554     IoAlign = 1;
555   }
556 
557   Lba       = DivU64x32Remainder (Offset, BlockSize, &UnderRun);
558   BufferPtr = (UINT8 *) Buffer;
559 
560   //
561   // Special handling for zero BufferSize
562   //
563   if (BufferSize == 0) {
564     Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, 0, NULL, BufferPtr, Blocking);
565     if (Subtask == NULL) {
566       goto Done;
567     }
568     InsertTailList (Subtasks, &Subtask->Link);
569     return TRUE;
570   }
571 
572   if (UnderRun != 0) {
573     Length = MIN (BlockSize - UnderRun, BufferSize);
574     if (Blocking) {
575       WorkingBuffer = SharedWorkingBuffer;
576     } else {
577       WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
578       if (WorkingBuffer == NULL) {
579         goto Done;
580       }
581     }
582     if (Write) {
583       //
584       // A half write operation can be splitted to a blocking block-read and half write operation
585       // This can simplify the sub task processing logic
586       //
587       Subtask = DiskIoCreateSubtask (FALSE, Lba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
588       if (Subtask == NULL) {
589         goto Done;
590       }
591       InsertTailList (Subtasks, &Subtask->Link);
592     }
593 
594     Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, Length, WorkingBuffer, BufferPtr, Blocking);
595     if (Subtask == NULL) {
596       goto Done;
597     }
598     InsertTailList (Subtasks, &Subtask->Link);
599 
600     BufferPtr  += Length;
601     Offset     += Length;
602     BufferSize -= Length;
603     Lba ++;
604   }
605 
606   OverRunLba  = Lba + DivU64x32Remainder (BufferSize, BlockSize, &OverRun);
607   BufferSize -= OverRun;
608 
609   if (OverRun != 0) {
610     if (Blocking) {
611       WorkingBuffer = SharedWorkingBuffer;
612     } else {
613       WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
614       if (WorkingBuffer == NULL) {
615         goto Done;
616       }
617     }
618     if (Write) {
619       //
620       // A half write operation can be splitted to a blocking block-read and half write operation
621       // This can simplify the sub task processing logic
622       //
623       Subtask = DiskIoCreateSubtask (FALSE, OverRunLba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
624       if (Subtask == NULL) {
625         goto Done;
626       }
627       InsertTailList (Subtasks, &Subtask->Link);
628     }
629 
630     Subtask = DiskIoCreateSubtask (Write, OverRunLba, 0, OverRun, WorkingBuffer, BufferPtr + BufferSize, Blocking);
631     if (Subtask == NULL) {
632       goto Done;
633     }
634     InsertTailList (Subtasks, &Subtask->Link);
635   }
636 
637   if (OverRunLba > Lba) {
638     //
639     // If the DiskIo maps directly to a BlockIo device do the read.
640     //
641     if (ALIGN_POINTER (BufferPtr, IoAlign) == BufferPtr) {
642       Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, NULL, BufferPtr, Blocking);
643       if (Subtask == NULL) {
644         goto Done;
645       }
646       InsertTailList (Subtasks, &Subtask->Link);
647 
648       BufferPtr  += BufferSize;
649       Offset     += BufferSize;
650       BufferSize -= BufferSize;
651 
652     } else {
653       if (Blocking) {
654         //
655         // Use the allocated buffer instead of the original buffer
656         // to avoid alignment issue.
657         //
658         for (; Lba < OverRunLba; Lba += PcdGet32 (PcdDiskIoDataBufferBlockNum)) {
659           DataBufferSize = MIN (BufferSize, PcdGet32 (PcdDiskIoDataBufferBlockNum) * BlockSize);
660 
661           Subtask = DiskIoCreateSubtask (Write, Lba, 0, DataBufferSize, SharedWorkingBuffer, BufferPtr, Blocking);
662           if (Subtask == NULL) {
663             goto Done;
664           }
665           InsertTailList (Subtasks, &Subtask->Link);
666 
667           BufferPtr  += DataBufferSize;
668           Offset     += DataBufferSize;
669           BufferSize -= DataBufferSize;
670         }
671       } else {
672         WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), IoAlign);
673         if (WorkingBuffer == NULL) {
674           //
675           // If there is not enough memory, downgrade to blocking access
676           //
677           DEBUG ((EFI_D_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n"));
678           if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, BufferPtr, TRUE, SharedWorkingBuffer, Subtasks)) {
679             goto Done;
680           }
681         } else {
682           Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, WorkingBuffer, BufferPtr, Blocking);
683           if (Subtask == NULL) {
684             goto Done;
685           }
686           InsertTailList (Subtasks, &Subtask->Link);
687         }
688 
689         BufferPtr  += BufferSize;
690         Offset     += BufferSize;
691         BufferSize -= BufferSize;
692       }
693     }
694   }
695 
696   ASSERT (BufferSize == 0);
697 
698   return TRUE;
699 
700 Done:
701   //
702   // Remove all the subtasks.
703   //
704   for (Link = GetFirstNode (Subtasks); !IsNull (Subtasks, Link); ) {
705     Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
706     Link = DiskIoDestroySubtask (Instance, Subtask);
707   }
708   return FALSE;
709 }
710 
711 /**
712   Terminate outstanding asynchronous requests to a device.
713 
714   @param This                   Indicates a pointer to the calling context.
715 
716   @retval EFI_SUCCESS           All outstanding requests were successfully terminated.
717   @retval EFI_DEVICE_ERROR      The device reported an error while performing the cancel
718                                 operation.
719 **/
720 EFI_STATUS
721 EFIAPI
DiskIo2Cancel(IN EFI_DISK_IO2_PROTOCOL * This)722 DiskIo2Cancel (
723   IN EFI_DISK_IO2_PROTOCOL *This
724   )
725 {
726   DISK_IO_PRIVATE_DATA  *Instance;
727   DISK_IO2_TASK         *Task;
728   LIST_ENTRY            *Link;
729 
730   Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
731 
732   EfiAcquireLock (&Instance->TaskQueueLock);
733 
734   for (Link = GetFirstNode (&Instance->TaskQueue)
735     ; !IsNull (&Instance->TaskQueue, Link)
736     ; Link = GetNextNode (&Instance->TaskQueue, Link)
737     ) {
738     Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
739 
740     if (Task->Token != NULL) {
741       Task->Token->TransactionStatus = EFI_ABORTED;
742       gBS->SignalEvent (Task->Token->Event);
743       //
744       // Set Token to NULL so that the further BlockIo2 responses will be ignored
745       //
746       Task->Token = NULL;
747     }
748   }
749 
750   EfiReleaseLock (&Instance->TaskQueueLock);
751 
752   return EFI_SUCCESS;
753 }
754 
755 /**
756   Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks.
757 
758   @param Instance    Pointer to the DISK_IO_PRIVATE_DATA.
759 
760   @retval TRUE       The Instance->TaskQueue is empty after the completed tasks are removed.
761   @retval FALSE      The Instance->TaskQueue is not empty after the completed tasks are removed.
762 **/
763 BOOLEAN
DiskIo2RemoveCompletedTask(IN DISK_IO_PRIVATE_DATA * Instance)764 DiskIo2RemoveCompletedTask (
765   IN DISK_IO_PRIVATE_DATA     *Instance
766   )
767 {
768   BOOLEAN                     QueueEmpty;
769   LIST_ENTRY                  *Link;
770   DISK_IO2_TASK               *Task;
771 
772   QueueEmpty = TRUE;
773 
774   EfiAcquireLock (&Instance->TaskQueueLock);
775   for (Link = GetFirstNode (&Instance->TaskQueue); !IsNull (&Instance->TaskQueue, Link); ) {
776     Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
777     if (IsListEmpty (&Task->Subtasks)) {
778       Link = RemoveEntryList (&Task->Link);
779       ASSERT (Task->Token == NULL);
780       FreePool (Task);
781     } else {
782       Link = GetNextNode (&Instance->TaskQueue, Link);
783       QueueEmpty = FALSE;
784     }
785   }
786   EfiReleaseLock (&Instance->TaskQueueLock);
787 
788   return QueueEmpty;
789 }
790 
791 /**
792   Common routine to access the disk.
793 
794   @param Instance    Pointer to the DISK_IO_PRIVATE_DATA.
795   @param Write       TRUE: Write operation; FALSE: Read operation.
796   @param MediaId     ID of the medium to access.
797   @param Offset      The starting byte offset on the logical block I/O device to access.
798   @param Token       A pointer to the token associated with the transaction.
799                      If this field is NULL, synchronous/blocking IO is performed.
800   @param  BufferSize            The size in bytes of Buffer. The number of bytes to read from the device.
801   @param  Buffer                A pointer to the destination buffer for the data.
802                                 The caller is responsible either having implicit or explicit ownership of the buffer.
803 **/
804 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)805 DiskIo2ReadWriteDisk (
806   IN DISK_IO_PRIVATE_DATA     *Instance,
807   IN BOOLEAN                  Write,
808   IN UINT32                   MediaId,
809   IN UINT64                   Offset,
810   IN EFI_DISK_IO2_TOKEN       *Token,
811   IN UINTN                    BufferSize,
812   IN UINT8                    *Buffer
813   )
814 {
815   EFI_STATUS             Status;
816   EFI_BLOCK_IO_PROTOCOL  *BlockIo;
817   EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
818   EFI_BLOCK_IO_MEDIA     *Media;
819   LIST_ENTRY             *Link;
820   LIST_ENTRY             *NextLink;
821   LIST_ENTRY             Subtasks;
822   DISK_IO_SUBTASK        *Subtask;
823   DISK_IO2_TASK          *Task;
824   EFI_TPL                OldTpl;
825   BOOLEAN                Blocking;
826   BOOLEAN                SubtaskBlocking;
827   LIST_ENTRY             *SubtasksPtr;
828 
829   Task      = NULL;
830   BlockIo   = Instance->BlockIo;
831   BlockIo2  = Instance->BlockIo2;
832   Media     = BlockIo->Media;
833   Status    = EFI_SUCCESS;
834   Blocking  = (BOOLEAN) ((Token == NULL) || (Token->Event == NULL));
835 
836   if (!(Media->MediaPresent)) {
837     return EFI_NO_MEDIA;
838   }
839 
840   if (Media->MediaId != MediaId) {
841     return EFI_MEDIA_CHANGED;
842   }
843 
844   if (Write && Media->ReadOnly) {
845     return EFI_WRITE_PROTECTED;
846   }
847 
848   if (Blocking) {
849     //
850     // Wait till pending async task is completed.
851     //
852     while (!DiskIo2RemoveCompletedTask (Instance));
853 
854     SubtasksPtr = &Subtasks;
855   } else {
856     DiskIo2RemoveCompletedTask (Instance);
857     Task = AllocatePool (sizeof (DISK_IO2_TASK));
858     if (Task == NULL) {
859       return EFI_OUT_OF_RESOURCES;
860     }
861 
862     EfiAcquireLock (&Instance->TaskQueueLock);
863     InsertTailList (&Instance->TaskQueue, &Task->Link);
864     EfiReleaseLock (&Instance->TaskQueueLock);
865 
866     Task->Signature = DISK_IO2_TASK_SIGNATURE;
867     Task->Instance  = Instance;
868     Task->Token     = Token;
869     EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY);
870 
871     SubtasksPtr = &Task->Subtasks;
872   }
873 
874   InitializeListHead (SubtasksPtr);
875   if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, Buffer, Blocking, Instance->SharedWorkingBuffer, SubtasksPtr)) {
876     if (Task != NULL) {
877       FreePool (Task);
878     }
879     return EFI_OUT_OF_RESOURCES;
880   }
881   ASSERT (!IsListEmpty (SubtasksPtr));
882 
883   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
884   for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link)
885       ; !IsNull (SubtasksPtr, Link)
886       ; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink)
887       ) {
888     Subtask         = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
889     Subtask->Task   = Task;
890     SubtaskBlocking = Subtask->Blocking;
891 
892     ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize));
893 
894     if (Subtask->Write) {
895       //
896       // Write
897       //
898       if (Subtask->WorkingBuffer != NULL) {
899         //
900         // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
901         //
902         CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);
903       }
904 
905       if (SubtaskBlocking) {
906         Status = BlockIo->WriteBlocks (
907                             BlockIo,
908                             MediaId,
909                             Subtask->Lba,
910                             (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
911                             (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
912                             );
913       } else {
914         Status = BlockIo2->WriteBlocksEx (
915                              BlockIo2,
916                              MediaId,
917                              Subtask->Lba,
918                              &Subtask->BlockIo2Token,
919                              (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
920                              (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
921                              );
922       }
923 
924     } else {
925       //
926       // Read
927       //
928       if (SubtaskBlocking) {
929         Status = BlockIo->ReadBlocks (
930                             BlockIo,
931                             MediaId,
932                             Subtask->Lba,
933                             (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
934                             (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
935                             );
936         if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {
937           CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
938         }
939       } else {
940         Status = BlockIo2->ReadBlocksEx (
941                              BlockIo2,
942                              MediaId,
943                              Subtask->Lba,
944                              &Subtask->BlockIo2Token,
945                              (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
946                              (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
947                              );
948       }
949     }
950 
951     if (SubtaskBlocking || EFI_ERROR (Status)) {
952       //
953       // Make sure the subtask list only contains non-blocking subtasks.
954       // Remove failed non-blocking subtasks as well because the callback won't be called.
955       //
956       DiskIoDestroySubtask (Instance, Subtask);
957     }
958 
959     if (EFI_ERROR (Status)) {
960       break;
961     }
962   }
963 
964   gBS->RaiseTPL (TPL_NOTIFY);
965 
966   //
967   // Remove all the remaining subtasks when failure.
968   // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
969   //
970   if (EFI_ERROR (Status)) {
971     while (!IsNull (SubtasksPtr, NextLink)) {
972       Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
973       NextLink = DiskIoDestroySubtask (Instance, Subtask);
974     }
975   }
976 
977   //
978   // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
979   // so the subtasks list might be empty at this point.
980   //
981   if (!Blocking && IsListEmpty (SubtasksPtr)) {
982     EfiAcquireLock (&Instance->TaskQueueLock);
983     RemoveEntryList (&Task->Link);
984     EfiReleaseLock (&Instance->TaskQueueLock);
985 
986     if (!EFI_ERROR (Status) && (Task->Token != NULL)) {
987       //
988       // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
989       // It it's not, that means the non-blocking request was downgraded to blocking request.
990       //
991       DEBUG ((EFI_D_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
992       Task->Token->TransactionStatus = Status;
993       gBS->SignalEvent (Task->Token->Event);
994     }
995 
996     FreePool (Task);
997   }
998 
999   gBS->RestoreTPL (OldTpl);
1000 
1001   return Status;
1002 }
1003 
1004 /**
1005   Reads a specified number of bytes from a device.
1006 
1007   @param This                   Indicates a pointer to the calling context.
1008   @param MediaId                ID of the medium to be read.
1009   @param Offset                 The starting byte offset on the logical block I/O device to read from.
1010   @param Token                  A pointer to the token associated with the transaction.
1011                                 If this field is NULL, synchronous/blocking IO is performed.
1012   @param  BufferSize            The size in bytes of Buffer. The number of bytes to read from the device.
1013   @param  Buffer                A pointer to the destination buffer for the data.
1014                                 The caller is responsible either having implicit or explicit ownership of the buffer.
1015 
1016   @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was read correctly from the device.
1017                                 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1018                                                                          Event will be signaled upon completion.
1019   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
1020   @retval EFI_NO_MEDIA          There is no medium in the device.
1021   @retval EFI_MEDIA_CHNAGED     The MediaId is not for the current medium.
1022   @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
1023   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
1024 
1025 **/
1026 EFI_STATUS
1027 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)1028 DiskIo2ReadDiskEx (
1029   IN EFI_DISK_IO2_PROTOCOL        *This,
1030   IN UINT32                       MediaId,
1031   IN UINT64                       Offset,
1032   IN OUT EFI_DISK_IO2_TOKEN       *Token,
1033   IN UINTN                        BufferSize,
1034   OUT VOID                        *Buffer
1035   )
1036 {
1037   return DiskIo2ReadWriteDisk (
1038            DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
1039            FALSE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
1040            );
1041 }
1042 
1043 /**
1044   Writes a specified number of bytes to a device.
1045 
1046   @param This        Indicates a pointer to the calling context.
1047   @param MediaId     ID of the medium to be written.
1048   @param Offset      The starting byte offset on the logical block I/O device to write to.
1049   @param Token       A pointer to the token associated with the transaction.
1050                      If this field is NULL, synchronous/blocking IO is performed.
1051   @param BufferSize  The size in bytes of Buffer. The number of bytes to write to the device.
1052   @param Buffer      A pointer to the buffer containing the data to be written.
1053 
1054   @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was written correctly to the device.
1055                                 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1056                                                                          Event will be signaled upon completion.
1057   @retval EFI_WRITE_PROTECTED   The device cannot be written to.
1058   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write operation.
1059   @retval EFI_NO_MEDIA          There is no medium in the device.
1060   @retval EFI_MEDIA_CHNAGED     The MediaId is not for the current medium.
1061   @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
1062   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
1063 
1064 **/
1065 EFI_STATUS
1066 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)1067 DiskIo2WriteDiskEx (
1068   IN EFI_DISK_IO2_PROTOCOL        *This,
1069   IN UINT32                       MediaId,
1070   IN UINT64                       Offset,
1071   IN OUT EFI_DISK_IO2_TOKEN       *Token,
1072   IN UINTN                        BufferSize,
1073   IN VOID                         *Buffer
1074   )
1075 {
1076   return DiskIo2ReadWriteDisk (
1077            DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
1078            TRUE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
1079            );
1080 }
1081 
1082 /**
1083   The callback for the BlockIo2 FlushBlocksEx.
1084   @param  Event                 Event whose notification function is being invoked.
1085   @param  Context               The pointer to the notification function's context,
1086                                 which points to the DISK_IO2_FLUSH_TASK instance.
1087 **/
1088 VOID
1089 EFIAPI
DiskIo2OnFlushComplete(IN EFI_EVENT Event,IN VOID * Context)1090 DiskIo2OnFlushComplete (
1091   IN EFI_EVENT                 Event,
1092   IN VOID                      *Context
1093   )
1094 {
1095   DISK_IO2_FLUSH_TASK             *Task;
1096 
1097   gBS->CloseEvent (Event);
1098 
1099   Task = (DISK_IO2_FLUSH_TASK *) Context;
1100   ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);
1101   Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;
1102   gBS->SignalEvent (Task->Token->Event);
1103 
1104   FreePool (Task);
1105 }
1106 
1107 /**
1108   Flushes all modified data to the physical device.
1109 
1110   @param This        Indicates a pointer to the calling context.
1111   @param Token       A pointer to the token associated with the transaction.
1112                      If this field is NULL, synchronous/blocking IO is performed.
1113 
1114   @retval EFI_SUCCESS           If Event is NULL (blocking I/O): The data was flushed successfully to the device.
1115                                 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
1116                                                                          Event will be signaled upon completion.
1117   @retval EFI_WRITE_PROTECTED   The device cannot be written to.
1118   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write operation.
1119   @retval EFI_NO_MEDIA          There is no medium in the device.
1120   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
1121 **/
1122 EFI_STATUS
1123 EFIAPI
DiskIo2FlushDiskEx(IN EFI_DISK_IO2_PROTOCOL * This,IN OUT EFI_DISK_IO2_TOKEN * Token)1124 DiskIo2FlushDiskEx (
1125   IN EFI_DISK_IO2_PROTOCOL        *This,
1126   IN OUT EFI_DISK_IO2_TOKEN       *Token
1127   )
1128 {
1129   EFI_STATUS                      Status;
1130   DISK_IO2_FLUSH_TASK             *Task;
1131   DISK_IO_PRIVATE_DATA            *Private;
1132 
1133   Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
1134 
1135   if ((Token != NULL) && (Token->Event != NULL)) {
1136     Task = AllocatePool (sizeof (DISK_IO2_FLUSH_TASK));
1137     if (Task == NULL) {
1138       return EFI_OUT_OF_RESOURCES;
1139     }
1140 
1141     Status = gBS->CreateEvent (
1142                     EVT_NOTIFY_SIGNAL,
1143                     TPL_CALLBACK,
1144                     DiskIo2OnFlushComplete,
1145                     Task,
1146                     &Task->BlockIo2Token.Event
1147                     );
1148     if (EFI_ERROR (Status)) {
1149       FreePool (Task);
1150       return Status;
1151     }
1152     Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE;
1153     Task->Token     = Token;
1154     Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);
1155     if (EFI_ERROR (Status)) {
1156       gBS->CloseEvent (Task->BlockIo2Token.Event);
1157       FreePool (Task);
1158     }
1159   } else {
1160     Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, NULL);
1161   }
1162 
1163   return Status;
1164 }
1165 
1166 /**
1167   Read BufferSize bytes from Offset into Buffer.
1168   Reads may support reads that are not aligned on
1169   sector boundaries. There are three cases:
1170     UnderRun - The first byte is not on a sector boundary or the read request is
1171                less than a sector in length.
1172     Aligned  - A read of N contiguous sectors.
1173     OverRun  - The last byte is not on a sector boundary.
1174 
1175   @param  This                  Protocol instance pointer.
1176   @param  MediaId               Id of the media, changes every time the media is replaced.
1177   @param  Offset                The starting byte offset to read from
1178   @param  BufferSize            Size of Buffer
1179   @param  Buffer                Buffer containing read data
1180 
1181   @retval EFI_SUCCESS           The data was read correctly from the device.
1182   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
1183   @retval EFI_NO_MEDIA          There is no media in the device.
1184   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
1185   @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
1186                                 valid for the device.
1187 
1188 **/
1189 EFI_STATUS
1190 EFIAPI
DiskIoReadDisk(IN EFI_DISK_IO_PROTOCOL * This,IN UINT32 MediaId,IN UINT64 Offset,IN UINTN BufferSize,OUT VOID * Buffer)1191 DiskIoReadDisk (
1192   IN EFI_DISK_IO_PROTOCOL  *This,
1193   IN UINT32                MediaId,
1194   IN UINT64                Offset,
1195   IN UINTN                 BufferSize,
1196   OUT VOID                 *Buffer
1197   )
1198 {
1199   return DiskIo2ReadWriteDisk (
1200            DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
1201            FALSE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
1202            );
1203 }
1204 
1205 
1206 /**
1207   Writes BufferSize bytes from Buffer into Offset.
1208   Writes may require a read modify write to support writes that are not
1209   aligned on sector boundaries. There are three cases:
1210     UnderRun - The first byte is not on a sector boundary or the write request
1211                is less than a sector in length. Read modify write is required.
1212     Aligned  - A write of N contiguous sectors.
1213     OverRun  - The last byte is not on a sector boundary. Read modified write
1214                required.
1215 
1216   @param  This       Protocol instance pointer.
1217   @param  MediaId    Id of the media, changes every time the media is replaced.
1218   @param  Offset     The starting byte offset to read from
1219   @param  BufferSize Size of Buffer
1220   @param  Buffer     Buffer containing read data
1221 
1222   @retval EFI_SUCCESS           The data was written correctly to the device.
1223   @retval EFI_WRITE_PROTECTED   The device can not be written to.
1224   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
1225   @retval EFI_NO_MEDIA          There is no media in the device.
1226   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
1227   @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
1228                                  valid for the device.
1229 
1230 **/
1231 EFI_STATUS
1232 EFIAPI
DiskIoWriteDisk(IN EFI_DISK_IO_PROTOCOL * This,IN UINT32 MediaId,IN UINT64 Offset,IN UINTN BufferSize,IN VOID * Buffer)1233 DiskIoWriteDisk (
1234   IN EFI_DISK_IO_PROTOCOL  *This,
1235   IN UINT32                MediaId,
1236   IN UINT64                Offset,
1237   IN UINTN                 BufferSize,
1238   IN VOID                  *Buffer
1239   )
1240 {
1241   return DiskIo2ReadWriteDisk (
1242            DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
1243            TRUE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
1244            );
1245 }
1246 
1247 /**
1248   The user Entry Point for module DiskIo. The user code starts with this function.
1249 
1250   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
1251   @param[in] SystemTable    A pointer to the EFI System Table.
1252 
1253   @retval EFI_SUCCESS       The entry point is executed successfully.
1254   @retval other             Some error occurs when executing this entry point.
1255 
1256 **/
1257 EFI_STATUS
1258 EFIAPI
InitializeDiskIo(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1259 InitializeDiskIo (
1260   IN EFI_HANDLE           ImageHandle,
1261   IN EFI_SYSTEM_TABLE     *SystemTable
1262   )
1263 {
1264   EFI_STATUS              Status;
1265 
1266   //
1267   // Install driver model protocol(s).
1268   //
1269   Status = EfiLibInstallDriverBindingComponentName2 (
1270              ImageHandle,
1271              SystemTable,
1272              &gDiskIoDriverBinding,
1273              ImageHandle,
1274              &gDiskIoComponentName,
1275              &gDiskIoComponentName2
1276              );
1277   ASSERT_EFI_ERROR (Status);
1278 
1279   return Status;
1280 }
1281