]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/DiskIo/Dxe/diskio.c
Fixed typo in function header
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / DiskIo / Dxe / diskio.c
CommitLineData
79840ee1 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 DiskIo.c\r
15\r
16Abstract:\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
40EFI_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
49DISK_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
59EFI_STATUS\r
60EFIAPI\r
61DiskIoDriverBindingSupported (\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
113EFI_STATUS\r
114EFIAPI\r
115DiskIoDriverBindingStart (\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
175ErrorExit:\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
193EFI_STATUS\r
194EFIAPI\r
195DiskIoDriverBindingStop (\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
263EFI_STATUS\r
264EFIAPI\r
265DiskIoReadDisk (\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
480Done:\r
481 if (PreData != NULL) {\r
482 FreePool (PreData);\r
483 }\r
484\r
485 return Status;\r
486}\r
487\r
488EFI_STATUS\r
489EFIAPI\r
490DiskIoWriteDisk (\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
728Done:\r
729 if (PreData != NULL) {\r
730 FreePool (PreData);\r
731 }\r
732\r
733 return Status;\r
734}\r