]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
Fix 3 bugs in DiskIoDxe and PartitionDxe drivers introduced in DiskIo2 implementation.
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / DiskIoDxe / DiskIo.c
CommitLineData
adbcbf8f 1/** @file\r
ff61847d 2 DiskIo driver that lays on every BlockIo protocol in the system.\r
adbcbf8f 3 DiskIo converts a block oriented device to a byte oriented device.\r
4\r
ff61847d 5 Disk access may have to handle unaligned request about sector boundaries.\r
adbcbf8f 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
493d8e3a 12Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 13This program and the accompanying materials\r
f42be642 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
adbcbf8f 20\r
21**/\r
22\r
23#include "DiskIo.h"\r
24\r
ff61847d 25//\r
26// Driver binding protocol implementation for DiskIo driver.\r
27//\r
adbcbf8f 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
ff61847d 37//\r
38// Template for DiskIo private data structure.\r
39// The pointer to BlockIo protocol interface is assigned dynamically.\r
40//\r
adbcbf8f 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
493d8e3a
RN
48 {\r
49 EFI_DISK_IO2_PROTOCOL_REVISION,\r
50 DiskIo2Cancel,\r
51 DiskIo2ReadDiskEx,\r
52 DiskIo2WriteDiskEx,\r
53 DiskIo2FlushDiskEx\r
54 }\r
adbcbf8f 55};\r
56\r
adbcbf8f 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
493d8e3a
RN
100 ControllerHandle,\r
101 &gEfiBlockIoProtocolGuid,\r
102 This->DriverBindingHandle,\r
103 ControllerHandle\r
104 );\r
adbcbf8f 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
493d8e3a 132 DISK_IO_PRIVATE_DATA *Instance;\r
15cc67e6 133 EFI_TPL OldTpl;\r
493d8e3a
RN
134\r
135 Instance = NULL;\r
adbcbf8f 136\r
15cc67e6 137 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
adbcbf8f 138\r
139 //\r
493d8e3a 140 // Connect to the Block IO and Block IO2 interface on ControllerHandle.\r
adbcbf8f 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
15cc67e6 151 goto ErrorExit1;\r
adbcbf8f 152 }\r
493d8e3a
RN
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
adbcbf8f 165 \r
166 //\r
167 // Initialize the Disk IO device instance.\r
168 //\r
493d8e3a
RN
169 Instance = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);\r
170 if (Instance == NULL) {\r
adbcbf8f 171 Status = EFI_OUT_OF_RESOURCES;\r
172 goto ErrorExit;\r
173 }\r
174 \r
493d8e3a
RN
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 (DATA_BUFFER_BLOCK_NUM * 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
adbcbf8f 194 //\r
195 // Install protocol interfaces for the Disk IO device.\r
196 //\r
493d8e3a
RN
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
adbcbf8f 211\r
212ErrorExit:\r
213 if (EFI_ERROR (Status)) {\r
493d8e3a
RN
214 if (Instance != NULL && Instance->SharedWorkingBuffer != NULL) {\r
215 FreeAlignedPages (\r
216 Instance->SharedWorkingBuffer,\r
217 EFI_SIZE_TO_PAGES (DATA_BUFFER_BLOCK_NUM * Instance->BlockIo->Media->BlockSize)\r
218 );\r
219 }\r
adbcbf8f 220\r
493d8e3a
RN
221 if (Instance != NULL) {\r
222 FreePool (Instance);\r
adbcbf8f 223 }\r
224\r
225 gBS->CloseProtocol (\r
493d8e3a
RN
226 ControllerHandle,\r
227 &gEfiBlockIoProtocolGuid,\r
228 This->DriverBindingHandle,\r
229 ControllerHandle\r
230 );\r
adbcbf8f 231 }\r
232\r
15cc67e6 233ErrorExit1:\r
234 gBS->RestoreTPL (OldTpl);\r
adbcbf8f 235 return Status;\r
236}\r
237\r
adbcbf8f 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
493d8e3a
RN
263 EFI_DISK_IO2_PROTOCOL *DiskIo2;\r
264 DISK_IO_PRIVATE_DATA *Instance;\r
265 BOOLEAN AllTaskDone;\r
adbcbf8f 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
493d8e3a 279 return Status;\r
adbcbf8f 280 }\r
493d8e3a 281 Status = gBS->OpenProtocol (\r
adbcbf8f 282 ControllerHandle,\r
493d8e3a
RN
283 &gEfiDiskIo2ProtocolGuid,\r
284 (VOID **) &DiskIo2,\r
285 This->DriverBindingHandle,\r
286 ControllerHandle,\r
287 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
adbcbf8f 288 );\r
493d8e3a
RN
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
adbcbf8f 317 if (!EFI_ERROR (Status)) {\r
493d8e3a
RN
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 (DATA_BUFFER_BLOCK_NUM * Instance->BlockIo->Media->BlockSize)\r
328 );\r
329\r
adbcbf8f 330 Status = gBS->CloseProtocol (\r
331 ControllerHandle,\r
332 &gEfiBlockIoProtocolGuid,\r
333 This->DriverBindingHandle,\r
334 ControllerHandle\r
335 );\r
493d8e3a
RN
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
adbcbf8f 348 }\r
349\r
493d8e3a
RN
350 return Status;\r
351}\r
352\r
353\r
354/**\r
355 Destroy the sub task.\r
356\r
b822eb42 357 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.\r
493d8e3a
RN
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 Link = RemoveEntryList (&Subtask->Link);\r
370 if (!Subtask->Blocking) {\r
371 if (Subtask->WorkingBuffer != NULL) {\r
372 FreeAlignedPages (\r
373 Subtask->WorkingBuffer, \r
374 Subtask->Length < Instance->BlockIo->Media->BlockSize\r
375 ? EFI_SIZE_TO_PAGES (Instance->BlockIo->Media->BlockSize)\r
376 : EFI_SIZE_TO_PAGES (Subtask->Length)\r
377 );\r
378 }\r
379 if (Subtask->BlockIo2Token.Event != NULL) {\r
380 gBS->CloseEvent (Subtask->BlockIo2Token.Event);\r
381 }\r
adbcbf8f 382 }\r
493d8e3a 383 FreePool (Subtask);\r
adbcbf8f 384\r
493d8e3a 385 return Link;\r
adbcbf8f 386}\r
387\r
493d8e3a
RN
388/**\r
389 The callback for the BlockIo2 ReadBlocksEx/WriteBlocksEx.\r
390 @param Event Event whose notification function is being invoked.\r
391 @param Context The pointer to the notification function's context,\r
392 which points to the DISK_IO_SUBTASK instance.\r
393**/\r
394VOID\r
395EFIAPI\r
396DiskIo2OnReadWriteComplete (\r
397 IN EFI_EVENT Event,\r
398 IN VOID *Context\r
399 )\r
400{\r
401 DISK_IO_SUBTASK *Subtask;\r
402 DISK_IO2_TASK *Task;\r
403 EFI_STATUS TransactionStatus;\r
404 DISK_IO_PRIVATE_DATA *Instance;\r
405\r
493d8e3a
RN
406 Subtask = (DISK_IO_SUBTASK *) Context;\r
407 TransactionStatus = Subtask->BlockIo2Token.TransactionStatus;\r
408 Task = Subtask->Task;\r
409 Instance = Task->Instance;\r
410\r
411 ASSERT (Subtask->Signature == DISK_IO_SUBTASK_SIGNATURE);\r
412 ASSERT (Instance->Signature == DISK_IO_PRIVATE_DATA_SIGNATURE);\r
413 ASSERT (Task->Signature == DISK_IO2_TASK_SIGNATURE);\r
adbcbf8f 414\r
80c83a69
RN
415 if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) && \r
416 (Task->Token != NULL) && !Subtask->Write\r
417 ) {\r
418 CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);\r
493d8e3a 419 }\r
80c83a69
RN
420\r
421 DiskIoDestroySubtask (Instance, Subtask);\r
493d8e3a
RN
422\r
423 if (EFI_ERROR (TransactionStatus) || IsListEmpty (&Task->Subtasks)) {\r
424 if (Task->Token != NULL) {\r
425 //\r
426 // Signal error status once the subtask is failed.\r
427 // Or signal the last status once the last subtask is finished.\r
428 //\r
429 Task->Token->TransactionStatus = TransactionStatus;\r
430 gBS->SignalEvent (Task->Token->Event);\r
431\r
432 //\r
433 // Mark token to NULL\r
434 //\r
435 Task->Token = NULL;\r
436 }\r
437 }\r
438\r
439 if (IsListEmpty (&Task->Subtasks)) {\r
440 EfiAcquireLock (&Instance->TaskQueueLock);\r
441 RemoveEntryList (&Task->Link);\r
442 EfiReleaseLock (&Instance->TaskQueueLock);\r
443\r
444 FreePool (Task);\r
445 }\r
446}\r
adbcbf8f 447\r
448/**\r
493d8e3a 449 Create the subtask.\r
adbcbf8f 450\r
493d8e3a
RN
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
adbcbf8f 458\r
493d8e3a
RN
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
adbcbf8f 474\r
493d8e3a
RN
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
adbcbf8f 523**/\r
493d8e3a
RN
524BOOLEAN\r
525DiskIoCreateSubtaskList (\r
526 IN DISK_IO_PRIVATE_DATA *Instance,\r
527 IN BOOLEAN Write,\r
adbcbf8f 528 IN UINT64 Offset,\r
529 IN UINTN BufferSize,\r
493d8e3a
RN
530 IN VOID *Buffer,\r
531 IN BOOLEAN Blocking,\r
532 IN VOID *SharedWorkingBuffer,\r
533 IN OUT LIST_ENTRY *Subtasks\r
adbcbf8f 534 )\r
535{\r
adbcbf8f 536 UINT32 BlockSize;\r
493d8e3a 537 UINT32 IoAlign;\r
adbcbf8f 538 UINT64 Lba;\r
539 UINT64 OverRunLba;\r
540 UINT32 UnderRun;\r
541 UINT32 OverRun;\r
493d8e3a 542 UINT8 *BufferPtr;\r
adbcbf8f 543 UINTN Length;\r
adbcbf8f 544 UINTN DataBufferSize;\r
493d8e3a
RN
545 DISK_IO_SUBTASK *Subtask;\r
546 VOID *WorkingBuffer;\r
547 LIST_ENTRY *Link;\r
adbcbf8f 548\r
493d8e3a 549 DEBUG ((EFI_D_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));\r
adbcbf8f 550\r
493d8e3a
RN
551 BlockSize = Instance->BlockIo->Media->BlockSize;\r
552 IoAlign = Instance->BlockIo->Media->IoAlign;\r
553 if (IoAlign == 0) {\r
554 IoAlign = 1;\r
adbcbf8f 555 }\r
493d8e3a
RN
556 \r
557 Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);\r
558 BufferPtr = (UINT8 *) Buffer;\r
adbcbf8f 559\r
560 //\r
493d8e3a 561 // Special handling for zero BufferSize\r
adbcbf8f 562 //\r
493d8e3a
RN
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
adbcbf8f 570 }\r
571\r
adbcbf8f 572 if (UnderRun != 0) {\r
493d8e3a
RN
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
adbcbf8f 592 }\r
593\r
493d8e3a
RN
594 Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, Length, WorkingBuffer, BufferPtr, Blocking);\r
595 if (Subtask == NULL) {\r
596 goto Done;\r
adbcbf8f 597 }\r
493d8e3a
RN
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
adbcbf8f 605\r
493d8e3a
RN
606 OverRunLba = Lba + DivU64x32Remainder (BufferSize, BlockSize, &OverRun);\r
607 BufferSize -= OverRun;\r
adbcbf8f 608\r
493d8e3a
RN
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
adbcbf8f 629\r
4e39b75e 630 Subtask = DiskIoCreateSubtask (Write, OverRunLba, 0, OverRun, WorkingBuffer, BufferPtr + BufferSize, Blocking);\r
493d8e3a 631 if (Subtask == NULL) {\r
adbcbf8f 632 goto Done;\r
633 }\r
493d8e3a 634 InsertTailList (Subtasks, &Subtask->Link);\r
adbcbf8f 635 }\r
493d8e3a
RN
636 \r
637 if (OverRunLba > Lba) {\r
adbcbf8f 638 //\r
639 // If the DiskIo maps directly to a BlockIo device do the read.\r
640 //\r
493d8e3a
RN
641 if (ALIGN_POINTER (BufferPtr, IoAlign) == BufferPtr) {\r
642 Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, NULL, BufferPtr, Blocking);\r
643 if (Subtask == NULL) {\r
adbcbf8f 644 goto Done;\r
645 }\r
493d8e3a 646 InsertTailList (Subtasks, &Subtask->Link);\r
adbcbf8f 647\r
493d8e3a
RN
648 BufferPtr += BufferSize;\r
649 Offset += BufferSize;\r
650 BufferSize -= BufferSize;\r
adbcbf8f 651\r
652 } else {\r
493d8e3a
RN
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 += DATA_BUFFER_BLOCK_NUM) {\r
659 DataBufferSize = MIN (BufferSize, DATA_BUFFER_BLOCK_NUM * 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
adbcbf8f 674 //\r
493d8e3a 675 // If there is not enough memory, downgrade to blocking access\r
adbcbf8f 676 //\r
493d8e3a
RN
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
adbcbf8f 687 }\r
688\r
493d8e3a
RN
689 BufferPtr += BufferSize;\r
690 Offset += BufferSize;\r
691 BufferSize -= BufferSize;\r
692 }\r
adbcbf8f 693 }\r
694 }\r
695\r
493d8e3a 696 ASSERT (BufferSize == 0);\r
adbcbf8f 697\r
493d8e3a 698 return TRUE;\r
adbcbf8f 699\r
700Done:\r
493d8e3a
RN
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
adbcbf8f 707 }\r
493d8e3a 708 return FALSE;\r
adbcbf8f 709}\r
710\r
adbcbf8f 711/**\r
493d8e3a 712 Terminate outstanding asynchronous requests to a device.\r
adbcbf8f 713\r
493d8e3a 714 @param This Indicates a pointer to the calling context.\r
adbcbf8f 715\r
493d8e3a
RN
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
adbcbf8f 719**/\r
720EFI_STATUS\r
721EFIAPI\r
493d8e3a
RN
722DiskIo2Cancel (\r
723 IN EFI_DISK_IO2_PROTOCOL *This\r
adbcbf8f 724 )\r
725{\r
493d8e3a
RN
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
adbcbf8f 731\r
493d8e3a 732 EfiAcquireLock (&Instance->TaskQueueLock);\r
adbcbf8f 733\r
493d8e3a
RN
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
adbcbf8f 739\r
493d8e3a
RN
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
adbcbf8f 748 }\r
749\r
493d8e3a 750 EfiReleaseLock (&Instance->TaskQueueLock);\r
adbcbf8f 751\r
493d8e3a
RN
752 return EFI_SUCCESS;\r
753}\r
adbcbf8f 754\r
493d8e3a
RN
755/**\r
756 Common routine to access the disk.\r
757\r
758 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.\r
759 @param Write TRUE: Write operation; FALSE: Read operation.\r
760 @param MediaId ID of the medium to access.\r
761 @param Offset The starting byte offset on the logical block I/O device to access.\r
762 @param Token A pointer to the token associated with the transaction.\r
763 If this field is NULL, synchronous/blocking IO is performed.\r
764 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.\r
765 @param Buffer A pointer to the destination buffer for the data.\r
766 The caller is responsible either having implicit or explicit ownership of the buffer. \r
767**/\r
768EFI_STATUS\r
769DiskIo2ReadWriteDisk (\r
770 IN DISK_IO_PRIVATE_DATA *Instance,\r
771 IN BOOLEAN Write,\r
772 IN UINT32 MediaId,\r
773 IN UINT64 Offset,\r
774 IN EFI_DISK_IO2_TOKEN *Token,\r
775 IN UINTN BufferSize,\r
776 IN UINT8 *Buffer\r
777 )\r
778{\r
779 EFI_STATUS Status;\r
780 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
781 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
782 EFI_BLOCK_IO_MEDIA *Media;\r
783 LIST_ENTRY *Link;\r
784 LIST_ENTRY Subtasks;\r
785 DISK_IO_SUBTASK *Subtask;\r
786 DISK_IO2_TASK *Task;\r
787 BOOLEAN TaskQueueEmpty;\r
788 EFI_TPL OldTpl;\r
789 BOOLEAN Blocking;\r
790 LIST_ENTRY *SubtasksPtr;\r
791\r
792 Task = NULL;\r
793 BlockIo = Instance->BlockIo;\r
794 BlockIo2 = Instance->BlockIo2;\r
795 Media = BlockIo->Media;\r
796 Status = EFI_SUCCESS;\r
de49225d 797 Blocking = (BOOLEAN) ((Token == NULL) || (Token->Event == NULL));\r
adbcbf8f 798\r
493d8e3a
RN
799 if (Media->MediaId != MediaId) {\r
800 return EFI_MEDIA_CHANGED;\r
adbcbf8f 801 }\r
493d8e3a
RN
802 \r
803 if (Write && Media->ReadOnly) {\r
804 return EFI_WRITE_PROTECTED;\r
805 }\r
806 \r
807 if (Blocking) {\r
adbcbf8f 808 //\r
493d8e3a 809 // Wait till pending async task is completed.\r
adbcbf8f 810 //\r
493d8e3a
RN
811 do {\r
812 EfiAcquireLock (&Instance->TaskQueueLock);\r
813 TaskQueueEmpty = IsListEmpty (&Instance->TaskQueue);\r
814 EfiReleaseLock (&Instance->TaskQueueLock);\r
815 } while (!TaskQueueEmpty);\r
adbcbf8f 816\r
493d8e3a
RN
817 SubtasksPtr = &Subtasks;\r
818 } else {\r
819 Task = AllocatePool (sizeof (DISK_IO2_TASK));\r
820 if (Task == NULL) {\r
821 return EFI_OUT_OF_RESOURCES;\r
adbcbf8f 822 }\r
493d8e3a
RN
823 \r
824 EfiAcquireLock (&Instance->TaskQueueLock);\r
825 InsertTailList (&Instance->TaskQueue, &Task->Link);\r
826 EfiReleaseLock (&Instance->TaskQueueLock);\r
adbcbf8f 827\r
493d8e3a
RN
828 Task->Signature = DISK_IO2_TASK_SIGNATURE;\r
829 Task->Instance = Instance;\r
830 Task->Token = Token;\r
adbcbf8f 831\r
493d8e3a
RN
832 SubtasksPtr = &Task->Subtasks;\r
833 }\r
adbcbf8f 834\r
493d8e3a
RN
835 InitializeListHead (SubtasksPtr);\r
836 if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, Buffer, Blocking, Instance->SharedWorkingBuffer, SubtasksPtr)) {\r
837 if (Task != NULL) {\r
838 FreePool (Task);\r
adbcbf8f 839 }\r
493d8e3a 840 return EFI_OUT_OF_RESOURCES;\r
adbcbf8f 841 }\r
493d8e3a 842 ASSERT (!IsListEmpty (SubtasksPtr));\r
adbcbf8f 843\r
493d8e3a
RN
844 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
845 for (Link = GetFirstNode (SubtasksPtr); !IsNull (SubtasksPtr, Link); Link = GetNextNode (SubtasksPtr, Link)) {\r
846 Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
adbcbf8f 847\r
493d8e3a
RN
848 if (!Subtask->Blocking) {\r
849 Subtask->Task = Task;\r
adbcbf8f 850 }\r
adbcbf8f 851\r
493d8e3a 852 if (Subtask->Write) {\r
adbcbf8f 853 //\r
493d8e3a 854 // Write\r
adbcbf8f 855 //\r
493d8e3a
RN
856 if (Subtask->WorkingBuffer != NULL) {\r
857 //\r
858 // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.\r
859 //\r
860 CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);\r
adbcbf8f 861 }\r
862\r
493d8e3a
RN
863 if (Subtask->Blocking) {\r
864 Status = BlockIo->WriteBlocks (\r
865 BlockIo,\r
866 MediaId,\r
867 Subtask->Lba,\r
868 Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,\r
869 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer\r
870 );\r
871 } else {\r
872 Status = BlockIo2->WriteBlocksEx (\r
873 BlockIo2,\r
874 MediaId,\r
875 Subtask->Lba,\r
876 &Subtask->BlockIo2Token,\r
877 Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,\r
878 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer\r
879 );\r
880 }\r
adbcbf8f 881\r
882 } else {\r
883 //\r
493d8e3a 884 // Read\r
adbcbf8f 885 //\r
493d8e3a
RN
886 if (Subtask->Blocking) {\r
887 Status = BlockIo->ReadBlocks (\r
adbcbf8f 888 BlockIo,\r
889 MediaId,\r
493d8e3a
RN
890 Subtask->Lba,\r
891 Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,\r
892 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer\r
adbcbf8f 893 );\r
493d8e3a
RN
894 if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {\r
895 CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);\r
adbcbf8f 896 }\r
493d8e3a
RN
897 } else {\r
898 Status = BlockIo2->ReadBlocksEx (\r
899 BlockIo2,\r
900 MediaId,\r
901 Subtask->Lba,\r
902 &Subtask->BlockIo2Token,\r
903 Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,\r
904 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer\r
905 );\r
906 }\r
907 }\r
908 \r
909 if (EFI_ERROR (Status)) {\r
910 break;\r
adbcbf8f 911 }\r
912 }\r
493d8e3a
RN
913 \r
914 gBS->RaiseTPL (TPL_NOTIFY);\r
adbcbf8f 915\r
493d8e3a
RN
916 //\r
917 // Remove all the remaining subtasks when failure.\r
918 // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.\r
919 //\r
920 if (EFI_ERROR (Status)) {\r
921 while (!IsNull (SubtasksPtr, Link)) {\r
922 Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
923 Link = DiskIoDestroySubtask (Instance, Subtask);\r
924 }\r
925 }\r
adbcbf8f 926\r
493d8e3a
RN
927 //\r
928 // Remove all the blocking subtasks because the non-blocking callback only removes the non-blocking subtask.\r
929 //\r
930 for (Link = GetFirstNode (SubtasksPtr); !IsNull (SubtasksPtr, Link); ) {\r
931 Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
932 if (Subtask->Blocking) {\r
933 Link = DiskIoDestroySubtask (Instance, Subtask);\r
934 } else {\r
935 Link = GetNextNode (SubtasksPtr, Link);\r
adbcbf8f 936 }\r
493d8e3a 937 }\r
adbcbf8f 938\r
493d8e3a
RN
939 //\r
940 // It's possible that the callback runs before raising TPL to NOTIFY,\r
941 // so the subtasks list only contains blocking subtask.\r
942 // Remove the Task after the blocking subtasks are removed in above.\r
943 //\r
944 if (!Blocking && IsListEmpty (SubtasksPtr)) {\r
945 EfiAcquireLock (&Instance->TaskQueueLock);\r
946 RemoveEntryList (&Task->Link);\r
947 EfiReleaseLock (&Instance->TaskQueueLock);\r
adbcbf8f 948\r
80c83a69 949 if (!EFI_ERROR (Status) && (Task->Token != NULL)) {\r
493d8e3a
RN
950 //\r
951 // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete\r
952 // It it's not, that means the non-blocking request was downgraded to blocking request.\r
953 //\r
954 DEBUG ((EFI_D_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));\r
955 Task->Token->TransactionStatus = Status;\r
956 gBS->SignalEvent (Task->Token->Event);\r
adbcbf8f 957 }\r
493d8e3a
RN
958\r
959 FreePool (Task);\r
adbcbf8f 960 }\r
961\r
493d8e3a
RN
962 gBS->RestoreTPL (OldTpl);\r
963\r
964 return Status;\r
965}\r
966\r
967/**\r
968 Reads a specified number of bytes from a device.\r
969\r
970 @param This Indicates a pointer to the calling context.\r
971 @param MediaId ID of the medium to be read.\r
972 @param Offset The starting byte offset on the logical block I/O device to read from.\r
973 @param Token A pointer to the token associated with the transaction.\r
974 If this field is NULL, synchronous/blocking IO is performed.\r
975 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.\r
976 @param Buffer A pointer to the destination buffer for the data.\r
977 The caller is responsible either having implicit or explicit ownership of the buffer.\r
978\r
979 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device.\r
980 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.\r
981 Event will be signaled upon completion.\r
982 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
983 @retval EFI_NO_MEDIA There is no medium in the device.\r
984 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.\r
985 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.\r
986 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
987\r
988**/\r
989EFI_STATUS\r
990EFIAPI\r
991DiskIo2ReadDiskEx (\r
992 IN EFI_DISK_IO2_PROTOCOL *This,\r
993 IN UINT32 MediaId,\r
994 IN UINT64 Offset,\r
995 IN OUT EFI_DISK_IO2_TOKEN *Token,\r
996 IN UINTN BufferSize,\r
997 OUT VOID *Buffer\r
998 )\r
999{\r
1000 return DiskIo2ReadWriteDisk (\r
1001 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),\r
1002 FALSE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer\r
1003 );\r
1004}\r
1005\r
1006/**\r
1007 Writes a specified number of bytes to a device.\r
1008\r
1009 @param This Indicates a pointer to the calling context.\r
1010 @param MediaId ID of the medium to be written.\r
1011 @param Offset The starting byte offset on the logical block I/O device to write to.\r
1012 @param Token A pointer to the token associated with the transaction.\r
1013 If this field is NULL, synchronous/blocking IO is performed.\r
1014 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.\r
1015 @param Buffer A pointer to the buffer containing the data to be written.\r
1016\r
1017 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to the device.\r
1018 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.\r
1019 Event will be signaled upon completion.\r
1020 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
1021 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.\r
1022 @retval EFI_NO_MEDIA There is no medium in the device.\r
1023 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.\r
1024 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.\r
1025 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
1026\r
1027**/\r
1028EFI_STATUS\r
1029EFIAPI\r
1030DiskIo2WriteDiskEx (\r
1031 IN EFI_DISK_IO2_PROTOCOL *This,\r
1032 IN UINT32 MediaId,\r
1033 IN UINT64 Offset,\r
1034 IN OUT EFI_DISK_IO2_TOKEN *Token,\r
1035 IN UINTN BufferSize,\r
1036 IN VOID *Buffer\r
1037 )\r
1038{\r
1039 return DiskIo2ReadWriteDisk (\r
1040 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),\r
1041 TRUE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer\r
1042 );\r
1043}\r
1044\r
1045/**\r
1046 The callback for the BlockIo2 FlushBlocksEx.\r
1047 @param Event Event whose notification function is being invoked.\r
1048 @param Context The pointer to the notification function's context,\r
1049 which points to the DISK_IO2_FLUSH_TASK instance.\r
1050**/\r
1051VOID\r
1052EFIAPI\r
1053DiskIo2OnFlushComplete (\r
1054 IN EFI_EVENT Event,\r
1055 IN VOID *Context\r
1056 )\r
1057{\r
1058 DISK_IO2_FLUSH_TASK *Task;\r
1059\r
1060 gBS->CloseEvent (Event);\r
1061\r
1062 Task = (DISK_IO2_FLUSH_TASK *) Context;\r
1063 ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);\r
1064 Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;\r
1065 gBS->SignalEvent (Task->Token->Event);\r
1066}\r
1067\r
1068/**\r
1069 Flushes all modified data to the physical device.\r
1070\r
1071 @param This Indicates a pointer to the calling context.\r
1072 @param Token A pointer to the token associated with the transaction.\r
1073 If this field is NULL, synchronous/blocking IO is performed.\r
1074\r
1075 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device.\r
1076 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.\r
1077 Event will be signaled upon completion.\r
1078 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
1079 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.\r
1080 @retval EFI_NO_MEDIA There is no medium in the device.\r
1081 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
1082**/\r
1083EFI_STATUS\r
1084EFIAPI\r
1085DiskIo2FlushDiskEx (\r
1086 IN EFI_DISK_IO2_PROTOCOL *This,\r
1087 IN OUT EFI_DISK_IO2_TOKEN *Token\r
1088 )\r
1089{\r
1090 EFI_STATUS Status;\r
1091 DISK_IO2_FLUSH_TASK *Task;\r
1092 DISK_IO_PRIVATE_DATA *Private;\r
1093\r
1094 Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);\r
1095\r
1096 if ((Token != NULL) && (Token->Event != NULL)) {\r
1097 Task = AllocatePool (sizeof (DISK_IO2_FLUSH_TASK));\r
1098 if (Task == NULL) {\r
1099 return EFI_OUT_OF_RESOURCES;\r
1100 }\r
1101\r
1102 Status = gBS->CreateEvent (\r
1103 EVT_NOTIFY_SIGNAL,\r
1104 TPL_CALLBACK,\r
1105 DiskIo2OnFlushComplete,\r
1106 Task,\r
1107 &Task->BlockIo2Token.Event\r
1108 );\r
1109 if (EFI_ERROR (Status)) {\r
1110 FreePool (Task);\r
1111 return Status;\r
1112 }\r
1113 Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE;\r
1114 Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);\r
1115 if (EFI_ERROR (Status)) {\r
1116 gBS->CloseEvent (Task->BlockIo2Token.Event);\r
1117 FreePool (Task);\r
1118 }\r
1119 } else {\r
1120 Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, NULL);\r
adbcbf8f 1121 }\r
1122\r
1123 return Status;\r
1124}\r
1125\r
493d8e3a
RN
1126/**\r
1127 Read BufferSize bytes from Offset into Buffer.\r
1128 Reads may support reads that are not aligned on\r
1129 sector boundaries. There are three cases:\r
1130 UnderRun - The first byte is not on a sector boundary or the read request is\r
1131 less than a sector in length.\r
1132 Aligned - A read of N contiguous sectors.\r
1133 OverRun - The last byte is not on a sector boundary.\r
1134\r
1135 @param This Protocol instance pointer.\r
1136 @param MediaId Id of the media, changes every time the media is replaced.\r
1137 @param Offset The starting byte offset to read from\r
1138 @param BufferSize Size of Buffer\r
1139 @param Buffer Buffer containing read data\r
1140\r
1141 @retval EFI_SUCCESS The data was read correctly from the device.\r
1142 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
1143 @retval EFI_NO_MEDIA There is no media in the device.\r
1144 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
1145 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not\r
1146 valid for the device.\r
1147\r
1148**/\r
1149EFI_STATUS\r
1150EFIAPI\r
1151DiskIoReadDisk (\r
1152 IN EFI_DISK_IO_PROTOCOL *This,\r
1153 IN UINT32 MediaId,\r
1154 IN UINT64 Offset,\r
1155 IN UINTN BufferSize,\r
1156 OUT VOID *Buffer\r
1157 )\r
1158{\r
1159 return DiskIo2ReadWriteDisk (\r
1160 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),\r
1161 FALSE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer\r
1162 );\r
1163}\r
1164\r
1165\r
1166/**\r
1167 Writes BufferSize bytes from Buffer into Offset.\r
1168 Writes may require a read modify write to support writes that are not\r
1169 aligned on sector boundaries. There are three cases:\r
1170 UnderRun - The first byte is not on a sector boundary or the write request\r
1171 is less than a sector in length. Read modify write is required.\r
1172 Aligned - A write of N contiguous sectors.\r
1173 OverRun - The last byte is not on a sector boundary. Read modified write\r
1174 required.\r
1175\r
1176 @param This Protocol instance pointer.\r
1177 @param MediaId Id of the media, changes every time the media is replaced.\r
1178 @param Offset The starting byte offset to read from\r
1179 @param BufferSize Size of Buffer\r
1180 @param Buffer Buffer containing read data\r
1181\r
1182 @retval EFI_SUCCESS The data was written correctly to the device.\r
1183 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
1184 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
1185 @retval EFI_NO_MEDIA There is no media in the device.\r
1186 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
1187 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not\r
1188 valid for the device.\r
1189\r
1190**/\r
1191EFI_STATUS\r
1192EFIAPI\r
1193DiskIoWriteDisk (\r
1194 IN EFI_DISK_IO_PROTOCOL *This,\r
1195 IN UINT32 MediaId,\r
1196 IN UINT64 Offset,\r
1197 IN UINTN BufferSize,\r
1198 IN VOID *Buffer\r
1199 )\r
1200{\r
1201 return DiskIo2ReadWriteDisk (\r
1202 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),\r
1203 TRUE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer\r
1204 );\r
1205}\r
adbcbf8f 1206\r
1207/**\r
1208 The user Entry Point for module DiskIo. The user code starts with this function.\r
1209\r
1210 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
1211 @param[in] SystemTable A pointer to the EFI System Table.\r
1212 \r
1213 @retval EFI_SUCCESS The entry point is executed successfully.\r
1214 @retval other Some error occurs when executing this entry point.\r
1215\r
1216**/\r
1217EFI_STATUS\r
1218EFIAPI\r
1219InitializeDiskIo (\r
1220 IN EFI_HANDLE ImageHandle,\r
1221 IN EFI_SYSTEM_TABLE *SystemTable\r
1222 )\r
1223{\r
1224 EFI_STATUS Status;\r
1225\r
1226 //\r
1227 // Install driver model protocol(s).\r
1228 //\r
d38a0f44 1229 Status = EfiLibInstallDriverBindingComponentName2 (\r
adbcbf8f 1230 ImageHandle,\r
1231 SystemTable,\r
1232 &gDiskIoDriverBinding,\r
1233 ImageHandle,\r
1234 &gDiskIoComponentName,\r
d38a0f44 1235 &gDiskIoComponentName2\r
adbcbf8f 1236 );\r
1237 ASSERT_EFI_ERROR (Status);\r
1238\r
adbcbf8f 1239 return Status;\r
1240}\r