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