add modules DiskIo, Partition and SecurityStub.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Disk / DiskIo / Dxe / diskio.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14   DiskIo.c\r
15 \r
16 Abstract:\r
17 \r
18   DiskIo driver that layers it's self on every Block IO protocol in the system.\r
19   DiskIo converts a block oriented device to a byte oriented device.\r
20 \r
21   ReadDisk may have to do reads that are not aligned on sector boundaries.\r
22   There are three cases:\r
23 \r
24     UnderRun - The first byte is not on a sector boundary or the read request is\r
25                less than a sector in length.\r
26 \r
27     Aligned  - A read of N contiguous sectors.\r
28 \r
29     OverRun  - The last byte is not on a sector boundary.\r
30 \r
31 --*/\r
32 \r
33 //\r
34 // Include common header file for this module.\r
35 //\r
36 #include "CommonHeader.h"\r
37 \r
38 #include "DiskIo.h"\r
39 \r
40 EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {\r
41   DiskIoDriverBindingSupported,\r
42   DiskIoDriverBindingStart,\r
43   DiskIoDriverBindingStop,\r
44   0xa,\r
45   NULL,\r
46   NULL\r
47 };\r
48 \r
49 DISK_IO_PRIVATE_DATA        gDiskIoPrivateDataTemplate = {\r
50   DISK_IO_PRIVATE_DATA_SIGNATURE,\r
51   {\r
52     EFI_DISK_IO_PROTOCOL_REVISION,\r
53     DiskIoReadDisk,\r
54     DiskIoWriteDisk\r
55   },\r
56   NULL\r
57 };\r
58 \r
59 EFI_STATUS\r
60 EFIAPI\r
61 DiskIoDriverBindingSupported (\r
62   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
63   IN EFI_HANDLE                   ControllerHandle,\r
64   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
65   )\r
66 /*++\r
67 \r
68   Routine Description:\r
69     Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
70     than contains a BlockIo protocol can be supported.\r
71 \r
72   Arguments:\r
73     This                - Protocol instance pointer.\r
74     ControllerHandle    - Handle of device to test.\r
75     RemainingDevicePath - Not used.\r
76 \r
77   Returns:\r
78     EFI_SUCCESS         - This driver supports this device.\r
79     EFI_ALREADY_STARTED - This driver is already running on this device.\r
80     other               - This driver does not support this device.\r
81 \r
82 --*/\r
83 {\r
84   EFI_STATUS            Status;\r
85   EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
86 \r
87   //\r
88   // Open the IO Abstraction(s) needed to perform the supported test.\r
89   //\r
90   Status = gBS->OpenProtocol (\r
91                   ControllerHandle,\r
92                   &gEfiBlockIoProtocolGuid,\r
93                   (VOID **) &BlockIo,\r
94                   This->DriverBindingHandle,\r
95                   ControllerHandle,\r
96                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
97                   );\r
98   if (EFI_ERROR (Status)) {\r
99     return Status;\r
100   }\r
101   //\r
102   // Close the I/O Abstraction(s) used to perform the supported test.\r
103   //\r
104   gBS->CloseProtocol (\r
105         ControllerHandle,\r
106         &gEfiBlockIoProtocolGuid,\r
107         This->DriverBindingHandle,\r
108         ControllerHandle\r
109         );\r
110   return EFI_SUCCESS;\r
111 }\r
112 \r
113 EFI_STATUS\r
114 EFIAPI\r
115 DiskIoDriverBindingStart (\r
116   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
117   IN EFI_HANDLE                   ControllerHandle,\r
118   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
119   )\r
120 /*++\r
121 \r
122   Routine Description:\r
123     Start this driver on ControllerHandle by opening a Block IO protocol and\r
124     installing a Disk IO protocol on ControllerHandle.\r
125 \r
126   Arguments:\r
127     This                - Protocol instance pointer.\r
128     ControllerHandle    - Handle of device to bind driver to.\r
129     RemainingDevicePath - Not used, always produce all possible children.\r
130 \r
131   Returns:\r
132     EFI_SUCCESS         - This driver is added to ControllerHandle.\r
133     EFI_ALREADY_STARTED - This driver is already running on ControllerHandle.\r
134     other               - This driver does not support this device.\r
135 \r
136 --*/\r
137 {\r
138   EFI_STATUS            Status;\r
139   DISK_IO_PRIVATE_DATA  *Private;\r
140 \r
141   Private = NULL;\r
142 \r
143   //\r
144   // Connect to the Block IO interface on ControllerHandle.\r
145   //\r
146   Status = gBS->OpenProtocol (\r
147                   ControllerHandle,\r
148                   &gEfiBlockIoProtocolGuid,\r
149                   (VOID **) &gDiskIoPrivateDataTemplate.BlockIo,\r
150                   This->DriverBindingHandle,\r
151                   ControllerHandle,\r
152                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
153                   );\r
154   if (EFI_ERROR (Status)) {\r
155     return Status;\r
156   }\r
157   //\r
158   // Initialize the Disk IO device instance.\r
159   //\r
160   Private = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);\r
161   if (Private == NULL) {\r
162     Status = EFI_OUT_OF_RESOURCES;\r
163     goto ErrorExit;\r
164   }\r
165   //\r
166   // Install protocol interfaces for the Disk IO device.\r
167   //\r
168   Status = gBS->InstallProtocolInterface (\r
169                   &ControllerHandle,\r
170                   &gEfiDiskIoProtocolGuid,\r
171                   EFI_NATIVE_INTERFACE,\r
172                   &Private->DiskIo\r
173                   );\r
174 \r
175 ErrorExit:\r
176   if (EFI_ERROR (Status)) {\r
177 \r
178     if (Private != NULL) {\r
179       FreePool (Private);\r
180     }\r
181 \r
182     gBS->CloseProtocol (\r
183           ControllerHandle,\r
184           &gEfiBlockIoProtocolGuid,\r
185           This->DriverBindingHandle,\r
186           ControllerHandle\r
187           );\r
188   }\r
189 \r
190   return Status;\r
191 }\r
192 \r
193 EFI_STATUS\r
194 EFIAPI\r
195 DiskIoDriverBindingStop (\r
196   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,\r
197   IN  EFI_HANDLE                     ControllerHandle,\r
198   IN  UINTN                          NumberOfChildren,\r
199   IN  EFI_HANDLE                     *ChildHandleBuffer\r
200   )\r
201 /*++\r
202 \r
203   Routine Description:\r
204     Stop this driver on ControllerHandle by removing Disk IO protocol and closing\r
205     the Block IO protocol on ControllerHandle.\r
206 \r
207   Arguments:\r
208     This              - Protocol instance pointer.\r
209     ControllerHandle  - Handle of device to stop driver on.\r
210     NumberOfChildren  - Not used.\r
211     ChildHandleBuffer - Not used.\r
212 \r
213   Returns:\r
214     EFI_SUCCESS         - This driver is removed ControllerHandle.\r
215     other               - This driver was not removed from this device.\r
216     EFI_UNSUPPORTED\r
217 \r
218 --*/\r
219 {\r
220   EFI_STATUS            Status;\r
221   EFI_DISK_IO_PROTOCOL  *DiskIo;\r
222   DISK_IO_PRIVATE_DATA  *Private;\r
223 \r
224   //\r
225   // Get our context back.\r
226   //\r
227   Status = gBS->OpenProtocol (\r
228                   ControllerHandle,\r
229                   &gEfiDiskIoProtocolGuid,\r
230                   (VOID **) &DiskIo,\r
231                   This->DriverBindingHandle,\r
232                   ControllerHandle,\r
233                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
234                   );\r
235   if (EFI_ERROR (Status)) {\r
236     return EFI_UNSUPPORTED;\r
237   }\r
238 \r
239   Private = DISK_IO_PRIVATE_DATA_FROM_THIS (DiskIo);\r
240 \r
241   Status = gBS->UninstallProtocolInterface (\r
242                   ControllerHandle,\r
243                   &gEfiDiskIoProtocolGuid,\r
244                   &Private->DiskIo\r
245                   );\r
246   if (!EFI_ERROR (Status)) {\r
247 \r
248     Status = gBS->CloseProtocol (\r
249                     ControllerHandle,\r
250                     &gEfiBlockIoProtocolGuid,\r
251                     This->DriverBindingHandle,\r
252                     ControllerHandle\r
253                     );\r
254   }\r
255 \r
256   if (!EFI_ERROR (Status)) {\r
257     FreePool (Private);\r
258   }\r
259 \r
260   return Status;\r
261 }\r
262 \r
263 EFI_STATUS\r
264 EFIAPI\r
265 DiskIoReadDisk (\r
266   IN EFI_DISK_IO_PROTOCOL  *This,\r
267   IN UINT32                MediaId,\r
268   IN UINT64                Offset,\r
269   IN UINTN                 BufferSize,\r
270   OUT VOID                 *Buffer\r
271   )\r
272 /*++\r
273 \r
274   Routine Description:\r
275     Read BufferSize bytes from Offset into Buffer.\r
276 \r
277     Reads may support reads that are not aligned on\r
278     sector boundaries. There are three cases:\r
279 \r
280       UnderRun - The first byte is not on a sector boundary or the read request is\r
281                  less than a sector in length.\r
282 \r
283       Aligned  - A read of N contiguous sectors.\r
284 \r
285       OverRun  - The last byte is not on a sector boundary.\r
286 \r
287 \r
288   Arguments:\r
289     This       - Protocol instance pointer.\r
290     MediaId    - Id of the media, changes every time the media is replaced.\r
291     Offset     - The starting byte offset to read from.\r
292     BufferSize - Size of Buffer.\r
293     Buffer     - Buffer containing read data.\r
294 \r
295   Returns:\r
296     EFI_SUCCESS           - The data was read correctly from the device.\r
297     EFI_DEVICE_ERROR      - The device reported an error while performing the read.\r
298     EFI_NO_MEDIA          - There is no media in the device.\r
299     EFI_MEDIA_CHNAGED     - The MediaId does not matched the current device.\r
300     EFI_INVALID_PARAMETER - The read request contains device addresses that are not\r
301                             valid for the device.\r
302     EFI_OUT_OF_RESOURCES\r
303 \r
304 --*/\r
305 {\r
306   EFI_STATUS            Status;\r
307   DISK_IO_PRIVATE_DATA  *Private;\r
308   EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
309   EFI_BLOCK_IO_MEDIA    *Media;\r
310   UINT32                BlockSize;\r
311   UINT64                Lba;\r
312   UINT64                OverRunLba;\r
313   UINT32                UnderRun;\r
314   UINT32                OverRun;\r
315   BOOLEAN               TransactionComplete;\r
316   UINTN                 WorkingBufferSize;\r
317   UINT8                 *WorkingBuffer;\r
318   UINTN                 Length;\r
319   UINT8                 *Data;\r
320   UINT8                 *PreData;\r
321   UINTN                 IsBufferAligned;\r
322   UINTN                 DataBufferSize;\r
323   BOOLEAN               LastRead;\r
324 \r
325   Private   = DISK_IO_PRIVATE_DATA_FROM_THIS (This);\r
326 \r
327   BlockIo   = Private->BlockIo;\r
328   Media     = BlockIo->Media;\r
329   BlockSize = Media->BlockSize;\r
330 \r
331   if (Media->MediaId != MediaId) {\r
332     return EFI_MEDIA_CHANGED;\r
333   }\r
334 \r
335   WorkingBuffer     = Buffer;\r
336   WorkingBufferSize = BufferSize;\r
337 \r
338   //\r
339   // Allocate a temporary buffer for operation\r
340   //\r
341   DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM;\r
342 \r
343   if (Media->IoAlign > 1) {\r
344     PreData = AllocatePool (DataBufferSize + Media->IoAlign);\r
345     Data    = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign;\r
346   } else {\r
347     PreData = AllocatePool (DataBufferSize);\r
348     Data    = PreData;\r
349   }\r
350 \r
351   if (PreData == NULL) {\r
352     return EFI_OUT_OF_RESOURCES;\r
353   }\r
354 \r
355   Lba                 = DivU64x32Remainder (Offset, BlockSize, &UnderRun);\r
356 \r
357   Length              = BlockSize - UnderRun;\r
358   TransactionComplete = FALSE;\r
359 \r
360   Status              = EFI_SUCCESS;\r
361   if (UnderRun != 0) {\r
362     //\r
363     // Offset starts in the middle of an Lba, so read the entire block.\r
364     //\r
365     Status = BlockIo->ReadBlocks (\r
366                         BlockIo,\r
367                         MediaId,\r
368                         Lba,\r
369                         BlockSize,\r
370                         Data\r
371                         );\r
372 \r
373     if (EFI_ERROR (Status)) {\r
374       goto Done;\r
375     }\r
376 \r
377     if (Length > BufferSize) {\r
378       Length              = BufferSize;\r
379       TransactionComplete = TRUE;\r
380     }\r
381 \r
382     CopyMem (WorkingBuffer, Data + UnderRun, Length);\r
383 \r
384     WorkingBuffer += Length;\r
385 \r
386     WorkingBufferSize -= Length;\r
387     if (WorkingBufferSize == 0) {\r
388       goto Done;\r
389     }\r
390 \r
391     Lba += 1;\r
392   }\r
393 \r
394   OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun);\r
395 \r
396   if (!TransactionComplete && WorkingBufferSize >= BlockSize) {\r
397     //\r
398     // If the DiskIo maps directly to a BlockIo device do the read.\r
399     //\r
400     if (OverRun != 0) {\r
401       WorkingBufferSize -= OverRun;\r
402     }\r
403     //\r
404     // Check buffer alignment\r
405     //\r
406     IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1);\r
407 \r
408     if (Media->IoAlign <= 1 || IsBufferAligned == 0) {\r
409       //\r
410       // Alignment is satisfied, so read them together\r
411       //\r
412       Status = BlockIo->ReadBlocks (\r
413                           BlockIo,\r
414                           MediaId,\r
415                           Lba,\r
416                           WorkingBufferSize,\r
417                           WorkingBuffer\r
418                           );\r
419 \r
420       if (EFI_ERROR (Status)) {\r
421         goto Done;\r
422       }\r
423 \r
424       WorkingBuffer += WorkingBufferSize;\r
425 \r
426     } else {\r
427       //\r
428       // Use the allocated buffer instead of the original buffer\r
429       // to avoid alignment issue.\r
430       // Here, the allocated buffer (8-byte align) can satisfy the alignment\r
431       //\r
432       LastRead = FALSE;\r
433       do {\r
434         if (WorkingBufferSize <= DataBufferSize) {\r
435           //\r
436           // It is the last calling to readblocks in this loop\r
437           //\r
438           DataBufferSize  = WorkingBufferSize;\r
439           LastRead        = TRUE;\r
440         }\r
441 \r
442         Status = BlockIo->ReadBlocks (\r
443                             BlockIo,\r
444                             MediaId,\r
445                             Lba,\r
446                             DataBufferSize,\r
447                             Data\r
448                             );\r
449         if (EFI_ERROR (Status)) {\r
450           goto Done;\r
451         }\r
452 \r
453         CopyMem (WorkingBuffer, Data, DataBufferSize);\r
454         WorkingBufferSize -= DataBufferSize;\r
455         WorkingBuffer += DataBufferSize;\r
456         Lba += DATA_BUFFER_BLOCK_NUM;\r
457       } while (!LastRead);\r
458     }\r
459   }\r
460 \r
461   if (!TransactionComplete && OverRun != 0) {\r
462     //\r
463     // Last read is not a complete block.\r
464     //\r
465     Status = BlockIo->ReadBlocks (\r
466                         BlockIo,\r
467                         MediaId,\r
468                         OverRunLba,\r
469                         BlockSize,\r
470                         Data\r
471                         );\r
472 \r
473     if (EFI_ERROR (Status)) {\r
474       goto Done;\r
475     }\r
476 \r
477     CopyMem (WorkingBuffer, Data, OverRun);\r
478   }\r
479 \r
480 Done:\r
481   if (PreData != NULL) {\r
482     FreePool (PreData);\r
483   }\r
484 \r
485   return Status;\r
486 }\r
487 \r
488 EFI_STATUS\r
489 EFIAPI\r
490 DiskIoWriteDisk (\r
491   IN EFI_DISK_IO_PROTOCOL  *This,\r
492   IN UINT32                MediaId,\r
493   IN UINT64                Offset,\r
494   IN UINTN                 BufferSize,\r
495   IN VOID                  *Buffer\r
496   )\r
497 /*++\r
498 \r
499   Routine Description:\r
500     Read BufferSize bytes from Offset into Buffer.\r
501 \r
502     Writes may require a read modify write to support writes that are not\r
503     aligned on sector boundaries. There are three cases:\r
504 \r
505       UnderRun - The first byte is not on a sector boundary or the write request\r
506                  is less than a sector in length. Read modify write is required.\r
507 \r
508       Aligned  - A write of N contiguous sectors.\r
509 \r
510       OverRun  - The last byte is not on a sector boundary. Read modified write\r
511                  required.\r
512 \r
513   Arguments:\r
514     This       - Protocol instance pointer.\r
515     MediaId    - Id of the media, changes every time the media is replaced.\r
516     Offset     - The starting byte offset to read from.\r
517     BufferSize - Size of Buffer.\r
518     Buffer     - Buffer containing read data.\r
519 \r
520   Returns:\r
521     EFI_SUCCESS           - The data was written correctly to the device.\r
522     EFI_WRITE_PROTECTED   - The device can not be written to.\r
523     EFI_DEVICE_ERROR      - The device reported an error while performing the write.\r
524     EFI_NO_MEDIA          - There is no media in the device.\r
525     EFI_MEDIA_CHNAGED     - The MediaId does not matched the current device.\r
526     EFI_INVALID_PARAMETER - The write request contains device addresses that are not\r
527                             valid for the device.\r
528     EFI_OUT_OF_RESOURCES\r
529 \r
530 --*/\r
531 {\r
532   EFI_STATUS            Status;\r
533   DISK_IO_PRIVATE_DATA  *Private;\r
534   EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
535   EFI_BLOCK_IO_MEDIA    *Media;\r
536   UINT32                BlockSize;\r
537   UINT64                Lba;\r
538   UINT64                OverRunLba;\r
539   UINT32                UnderRun;\r
540   UINT32                OverRun;\r
541   BOOLEAN               TransactionComplete;\r
542   UINTN                 WorkingBufferSize;\r
543   UINT8                 *WorkingBuffer;\r
544   UINTN                 Length;\r
545   UINT8                 *Data;\r
546   UINT8                 *PreData;\r
547   UINTN                 IsBufferAligned;\r
548   UINTN                 DataBufferSize;\r
549   BOOLEAN               LastWrite;\r
550 \r
551   Private   = DISK_IO_PRIVATE_DATA_FROM_THIS (This);\r
552 \r
553   BlockIo   = Private->BlockIo;\r
554   Media     = BlockIo->Media;\r
555   BlockSize = Media->BlockSize;\r
556 \r
557   if (Media->ReadOnly) {\r
558     return EFI_WRITE_PROTECTED;\r
559   }\r
560 \r
561   if (Media->MediaId != MediaId) {\r
562     return EFI_MEDIA_CHANGED;\r
563   }\r
564 \r
565   DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM;\r
566 \r
567   if (Media->IoAlign > 1) {\r
568     PreData = AllocatePool (DataBufferSize + Media->IoAlign);\r
569     Data    = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign;\r
570   } else {\r
571     PreData = AllocatePool (DataBufferSize);\r
572     Data    = PreData;\r
573   }\r
574 \r
575   if (PreData == NULL) {\r
576     return EFI_OUT_OF_RESOURCES;\r
577   }\r
578 \r
579   WorkingBuffer       = Buffer;\r
580   WorkingBufferSize   = BufferSize;\r
581 \r
582   Lba                 = DivU64x32Remainder (Offset, BlockSize, &UnderRun);\r
583 \r
584   Length              = BlockSize - UnderRun;\r
585   TransactionComplete = FALSE;\r
586 \r
587   Status              = EFI_SUCCESS;\r
588   if (UnderRun != 0) {\r
589     //\r
590     // Offset starts in the middle of an Lba, so do read modify write.\r
591     //\r
592     Status = BlockIo->ReadBlocks (\r
593                         BlockIo,\r
594                         MediaId,\r
595                         Lba,\r
596                         BlockSize,\r
597                         Data\r
598                         );\r
599 \r
600     if (EFI_ERROR (Status)) {\r
601       goto Done;\r
602     }\r
603 \r
604     if (Length > BufferSize) {\r
605       Length              = BufferSize;\r
606       TransactionComplete = TRUE;\r
607     }\r
608 \r
609     CopyMem (Data + UnderRun, WorkingBuffer, Length);\r
610 \r
611     Status = BlockIo->WriteBlocks (\r
612                         BlockIo,\r
613                         MediaId,\r
614                         Lba,\r
615                         BlockSize,\r
616                         Data\r
617                         );\r
618     if (EFI_ERROR (Status)) {\r
619       goto Done;\r
620     }\r
621 \r
622     WorkingBuffer += Length;\r
623     WorkingBufferSize -= Length;\r
624     if (WorkingBufferSize == 0) {\r
625       goto Done;\r
626     }\r
627 \r
628     Lba += 1;\r
629   }\r
630 \r
631   OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun);\r
632 \r
633   if (!TransactionComplete && WorkingBufferSize >= BlockSize) {\r
634     //\r
635     // If the DiskIo maps directly to a BlockIo device do the write.\r
636     //\r
637     if (OverRun != 0) {\r
638       WorkingBufferSize -= OverRun;\r
639     }\r
640     //\r
641     // Check buffer alignment\r
642     //\r
643     IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1);\r
644 \r
645     if (Media->IoAlign <= 1 || IsBufferAligned == 0) {\r
646       //\r
647       // Alignment is satisfied, so write them together\r
648       //\r
649       Status = BlockIo->WriteBlocks (\r
650                           BlockIo,\r
651                           MediaId,\r
652                           Lba,\r
653                           WorkingBufferSize,\r
654                           WorkingBuffer\r
655                           );\r
656 \r
657       if (EFI_ERROR (Status)) {\r
658         goto Done;\r
659       }\r
660 \r
661       WorkingBuffer += WorkingBufferSize;\r
662 \r
663     } else {\r
664       //\r
665       // The buffer parameter is not aligned with the request\r
666       // So use the allocated instead.\r
667       // It can fit almost all the cases.\r
668       //\r
669       LastWrite = FALSE;\r
670       do {\r
671         if (WorkingBufferSize <= DataBufferSize) {\r
672           //\r
673           // It is the last calling to writeblocks in this loop\r
674           //\r
675           DataBufferSize  = WorkingBufferSize;\r
676           LastWrite       = TRUE;\r
677         }\r
678 \r
679         CopyMem (Data, WorkingBuffer, DataBufferSize);\r
680         Status = BlockIo->WriteBlocks (\r
681                             BlockIo,\r
682                             MediaId,\r
683                             Lba,\r
684                             DataBufferSize,\r
685                             Data\r
686                             );\r
687         if (EFI_ERROR (Status)) {\r
688           goto Done;\r
689         }\r
690 \r
691         WorkingBufferSize -= DataBufferSize;\r
692         WorkingBuffer += DataBufferSize;\r
693         Lba += DATA_BUFFER_BLOCK_NUM;\r
694       } while (!LastWrite);\r
695     }\r
696   }\r
697 \r
698   if (!TransactionComplete && OverRun != 0) {\r
699     //\r
700     // Last bit is not a complete block, so do a read modify write.\r
701     //\r
702     Status = BlockIo->ReadBlocks (\r
703                         BlockIo,\r
704                         MediaId,\r
705                         OverRunLba,\r
706                         BlockSize,\r
707                         Data\r
708                         );\r
709 \r
710     if (EFI_ERROR (Status)) {\r
711       goto Done;\r
712     }\r
713 \r
714     CopyMem (Data, WorkingBuffer, OverRun);\r
715 \r
716     Status = BlockIo->WriteBlocks (\r
717                         BlockIo,\r
718                         MediaId,\r
719                         OverRunLba,\r
720                         BlockSize,\r
721                         Data\r
722                         );\r
723     if (EFI_ERROR (Status)) {\r
724       goto Done;\r
725     }\r
726   }\r
727 \r
728 Done:\r
729   if (PreData != NULL) {\r
730     FreePool (PreData);\r
731   }\r
732 \r
733   return Status;\r
734 }\r