]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Disk/DiskIo/Dxe/diskio.c
sync with MdePkg.fpd to add PcdPciExpressBaseAddress
[mirror_edk2.git] / EdkModulePkg / Universal / Disk / DiskIo / Dxe / diskio.c
CommitLineData
878ddf1f 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#include "DiskIo.h"\r
34\r
35//\r
36// Prototypes\r
37// Driver model protocol interface\r
38//\r
39EFI_STATUS\r
40EFIAPI\r
41DiskIoDriverBindingSupported (\r
42 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
43 IN EFI_HANDLE ControllerHandle,\r
44 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
45 );\r
46\r
47EFI_STATUS\r
48EFIAPI\r
49DiskIoDriverBindingStart (\r
50 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
51 IN EFI_HANDLE ControllerHandle,\r
52 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
53 );\r
54\r
55EFI_STATUS\r
56EFIAPI\r
57DiskIoDriverBindingStop (\r
58 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
59 IN EFI_HANDLE ControllerHandle,\r
60 IN UINTN NumberOfChildren,\r
61 IN EFI_HANDLE *ChildHandleBuffer\r
62 );\r
63\r
64//\r
65// Disk I/O Protocol Interface\r
66//\r
67EFI_STATUS\r
68EFIAPI\r
69DiskIoReadDisk (\r
70 IN EFI_DISK_IO_PROTOCOL *This,\r
71 IN UINT32 MediaId,\r
72 IN UINT64 Offset,\r
73 IN UINTN BufferSize,\r
74 OUT VOID *Buffer\r
75 );\r
76\r
77EFI_STATUS\r
78EFIAPI\r
79DiskIoWriteDisk (\r
80 IN EFI_DISK_IO_PROTOCOL *This,\r
81 IN UINT32 MediaId,\r
82 IN UINT64 Offset,\r
83 IN UINTN BufferSize,\r
84 IN VOID *Buffer\r
85 );\r
86\r
87EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {\r
88 DiskIoDriverBindingSupported,\r
89 DiskIoDriverBindingStart,\r
90 DiskIoDriverBindingStop,\r
91 0x10,\r
92 NULL,\r
93 NULL\r
94};\r
95\r
96DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate = {\r
97 DISK_IO_PRIVATE_DATA_SIGNATURE,\r
98 {\r
99 EFI_DISK_IO_PROTOCOL_REVISION,\r
100 DiskIoReadDisk,\r
101 DiskIoWriteDisk\r
102 },\r
103 NULL\r
104};\r
105\r
106EFI_STATUS\r
107EFIAPI\r
108DiskIoDriverBindingSupported (\r
109 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
110 IN EFI_HANDLE ControllerHandle,\r
111 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
112 )\r
113/*++\r
114\r
115 Routine Description:\r
116 Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
117 than contains a BlockIo protocol can be supported.\r
118\r
119 Arguments:\r
120 This - Protocol instance pointer.\r
121 ControllerHandle - Handle of device to test.\r
122 RemainingDevicePath - Not used.\r
123\r
124 Returns:\r
125 EFI_SUCCESS - This driver supports this device.\r
126 EFI_ALREADY_STARTED - This driver is already running on this device.\r
127 other - This driver does not support this device.\r
128\r
129--*/\r
130{\r
131 EFI_STATUS Status;\r
132 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
133/*\r
134 DEBUG_CODE_BEGIN\r
135 UINT32 Bar;\r
136 UINT32 Foo;\r
137 UINT32 HotPlug;\r
138\r
139 //\r
140 // Get TYPE 0\r
141 //\r
142 Bar = PcdGet32 (PciExpressBaseVersion);\r
143 DEBUG ((EFI_D_ERROR, "PciExpressBaseVersion = %08x\n", Bar));\r
144\r
145 //\r
146 // Get TYPE 1\r
147 //\r
148 Foo = PcdGet32 (PciExpressBaseAddress);\r
149 DEBUG ((EFI_D_ERROR, "PciExpressBaseAddress = %08x\n", Foo));\r
150\r
151 //\r
152 // Set TYPE 1\r
153 //\r
154 PcdSet32 (PciExpressBaseAddress, Foo + 1);\r
155\r
156 //\r
157 // Get TYPE 1\r
158 //\r
159 Foo = PcdGet32 (PciExpressBaseAddress);\r
160 DEBUG ((EFI_D_ERROR, "PciExpressBaseAddress = %08x\n", Foo));\r
161\r
162 //\r
163 // Get TYPE 2\r
164 //\r
165 HotPlug = PcdGet32 (PciExpressBaseHotPlug);\r
166 DEBUG ((EFI_D_ERROR, "PciExpressHotPlug = %08x\n", HotPlug));\r
167\r
168 //\r
169 // Set TYPE 1\r
170 //\r
171 PcdSet32 (PciExpressBaseHotPlug, HotPlug + 1);\r
172\r
173 //\r
174 // Get TYPE 1\r
175 //\r
176 HotPlug = PcdGet32 (PciExpressBaseHotPlug);\r
177 DEBUG ((EFI_D_ERROR, "PciExpressHotPlug = %08x\n", HotPlug));\r
178\r
179 DEBUG_CODE_END\r
180\r
181 DEBUG_CODE_BEGIN\r
182 UINT32 MyVariable;\r
183\r
184 if (ControllerHandle == NULL) {\r
185 MyVariable = 32 * (UINTN)This;\r
186 ControllerHandle = (EFI_HANDLE)MyVariable;\r
187 DEBUG ((EFI_D_ERROR, "DiskIoSupported-DebugCode. MyVariable = %08x\n", MyVariable));\r
188 ASSERT (MyVariable != 32);\r
189 }\r
190 DEBUG_CODE_END\r
191*/\r
192 DEBUG ((EFI_D_ERROR, "DiskIoSupported\n"));\r
193\r
194// Io8Or (0x400, 1);\r
195// Io8And (0x400, 1);\r
196// Io8AndThenOr (0x400, 1, 2);\r
197\r
198// Mmio8Or (0xa0000000, 1);\r
199// Mmio8And (0xa0000000, 1);\r
200// Mmio8AndThenOr (0xa0000000, 1, 2);\r
201\r
202/*\r
203 PciRead8 (PCI_LIB_ADDRESS (1,2,3,4));\r
204 PciRead16 (PCI_LIB_ADDRESS (1,2,3,4));\r
205 PciRead32 (PCI_LIB_ADDRESS (1,2,3,4));\r
206\r
207 PciWrite8 (PCI_LIB_ADDRESS (1,2,3,4), 0xAA);\r
208 PciWrite16 (PCI_LIB_ADDRESS (1,2,3,4), 0xAA55);\r
209 PciWrite32 (PCI_LIB_ADDRESS (1,2,3,4), 0xAA55A55A);\r
210\r
211 Pci8Or (PCI_LIB_ADDRESS (1,2,3,4), 0xAA);\r
212 Pci8And (PCI_LIB_ADDRESS (1,2,3,4), 0x55);\r
213 Pci8AndThenOr (PCI_LIB_ADDRESS (1,2,3,4), 0xAA, 0x55);\r
214\r
215 Pci16Or (PCI_LIB_ADDRESS (1,2,3,4), 0xAA55);\r
216 Pci16And (PCI_LIB_ADDRESS (1,2,3,4), 0x55AA);\r
217 Pci16AndThenOr (PCI_LIB_ADDRESS (1,2,3,4), 0xAA55, 0x55AA);\r
218\r
219 Pci32Or (PCI_LIB_ADDRESS (1,2,3,4), 0xAA55A55A);\r
220 Pci32And (PCI_LIB_ADDRESS (1,2,3,4), 0x55AA5AA5);\r
221 Pci32AndThenOr (PCI_LIB_ADDRESS (1,2,3,4), 0xAA555AA5, 0x55AAA55A);\r
222*/\r
223 //\r
224 // Open the IO Abstraction(s) needed to perform the supported test.\r
225 //\r
226 Status = gBS->OpenProtocol (\r
227 ControllerHandle,\r
228 &gEfiBlockIoProtocolGuid,\r
229 (VOID **) &BlockIo,\r
230 This->DriverBindingHandle,\r
231 ControllerHandle,\r
232 EFI_OPEN_PROTOCOL_BY_DRIVER\r
233 );\r
234 if (EFI_ERROR (Status)) {\r
235 return Status;\r
236 }\r
237 //\r
238 // Close the I/O Abstraction(s) used to perform the supported test.\r
239 //\r
240 gBS->CloseProtocol (\r
241 ControllerHandle,\r
242 &gEfiBlockIoProtocolGuid,\r
243 This->DriverBindingHandle,\r
244 ControllerHandle\r
245 );\r
246 return EFI_SUCCESS;\r
247}\r
248\r
249EFI_STATUS\r
250EFIAPI\r
251DiskIoDriverBindingStart (\r
252 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
253 IN EFI_HANDLE ControllerHandle,\r
254 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
255 )\r
256/*++\r
257\r
258 Routine Description:\r
259 Start this driver on ControllerHandle by opening a Block IO protocol and\r
260 installing a Disk IO protocol on ControllerHandle.\r
261\r
262 Arguments:\r
263 This - Protocol instance pointer.\r
264 ControllerHandle - Handle of device to bind driver to.\r
265 RemainingDevicePath - Not used, always produce all possible children.\r
266\r
267 Returns:\r
268 EFI_SUCCESS - This driver is added to ControllerHandle.\r
269 EFI_ALREADY_STARTED - This driver is already running on ControllerHandle.\r
270 other - This driver does not support this device.\r
271\r
272--*/\r
273{\r
274 EFI_STATUS Status;\r
275 DISK_IO_PRIVATE_DATA *Private;\r
276\r
277 Private = NULL;\r
278\r
279 DEBUG ((EFI_D_ERROR, "DiskIoStart\n"));\r
280 //\r
281 // Connect to the Block IO interface on ControllerHandle.\r
282 //\r
283 Status = gBS->OpenProtocol (\r
284 ControllerHandle,\r
285 &gEfiBlockIoProtocolGuid,\r
286 (VOID **) &gDiskIoPrivateDataTemplate.BlockIo,\r
287 This->DriverBindingHandle,\r
288 ControllerHandle,\r
289 EFI_OPEN_PROTOCOL_BY_DRIVER\r
290 );\r
291 if (EFI_ERROR (Status)) {\r
292 return Status;\r
293 }\r
294 //\r
295 // Initialize the Disk IO device instance.\r
296 //\r
297 Private = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);\r
298 if (Private == NULL) {\r
299 Status = EFI_OUT_OF_RESOURCES;\r
300 goto ErrorExit;\r
301 }\r
302 //\r
303 // Install protocol interfaces for the Disk IO device.\r
304 //\r
305 Status = gBS->InstallProtocolInterface (\r
306 &ControllerHandle,\r
307 &gEfiDiskIoProtocolGuid,\r
308 EFI_NATIVE_INTERFACE,\r
309 &Private->DiskIo\r
310 );\r
311\r
312ErrorExit:\r
313 if (EFI_ERROR (Status)) {\r
314\r
315 if (Private != NULL) {\r
316 gBS->FreePool (Private);\r
317 }\r
318\r
319 gBS->CloseProtocol (\r
320 ControllerHandle,\r
321 &gEfiBlockIoProtocolGuid,\r
322 This->DriverBindingHandle,\r
323 ControllerHandle\r
324 );\r
325 }\r
326\r
327 return Status;\r
328}\r
329\r
330EFI_STATUS\r
331EFIAPI\r
332DiskIoDriverBindingStop (\r
333 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
334 IN EFI_HANDLE ControllerHandle,\r
335 IN UINTN NumberOfChildren,\r
336 IN EFI_HANDLE *ChildHandleBuffer\r
337 )\r
338/*++\r
339\r
340 Routine Description:\r
341 Stop this driver on ControllerHandle by removing Disk IO protocol and closing\r
342 the Block IO protocol on ControllerHandle.\r
343\r
344 Arguments:\r
345 This - Protocol instance pointer.\r
346 ControllerHandle - Handle of device to stop driver on.\r
347 NumberOfChildren - Not used.\r
348 ChildHandleBuffer - Not used.\r
349\r
350 Returns:\r
351 EFI_SUCCESS - This driver is removed ControllerHandle.\r
352 other - This driver was not removed from this device.\r
353 EFI_UNSUPPORTED\r
354\r
355--*/\r
356{\r
357 EFI_STATUS Status;\r
358 EFI_DISK_IO_PROTOCOL *DiskIo;\r
359 DISK_IO_PRIVATE_DATA *Private;\r
360\r
361 DEBUG ((EFI_D_ERROR, "DiskIoStop\n"));\r
362 //\r
363 // Get our context back.\r
364 //\r
365 Status = gBS->OpenProtocol (\r
366 ControllerHandle,\r
367 &gEfiDiskIoProtocolGuid,\r
368 (VOID **) &DiskIo,\r
369 This->DriverBindingHandle,\r
370 ControllerHandle,\r
371 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
372 );\r
373 if (EFI_ERROR (Status)) {\r
374 return EFI_UNSUPPORTED;\r
375 }\r
376\r
377 Private = DISK_IO_PRIVATE_DATA_FROM_THIS (DiskIo);\r
378\r
379 Status = gBS->UninstallProtocolInterface (\r
380 ControllerHandle,\r
381 &gEfiDiskIoProtocolGuid,\r
382 &Private->DiskIo\r
383 );\r
384 if (!EFI_ERROR (Status)) {\r
385\r
386 Status = gBS->CloseProtocol (\r
387 ControllerHandle,\r
388 &gEfiBlockIoProtocolGuid,\r
389 This->DriverBindingHandle,\r
390 ControllerHandle\r
391 );\r
392 }\r
393\r
394 if (!EFI_ERROR (Status)) {\r
395 gBS->FreePool (Private);\r
396 }\r
397\r
398 return Status;\r
399}\r
400\r
401EFI_STATUS\r
402EFIAPI\r
403DiskIoReadDisk (\r
404 IN EFI_DISK_IO_PROTOCOL *This,\r
405 IN UINT32 MediaId,\r
406 IN UINT64 Offset,\r
407 IN UINTN BufferSize,\r
408 OUT VOID *Buffer\r
409 )\r
410/*++\r
411\r
412 Routine Description:\r
413 Read BufferSize bytes from Offset into Buffer.\r
414\r
415 Reads may support reads that are not aligned on\r
416 sector boundaries. There are three cases:\r
417\r
418 UnderRun - The first byte is not on a sector boundary or the read request is\r
419 less than a sector in length.\r
420\r
421 Aligned - A read of N contiguous sectors.\r
422\r
423 OverRun - The last byte is not on a sector boundary.\r
424\r
425\r
426 Arguments:\r
427 This - Protocol instance pointer.\r
428 MediaId - Id of the media, changes every time the media is replaced.\r
429 Offset - The starting byte offset to read from.\r
430 BufferSize - Size of Buffer.\r
431 Buffer - Buffer containing read data.\r
432\r
433 Returns:\r
434 EFI_SUCCESS - The data was read correctly from the device.\r
435 EFI_DEVICE_ERROR - The device reported an error while performing the read.\r
436 EFI_NO_MEDIA - There is no media in the device.\r
437 EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.\r
438 EFI_INVALID_PARAMETER - The read request contains device addresses that are not\r
439 valid for the device.\r
440 EFI_OUT_OF_RESOURCES\r
441\r
442--*/\r
443{\r
444 EFI_STATUS Status;\r
445 DISK_IO_PRIVATE_DATA *Private;\r
446 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
447 EFI_BLOCK_IO_MEDIA *Media;\r
448 UINT32 BlockSize;\r
449 UINT64 Lba;\r
450 UINT64 OverRunLba;\r
451 UINT32 UnderRun;\r
452 UINT32 OverRun;\r
453 BOOLEAN TransactionComplete;\r
454 UINTN WorkingBufferSize;\r
455 UINT8 *WorkingBuffer;\r
456 UINTN Length;\r
457 UINT8 *Data;\r
458 UINT8 *PreData;\r
459 UINTN IsBufferAligned;\r
460 UINTN DataBufferSize;\r
461 BOOLEAN LastRead;\r
462\r
463 DEBUG ((EFI_D_ERROR, "DiskIoReadDisk\n"));\r
464\r
465 Private = DISK_IO_PRIVATE_DATA_FROM_THIS (This);\r
466\r
467 BlockIo = Private->BlockIo;\r
468 Media = BlockIo->Media;\r
469 BlockSize = Media->BlockSize;\r
470\r
471 if (Media->MediaId != MediaId) {\r
472 return EFI_MEDIA_CHANGED;\r
473 }\r
474\r
475 WorkingBuffer = Buffer;\r
476 WorkingBufferSize = BufferSize;\r
477\r
478 //\r
479 // Allocate a temporary buffer for operation\r
480 //\r
481 DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM;\r
482\r
483 if (Media->IoAlign > 1) {\r
484 PreData = AllocatePool (DataBufferSize + Media->IoAlign);\r
485 Data = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign;\r
486 } else {\r
487 PreData = AllocatePool (DataBufferSize);\r
488 Data = PreData;\r
489 }\r
490\r
491 if (PreData == NULL) {\r
492 return EFI_OUT_OF_RESOURCES;\r
493 }\r
494\r
495 Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);\r
496\r
497 Length = BlockSize - UnderRun;\r
498 TransactionComplete = FALSE;\r
499\r
500 Status = EFI_SUCCESS;\r
501 if (UnderRun != 0) {\r
502 //\r
503 // Offset starts in the middle of an Lba, so read the entire block.\r
504 //\r
505 Status = BlockIo->ReadBlocks (\r
506 BlockIo,\r
507 MediaId,\r
508 Lba,\r
509 BlockSize,\r
510 Data\r
511 );\r
512\r
513 if (EFI_ERROR (Status)) {\r
514 goto Done;\r
515 }\r
516\r
517 if (Length > BufferSize) {\r
518 Length = BufferSize;\r
519 TransactionComplete = TRUE;\r
520 }\r
521\r
522 CopyMem (WorkingBuffer, Data + UnderRun, Length);\r
523\r
524 WorkingBuffer += Length;\r
525\r
526 WorkingBufferSize -= Length;\r
527 if (WorkingBufferSize == 0) {\r
528 goto Done;\r
529 }\r
530\r
531 Lba += 1;\r
532 }\r
533\r
534 OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun);\r
535\r
536 if (!TransactionComplete && WorkingBufferSize >= BlockSize) {\r
537 //\r
538 // If the DiskIo maps directly to a BlockIo device do the read.\r
539 //\r
540 if (OverRun != 0) {\r
541 WorkingBufferSize -= OverRun;\r
542 }\r
543 //\r
544 // Check buffer alignment\r
545 //\r
546 IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1);\r
547\r
548 if (Media->IoAlign <= 1 || IsBufferAligned == 0) {\r
549 //\r
550 // Alignment is satisfied, so read them together\r
551 //\r
552 Status = BlockIo->ReadBlocks (\r
553 BlockIo,\r
554 MediaId,\r
555 Lba,\r
556 WorkingBufferSize,\r
557 WorkingBuffer\r
558 );\r
559\r
560 if (EFI_ERROR (Status)) {\r
561 goto Done;\r
562 }\r
563\r
564 WorkingBuffer += WorkingBufferSize;\r
565\r
566 } else {\r
567 //\r
568 // Use the allocated buffer instead of the original buffer\r
569 // to avoid alignment issue.\r
570 // Here, the allocated buffer (8-byte align) can satisfy the alignment\r
571 //\r
572 LastRead = FALSE;\r
573 do {\r
574 if (WorkingBufferSize <= DataBufferSize) {\r
575 //\r
576 // It is the last calling to readblocks in this loop\r
577 //\r
578 DataBufferSize = WorkingBufferSize;\r
579 LastRead = TRUE;\r
580 }\r
581\r
582 Status = BlockIo->ReadBlocks (\r
583 BlockIo,\r
584 MediaId,\r
585 Lba,\r
586 DataBufferSize,\r
587 Data\r
588 );\r
589 if (EFI_ERROR (Status)) {\r
590 goto Done;\r
591 }\r
592\r
593 CopyMem (WorkingBuffer, Data, DataBufferSize);\r
594 WorkingBufferSize -= DataBufferSize;\r
595 WorkingBuffer += DataBufferSize;\r
596 Lba += DATA_BUFFER_BLOCK_NUM;\r
597 } while (!LastRead);\r
598 }\r
599 }\r
600\r
601 if (!TransactionComplete && OverRun != 0) {\r
602 //\r
603 // Last read is not a complete block.\r
604 //\r
605 Status = BlockIo->ReadBlocks (\r
606 BlockIo,\r
607 MediaId,\r
608 OverRunLba,\r
609 BlockSize,\r
610 Data\r
611 );\r
612\r
613 if (EFI_ERROR (Status)) {\r
614 goto Done;\r
615 }\r
616\r
617 CopyMem (WorkingBuffer, Data, OverRun);\r
618 }\r
619\r
620Done:\r
621 if (PreData != NULL) {\r
622 gBS->FreePool (PreData);\r
623 }\r
624\r
625 return Status;\r
626}\r
627\r
628EFI_STATUS\r
629EFIAPI\r
630DiskIoWriteDisk (\r
631 IN EFI_DISK_IO_PROTOCOL *This,\r
632 IN UINT32 MediaId,\r
633 IN UINT64 Offset,\r
634 IN UINTN BufferSize,\r
635 IN VOID *Buffer\r
636 )\r
637/*++\r
638\r
639 Routine Description:\r
640 Read BufferSize bytes from Offset into Buffer.\r
641\r
642 Writes may require a read modify write to support writes that are not\r
643 aligned on sector boundaries. There are three cases:\r
644\r
645 UnderRun - The first byte is not on a sector boundary or the write request\r
646 is less than a sector in length. Read modify write is required.\r
647\r
648 Aligned - A write of N contiguous sectors.\r
649\r
650 OverRun - The last byte is not on a sector boundary. Read modified write\r
651 required.\r
652\r
653 Arguments:\r
654 This - Protocol instance pointer.\r
655 MediaId - Id of the media, changes every time the media is replaced.\r
656 Offset - The starting byte offset to read from.\r
657 BufferSize - Size of Buffer.\r
658 Buffer - Buffer containing read data.\r
659\r
660 Returns:\r
661 EFI_SUCCESS - The data was written correctly to the device.\r
662 EFI_WRITE_PROTECTED - The device can not be written to.\r
663 EFI_DEVICE_ERROR - The device reported an error while performing the write.\r
664 EFI_NO_MEDIA - There is no media in the device.\r
665 EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.\r
666 EFI_INVALID_PARAMETER - The write request contains device addresses that are not\r
667 valid for the device.\r
668 EFI_OUT_OF_RESOURCES\r
669\r
670--*/\r
671{\r
672 EFI_STATUS Status;\r
673 DISK_IO_PRIVATE_DATA *Private;\r
674 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
675 EFI_BLOCK_IO_MEDIA *Media;\r
676 UINT32 BlockSize;\r
677 UINT64 Lba;\r
678 UINT64 OverRunLba;\r
679 UINT32 UnderRun;\r
680 UINT32 OverRun;\r
681 BOOLEAN TransactionComplete;\r
682 UINTN WorkingBufferSize;\r
683 UINT8 *WorkingBuffer;\r
684 UINTN Length;\r
685 UINT8 *Data;\r
686 UINT8 *PreData;\r
687 UINTN IsBufferAligned;\r
688 UINTN DataBufferSize;\r
689 BOOLEAN LastWrite;\r
690\r
691 DEBUG ((EFI_D_ERROR, "DiskIoWriteDisk\n"));\r
692\r
693 Private = DISK_IO_PRIVATE_DATA_FROM_THIS (This);\r
694\r
695 BlockIo = Private->BlockIo;\r
696 Media = BlockIo->Media;\r
697 BlockSize = Media->BlockSize;\r
698\r
699 if (Media->ReadOnly) {\r
700 return EFI_WRITE_PROTECTED;\r
701 }\r
702\r
703 if (Media->MediaId != MediaId) {\r
704 return EFI_MEDIA_CHANGED;\r
705 }\r
706\r
707 DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM;\r
708\r
709 if (Media->IoAlign > 1) {\r
710 PreData = AllocatePool (DataBufferSize + Media->IoAlign);\r
711 Data = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign;\r
712 } else {\r
713 PreData = AllocatePool (DataBufferSize);\r
714 Data = PreData;\r
715 }\r
716\r
717 if (PreData == NULL) {\r
718 return EFI_OUT_OF_RESOURCES;\r
719 }\r
720\r
721 WorkingBuffer = Buffer;\r
722 WorkingBufferSize = BufferSize;\r
723\r
724 Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);\r
725\r
726 Length = BlockSize - UnderRun;\r
727 TransactionComplete = FALSE;\r
728\r
729 Status = EFI_SUCCESS;\r
730 if (UnderRun != 0) {\r
731 //\r
732 // Offset starts in the middle of an Lba, so do read modify write.\r
733 //\r
734 Status = BlockIo->ReadBlocks (\r
735 BlockIo,\r
736 MediaId,\r
737 Lba,\r
738 BlockSize,\r
739 Data\r
740 );\r
741\r
742 if (EFI_ERROR (Status)) {\r
743 goto Done;\r
744 }\r
745\r
746 if (Length > BufferSize) {\r
747 Length = BufferSize;\r
748 TransactionComplete = TRUE;\r
749 }\r
750\r
751 CopyMem (Data + UnderRun, WorkingBuffer, Length);\r
752\r
753 Status = BlockIo->WriteBlocks (\r
754 BlockIo,\r
755 MediaId,\r
756 Lba,\r
757 BlockSize,\r
758 Data\r
759 );\r
760 if (EFI_ERROR (Status)) {\r
761 goto Done;\r
762 }\r
763\r
764 WorkingBuffer += Length;\r
765 WorkingBufferSize -= Length;\r
766 if (WorkingBufferSize == 0) {\r
767 goto Done;\r
768 }\r
769\r
770 Lba += 1;\r
771 }\r
772\r
773 OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun);\r
774\r
775 if (!TransactionComplete && WorkingBufferSize >= BlockSize) {\r
776 //\r
777 // If the DiskIo maps directly to a BlockIo device do the write.\r
778 //\r
779 if (OverRun != 0) {\r
780 WorkingBufferSize -= OverRun;\r
781 }\r
782 //\r
783 // Check buffer alignment\r
784 //\r
785 IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1);\r
786\r
787 if (Media->IoAlign <= 1 || IsBufferAligned == 0) {\r
788 //\r
789 // Alignment is satisfied, so write them together\r
790 //\r
791 Status = BlockIo->WriteBlocks (\r
792 BlockIo,\r
793 MediaId,\r
794 Lba,\r
795 WorkingBufferSize,\r
796 WorkingBuffer\r
797 );\r
798\r
799 if (EFI_ERROR (Status)) {\r
800 goto Done;\r
801 }\r
802\r
803 WorkingBuffer += WorkingBufferSize;\r
804\r
805 } else {\r
806 //\r
807 // The buffer parameter is not aligned with the request\r
808 // So use the allocated instead.\r
809 // It can fit almost all the cases.\r
810 //\r
811 LastWrite = FALSE;\r
812 do {\r
813 if (WorkingBufferSize <= DataBufferSize) {\r
814 //\r
815 // It is the last calling to writeblocks in this loop\r
816 //\r
817 DataBufferSize = WorkingBufferSize;\r
818 LastWrite = TRUE;\r
819 }\r
820\r
821 CopyMem (Data, WorkingBuffer, DataBufferSize);\r
822 Status = BlockIo->WriteBlocks (\r
823 BlockIo,\r
824 MediaId,\r
825 Lba,\r
826 DataBufferSize,\r
827 Data\r
828 );\r
829 if (EFI_ERROR (Status)) {\r
830 goto Done;\r
831 }\r
832\r
833 WorkingBufferSize -= DataBufferSize;\r
834 WorkingBuffer += DataBufferSize;\r
835 Lba += DATA_BUFFER_BLOCK_NUM;\r
836 } while (!LastWrite);\r
837 }\r
838 }\r
839\r
840 if (!TransactionComplete && OverRun != 0) {\r
841 //\r
842 // Last bit is not a complete block, so do a read modify write.\r
843 //\r
844 Status = BlockIo->ReadBlocks (\r
845 BlockIo,\r
846 MediaId,\r
847 OverRunLba,\r
848 BlockSize,\r
849 Data\r
850 );\r
851\r
852 if (EFI_ERROR (Status)) {\r
853 goto Done;\r
854 }\r
855\r
856 CopyMem (Data, WorkingBuffer, OverRun);\r
857\r
858 Status = BlockIo->WriteBlocks (\r
859 BlockIo,\r
860 MediaId,\r
861 OverRunLba,\r
862 BlockSize,\r
863 Data\r
864 );\r
865 if (EFI_ERROR (Status)) {\r
866 goto Done;\r
867 }\r
868 }\r
869\r
870Done:\r
871 if (PreData != NULL) {\r
872 gBS->FreePool (PreData);\r
873 }\r
874\r
875 return Status;\r
876}\r