]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
MdeModulePkg/DiskIoDxe: fix source/destination pointer of overrun transfer
[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
406 gBS->CloseEvent (Event);\r
407\r
408 Subtask = (DISK_IO_SUBTASK *) Context;\r
409 TransactionStatus = Subtask->BlockIo2Token.TransactionStatus;\r
410 Task = Subtask->Task;\r
411 Instance = Task->Instance;\r
412\r
413 ASSERT (Subtask->Signature == DISK_IO_SUBTASK_SIGNATURE);\r
414 ASSERT (Instance->Signature == DISK_IO_PRIVATE_DATA_SIGNATURE);\r
415 ASSERT (Task->Signature == DISK_IO2_TASK_SIGNATURE);\r
adbcbf8f 416\r
493d8e3a
RN
417 if (Subtask->WorkingBuffer != NULL) {\r
418 if (!EFI_ERROR (TransactionStatus) && (Task->Token != NULL) && !Subtask->Write) {\r
419 CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);\r
420 }\r
421\r
422 //\r
423 // The WorkingBuffer of blocking subtask either points to SharedWorkingBuffer\r
424 // or will be used by non-blocking subtask which will be freed below.\r
425 //\r
426 if (!Subtask->Blocking) {\r
427 FreeAlignedPages (\r
428 Subtask->WorkingBuffer, \r
429 Subtask->Length < Instance->BlockIo->Media->BlockSize\r
430 ? EFI_SIZE_TO_PAGES (Instance->BlockIo->Media->BlockSize)\r
431 : EFI_SIZE_TO_PAGES (Subtask->Length)\r
432 );\r
433 }\r
434 }\r
435 RemoveEntryList (&Subtask->Link);\r
436 FreePool (Subtask);\r
437\r
438 if (EFI_ERROR (TransactionStatus) || IsListEmpty (&Task->Subtasks)) {\r
439 if (Task->Token != NULL) {\r
440 //\r
441 // Signal error status once the subtask is failed.\r
442 // Or signal the last status once the last subtask is finished.\r
443 //\r
444 Task->Token->TransactionStatus = TransactionStatus;\r
445 gBS->SignalEvent (Task->Token->Event);\r
446\r
447 //\r
448 // Mark token to NULL\r
449 //\r
450 Task->Token = NULL;\r
451 }\r
452 }\r
453\r
454 if (IsListEmpty (&Task->Subtasks)) {\r
455 EfiAcquireLock (&Instance->TaskQueueLock);\r
456 RemoveEntryList (&Task->Link);\r
457 EfiReleaseLock (&Instance->TaskQueueLock);\r
458\r
459 FreePool (Task);\r
460 }\r
461}\r
adbcbf8f 462\r
463/**\r
493d8e3a 464 Create the subtask.\r
adbcbf8f 465\r
493d8e3a
RN
466 @param Write TRUE: Write request; FALSE: Read request.\r
467 @param Lba The starting logical block address to read from on the device.\r
468 @param Offset The starting byte offset to read from the LBA.\r
469 @param Length The number of bytes to read from the device.\r
470 @param WorkingBuffer The aligned buffer to hold the data for reading or writing.\r
471 @param Buffer The buffer to hold the data for reading or writing.\r
472 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.\r
adbcbf8f 473\r
493d8e3a
RN
474 @return A pointer to the created subtask.\r
475**/\r
476DISK_IO_SUBTASK *\r
477DiskIoCreateSubtask (\r
478 IN BOOLEAN Write,\r
479 IN UINT64 Lba,\r
480 IN UINT32 Offset,\r
481 IN UINTN Length,\r
482 IN VOID *WorkingBuffer, OPTIONAL\r
483 IN VOID *Buffer,\r
484 IN BOOLEAN Blocking\r
485 )\r
486{\r
487 DISK_IO_SUBTASK *Subtask;\r
488 EFI_STATUS Status;\r
adbcbf8f 489\r
493d8e3a
RN
490 Subtask = AllocateZeroPool (sizeof (DISK_IO_SUBTASK));\r
491 if (Subtask == NULL) {\r
492 return NULL;\r
493 }\r
494 Subtask->Signature = DISK_IO_SUBTASK_SIGNATURE;\r
495 Subtask->Write = Write;\r
496 Subtask->Lba = Lba;\r
497 Subtask->Offset = Offset;\r
498 Subtask->Length = Length;\r
499 Subtask->WorkingBuffer = WorkingBuffer;\r
500 Subtask->Buffer = Buffer;\r
501 Subtask->Blocking = Blocking;\r
502 if (!Blocking) {\r
503 Status = gBS->CreateEvent (\r
504 EVT_NOTIFY_SIGNAL,\r
505 TPL_NOTIFY,\r
506 DiskIo2OnReadWriteComplete,\r
507 Subtask,\r
508 &Subtask->BlockIo2Token.Event\r
509 );\r
510 if (EFI_ERROR (Status)) {\r
511 FreePool (Subtask);\r
512 return NULL;\r
513 }\r
514 }\r
515 DEBUG ((\r
516 EFI_D_BLKIO, \r
517 " %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",\r
518 Write ? 'W': 'R', Lba, Offset, Length, WorkingBuffer, Buffer\r
519 ));\r
520\r
521 return Subtask;\r
522}\r
523\r
524/**\r
525 Create the subtask list.\r
526\r
527 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.\r
528 @param Write TRUE: Write request; FALSE: Read request.\r
529 @param Offset The starting byte offset to read from the device.\r
530 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.\r
531 @param Buffer A pointer to the buffer for the data.\r
532 @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.\r
533 @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing.\r
534 @param Subtasks The subtask list header.\r
535\r
536 @retval TRUE The subtask list is created successfully.\r
537 @retval FALSE The subtask list is not created.\r
adbcbf8f 538**/\r
493d8e3a
RN
539BOOLEAN\r
540DiskIoCreateSubtaskList (\r
541 IN DISK_IO_PRIVATE_DATA *Instance,\r
542 IN BOOLEAN Write,\r
adbcbf8f 543 IN UINT64 Offset,\r
544 IN UINTN BufferSize,\r
493d8e3a
RN
545 IN VOID *Buffer,\r
546 IN BOOLEAN Blocking,\r
547 IN VOID *SharedWorkingBuffer,\r
548 IN OUT LIST_ENTRY *Subtasks\r
adbcbf8f 549 )\r
550{\r
adbcbf8f 551 UINT32 BlockSize;\r
493d8e3a 552 UINT32 IoAlign;\r
adbcbf8f 553 UINT64 Lba;\r
554 UINT64 OverRunLba;\r
555 UINT32 UnderRun;\r
556 UINT32 OverRun;\r
493d8e3a 557 UINT8 *BufferPtr;\r
adbcbf8f 558 UINTN Length;\r
adbcbf8f 559 UINTN DataBufferSize;\r
493d8e3a
RN
560 DISK_IO_SUBTASK *Subtask;\r
561 VOID *WorkingBuffer;\r
562 LIST_ENTRY *Link;\r
adbcbf8f 563\r
493d8e3a 564 DEBUG ((EFI_D_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));\r
adbcbf8f 565\r
493d8e3a
RN
566 BlockSize = Instance->BlockIo->Media->BlockSize;\r
567 IoAlign = Instance->BlockIo->Media->IoAlign;\r
568 if (IoAlign == 0) {\r
569 IoAlign = 1;\r
adbcbf8f 570 }\r
493d8e3a
RN
571 \r
572 Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);\r
573 BufferPtr = (UINT8 *) Buffer;\r
adbcbf8f 574\r
575 //\r
493d8e3a 576 // Special handling for zero BufferSize\r
adbcbf8f 577 //\r
493d8e3a
RN
578 if (BufferSize == 0) {\r
579 Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, 0, NULL, BufferPtr, Blocking);\r
580 if (Subtask == NULL) {\r
581 goto Done;\r
582 }\r
583 InsertTailList (Subtasks, &Subtask->Link);\r
584 return TRUE;\r
adbcbf8f 585 }\r
586\r
adbcbf8f 587 if (UnderRun != 0) {\r
493d8e3a
RN
588 Length = MIN (BlockSize - UnderRun, BufferSize);\r
589 if (Blocking) {\r
590 WorkingBuffer = SharedWorkingBuffer;\r
591 } else {\r
592 WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);\r
593 if (WorkingBuffer == NULL) {\r
594 goto Done;\r
595 }\r
596 }\r
597 if (Write) {\r
598 //\r
599 // A half write operation can be splitted to a blocking block-read and half write operation\r
600 // This can simplify the sub task processing logic\r
601 //\r
602 Subtask = DiskIoCreateSubtask (FALSE, Lba, 0, BlockSize, NULL, WorkingBuffer, TRUE);\r
603 if (Subtask == NULL) {\r
604 goto Done;\r
605 }\r
606 InsertTailList (Subtasks, &Subtask->Link);\r
adbcbf8f 607 }\r
608\r
493d8e3a
RN
609 Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, Length, WorkingBuffer, BufferPtr, Blocking);\r
610 if (Subtask == NULL) {\r
611 goto Done;\r
adbcbf8f 612 }\r
493d8e3a
RN
613 InsertTailList (Subtasks, &Subtask->Link);\r
614 \r
615 BufferPtr += Length;\r
616 Offset += Length;\r
617 BufferSize -= Length;\r
618 Lba ++;\r
619 }\r
adbcbf8f 620\r
493d8e3a
RN
621 OverRunLba = Lba + DivU64x32Remainder (BufferSize, BlockSize, &OverRun);\r
622 BufferSize -= OverRun;\r
adbcbf8f 623\r
493d8e3a
RN
624 if (OverRun != 0) {\r
625 if (Blocking) {\r
626 WorkingBuffer = SharedWorkingBuffer;\r
627 } else {\r
628 WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);\r
629 if (WorkingBuffer == NULL) {\r
630 goto Done;\r
631 }\r
632 }\r
633 if (Write) {\r
634 //\r
635 // A half write operation can be splitted to a blocking block-read and half write operation\r
636 // This can simplify the sub task processing logic\r
637 //\r
638 Subtask = DiskIoCreateSubtask (FALSE, OverRunLba, 0, BlockSize, NULL, WorkingBuffer, TRUE);\r
639 if (Subtask == NULL) {\r
640 goto Done;\r
641 }\r
642 InsertTailList (Subtasks, &Subtask->Link);\r
643 }\r
adbcbf8f 644\r
4e39b75e 645 Subtask = DiskIoCreateSubtask (Write, OverRunLba, 0, OverRun, WorkingBuffer, BufferPtr + BufferSize, Blocking);\r
493d8e3a 646 if (Subtask == NULL) {\r
adbcbf8f 647 goto Done;\r
648 }\r
493d8e3a 649 InsertTailList (Subtasks, &Subtask->Link);\r
adbcbf8f 650 }\r
493d8e3a
RN
651 \r
652 if (OverRunLba > Lba) {\r
adbcbf8f 653 //\r
654 // If the DiskIo maps directly to a BlockIo device do the read.\r
655 //\r
493d8e3a
RN
656 if (ALIGN_POINTER (BufferPtr, IoAlign) == BufferPtr) {\r
657 Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, NULL, BufferPtr, Blocking);\r
658 if (Subtask == NULL) {\r
adbcbf8f 659 goto Done;\r
660 }\r
493d8e3a 661 InsertTailList (Subtasks, &Subtask->Link);\r
adbcbf8f 662\r
493d8e3a
RN
663 BufferPtr += BufferSize;\r
664 Offset += BufferSize;\r
665 BufferSize -= BufferSize;\r
adbcbf8f 666\r
667 } else {\r
493d8e3a
RN
668 if (Blocking) {\r
669 //\r
670 // Use the allocated buffer instead of the original buffer\r
671 // to avoid alignment issue.\r
672 //\r
673 for (; Lba < OverRunLba; Lba += DATA_BUFFER_BLOCK_NUM) {\r
674 DataBufferSize = MIN (BufferSize, DATA_BUFFER_BLOCK_NUM * BlockSize);\r
675\r
676 Subtask = DiskIoCreateSubtask (Write, Lba, 0, DataBufferSize, SharedWorkingBuffer, BufferPtr, Blocking);\r
677 if (Subtask == NULL) {\r
678 goto Done;\r
679 }\r
680 InsertTailList (Subtasks, &Subtask->Link);\r
681\r
682 BufferPtr += DataBufferSize;\r
683 Offset += DataBufferSize;\r
684 BufferSize -= DataBufferSize;\r
685 }\r
686 } else {\r
687 WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), IoAlign);\r
688 if (WorkingBuffer == NULL) {\r
adbcbf8f 689 //\r
493d8e3a 690 // If there is not enough memory, downgrade to blocking access\r
adbcbf8f 691 //\r
493d8e3a
RN
692 DEBUG ((EFI_D_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n"));\r
693 if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, BufferPtr, TRUE, SharedWorkingBuffer, Subtasks)) {\r
694 goto Done;\r
695 }\r
696 } else {\r
697 Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, WorkingBuffer, BufferPtr, Blocking);\r
698 if (Subtask == NULL) {\r
699 goto Done;\r
700 }\r
701 InsertTailList (Subtasks, &Subtask->Link);\r
adbcbf8f 702 }\r
703\r
493d8e3a
RN
704 BufferPtr += BufferSize;\r
705 Offset += BufferSize;\r
706 BufferSize -= BufferSize;\r
707 }\r
adbcbf8f 708 }\r
709 }\r
710\r
493d8e3a 711 ASSERT (BufferSize == 0);\r
adbcbf8f 712\r
493d8e3a 713 return TRUE;\r
adbcbf8f 714\r
715Done:\r
493d8e3a
RN
716 //\r
717 // Remove all the subtasks.\r
718 //\r
719 for (Link = GetFirstNode (Subtasks); !IsNull (Subtasks, Link); ) {\r
720 Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
721 Link = DiskIoDestroySubtask (Instance, Subtask);\r
adbcbf8f 722 }\r
493d8e3a 723 return FALSE;\r
adbcbf8f 724}\r
725\r
adbcbf8f 726/**\r
493d8e3a 727 Terminate outstanding asynchronous requests to a device.\r
adbcbf8f 728\r
493d8e3a 729 @param This Indicates a pointer to the calling context.\r
adbcbf8f 730\r
493d8e3a
RN
731 @retval EFI_SUCCESS All outstanding requests were successfully terminated.\r
732 @retval EFI_DEVICE_ERROR The device reported an error while performing the cancel\r
733 operation.\r
adbcbf8f 734**/\r
735EFI_STATUS\r
736EFIAPI\r
493d8e3a
RN
737DiskIo2Cancel (\r
738 IN EFI_DISK_IO2_PROTOCOL *This\r
adbcbf8f 739 )\r
740{\r
493d8e3a
RN
741 DISK_IO_PRIVATE_DATA *Instance;\r
742 DISK_IO2_TASK *Task;\r
743 LIST_ENTRY *Link;\r
744 \r
745 Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);\r
adbcbf8f 746\r
493d8e3a 747 EfiAcquireLock (&Instance->TaskQueueLock);\r
adbcbf8f 748\r
493d8e3a
RN
749 for (Link = GetFirstNode (&Instance->TaskQueue)\r
750 ; !IsNull (&Instance->TaskQueue, Link)\r
751 ; Link = GetNextNode (&Instance->TaskQueue, Link)\r
752 ) {\r
753 Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);\r
adbcbf8f 754\r
493d8e3a
RN
755 if (Task->Token != NULL) {\r
756 Task->Token->TransactionStatus = EFI_ABORTED;\r
757 gBS->SignalEvent (Task->Token->Event);\r
758 //\r
759 // Set Token to NULL so that the further BlockIo2 responses will be ignored\r
760 //\r
761 Task->Token = NULL;\r
762 }\r
adbcbf8f 763 }\r
764\r
493d8e3a 765 EfiReleaseLock (&Instance->TaskQueueLock);\r
adbcbf8f 766\r
493d8e3a
RN
767 return EFI_SUCCESS;\r
768}\r
adbcbf8f 769\r
493d8e3a
RN
770/**\r
771 Common routine to access the disk.\r
772\r
773 @param Instance Pointer to the DISK_IO_PRIVATE_DATA.\r
774 @param Write TRUE: Write operation; FALSE: Read operation.\r
775 @param MediaId ID of the medium to access.\r
776 @param Offset The starting byte offset on the logical block I/O device to access.\r
777 @param Token A pointer to the token associated with the transaction.\r
778 If this field is NULL, synchronous/blocking IO is performed.\r
779 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.\r
780 @param Buffer A pointer to the destination buffer for the data.\r
781 The caller is responsible either having implicit or explicit ownership of the buffer. \r
782**/\r
783EFI_STATUS\r
784DiskIo2ReadWriteDisk (\r
785 IN DISK_IO_PRIVATE_DATA *Instance,\r
786 IN BOOLEAN Write,\r
787 IN UINT32 MediaId,\r
788 IN UINT64 Offset,\r
789 IN EFI_DISK_IO2_TOKEN *Token,\r
790 IN UINTN BufferSize,\r
791 IN UINT8 *Buffer\r
792 )\r
793{\r
794 EFI_STATUS Status;\r
795 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
796 EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
797 EFI_BLOCK_IO_MEDIA *Media;\r
798 LIST_ENTRY *Link;\r
799 LIST_ENTRY Subtasks;\r
800 DISK_IO_SUBTASK *Subtask;\r
801 DISK_IO2_TASK *Task;\r
802 BOOLEAN TaskQueueEmpty;\r
803 EFI_TPL OldTpl;\r
804 BOOLEAN Blocking;\r
805 LIST_ENTRY *SubtasksPtr;\r
806\r
807 Task = NULL;\r
808 BlockIo = Instance->BlockIo;\r
809 BlockIo2 = Instance->BlockIo2;\r
810 Media = BlockIo->Media;\r
811 Status = EFI_SUCCESS;\r
de49225d 812 Blocking = (BOOLEAN) ((Token == NULL) || (Token->Event == NULL));\r
adbcbf8f 813\r
493d8e3a
RN
814 if (Media->MediaId != MediaId) {\r
815 return EFI_MEDIA_CHANGED;\r
adbcbf8f 816 }\r
493d8e3a
RN
817 \r
818 if (Write && Media->ReadOnly) {\r
819 return EFI_WRITE_PROTECTED;\r
820 }\r
821 \r
822 if (Blocking) {\r
adbcbf8f 823 //\r
493d8e3a 824 // Wait till pending async task is completed.\r
adbcbf8f 825 //\r
493d8e3a
RN
826 do {\r
827 EfiAcquireLock (&Instance->TaskQueueLock);\r
828 TaskQueueEmpty = IsListEmpty (&Instance->TaskQueue);\r
829 EfiReleaseLock (&Instance->TaskQueueLock);\r
830 } while (!TaskQueueEmpty);\r
adbcbf8f 831\r
493d8e3a
RN
832 SubtasksPtr = &Subtasks;\r
833 } else {\r
834 Task = AllocatePool (sizeof (DISK_IO2_TASK));\r
835 if (Task == NULL) {\r
836 return EFI_OUT_OF_RESOURCES;\r
adbcbf8f 837 }\r
493d8e3a
RN
838 \r
839 EfiAcquireLock (&Instance->TaskQueueLock);\r
840 InsertTailList (&Instance->TaskQueue, &Task->Link);\r
841 EfiReleaseLock (&Instance->TaskQueueLock);\r
adbcbf8f 842\r
493d8e3a
RN
843 Task->Signature = DISK_IO2_TASK_SIGNATURE;\r
844 Task->Instance = Instance;\r
845 Task->Token = Token;\r
adbcbf8f 846\r
493d8e3a
RN
847 SubtasksPtr = &Task->Subtasks;\r
848 }\r
adbcbf8f 849\r
493d8e3a
RN
850 InitializeListHead (SubtasksPtr);\r
851 if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, Buffer, Blocking, Instance->SharedWorkingBuffer, SubtasksPtr)) {\r
852 if (Task != NULL) {\r
853 FreePool (Task);\r
adbcbf8f 854 }\r
493d8e3a 855 return EFI_OUT_OF_RESOURCES;\r
adbcbf8f 856 }\r
493d8e3a 857 ASSERT (!IsListEmpty (SubtasksPtr));\r
adbcbf8f 858\r
493d8e3a
RN
859 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
860 for (Link = GetFirstNode (SubtasksPtr); !IsNull (SubtasksPtr, Link); Link = GetNextNode (SubtasksPtr, Link)) {\r
861 Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
adbcbf8f 862\r
493d8e3a
RN
863 if (!Subtask->Blocking) {\r
864 Subtask->Task = Task;\r
adbcbf8f 865 }\r
adbcbf8f 866\r
493d8e3a 867 if (Subtask->Write) {\r
adbcbf8f 868 //\r
493d8e3a 869 // Write\r
adbcbf8f 870 //\r
493d8e3a
RN
871 if (Subtask->WorkingBuffer != NULL) {\r
872 //\r
873 // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.\r
874 //\r
875 CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);\r
adbcbf8f 876 }\r
877\r
493d8e3a
RN
878 if (Subtask->Blocking) {\r
879 Status = BlockIo->WriteBlocks (\r
880 BlockIo,\r
881 MediaId,\r
882 Subtask->Lba,\r
883 Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,\r
884 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer\r
885 );\r
886 } else {\r
887 Status = BlockIo2->WriteBlocksEx (\r
888 BlockIo2,\r
889 MediaId,\r
890 Subtask->Lba,\r
891 &Subtask->BlockIo2Token,\r
892 Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,\r
893 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer\r
894 );\r
895 }\r
adbcbf8f 896\r
897 } else {\r
898 //\r
493d8e3a 899 // Read\r
adbcbf8f 900 //\r
493d8e3a
RN
901 if (Subtask->Blocking) {\r
902 Status = BlockIo->ReadBlocks (\r
adbcbf8f 903 BlockIo,\r
904 MediaId,\r
493d8e3a
RN
905 Subtask->Lba,\r
906 Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,\r
907 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer\r
adbcbf8f 908 );\r
493d8e3a
RN
909 if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {\r
910 CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);\r
adbcbf8f 911 }\r
493d8e3a
RN
912 } else {\r
913 Status = BlockIo2->ReadBlocksEx (\r
914 BlockIo2,\r
915 MediaId,\r
916 Subtask->Lba,\r
917 &Subtask->BlockIo2Token,\r
918 Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,\r
919 (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer\r
920 );\r
921 }\r
922 }\r
923 \r
924 if (EFI_ERROR (Status)) {\r
925 break;\r
adbcbf8f 926 }\r
927 }\r
493d8e3a
RN
928 \r
929 gBS->RaiseTPL (TPL_NOTIFY);\r
adbcbf8f 930\r
493d8e3a
RN
931 //\r
932 // Remove all the remaining subtasks when failure.\r
933 // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.\r
934 //\r
935 if (EFI_ERROR (Status)) {\r
936 while (!IsNull (SubtasksPtr, Link)) {\r
937 Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
938 Link = DiskIoDestroySubtask (Instance, Subtask);\r
939 }\r
940 }\r
adbcbf8f 941\r
493d8e3a
RN
942 //\r
943 // Remove all the blocking subtasks because the non-blocking callback only removes the non-blocking subtask.\r
944 //\r
945 for (Link = GetFirstNode (SubtasksPtr); !IsNull (SubtasksPtr, Link); ) {\r
946 Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
947 if (Subtask->Blocking) {\r
948 Link = DiskIoDestroySubtask (Instance, Subtask);\r
949 } else {\r
950 Link = GetNextNode (SubtasksPtr, Link);\r
adbcbf8f 951 }\r
493d8e3a 952 }\r
adbcbf8f 953\r
493d8e3a
RN
954 //\r
955 // It's possible that the callback runs before raising TPL to NOTIFY,\r
956 // so the subtasks list only contains blocking subtask.\r
957 // Remove the Task after the blocking subtasks are removed in above.\r
958 //\r
959 if (!Blocking && IsListEmpty (SubtasksPtr)) {\r
960 EfiAcquireLock (&Instance->TaskQueueLock);\r
961 RemoveEntryList (&Task->Link);\r
962 EfiReleaseLock (&Instance->TaskQueueLock);\r
adbcbf8f 963\r
493d8e3a
RN
964 if (Task->Token != NULL) {\r
965 //\r
966 // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete\r
967 // It it's not, that means the non-blocking request was downgraded to blocking request.\r
968 //\r
969 DEBUG ((EFI_D_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));\r
970 Task->Token->TransactionStatus = Status;\r
971 gBS->SignalEvent (Task->Token->Event);\r
adbcbf8f 972 }\r
493d8e3a
RN
973\r
974 FreePool (Task);\r
adbcbf8f 975 }\r
976\r
493d8e3a
RN
977 gBS->RestoreTPL (OldTpl);\r
978\r
979 return Status;\r
980}\r
981\r
982/**\r
983 Reads a specified number of bytes from a device.\r
984\r
985 @param This Indicates a pointer to the calling context.\r
986 @param MediaId ID of the medium to be read.\r
987 @param Offset The starting byte offset on the logical block I/O device to read from.\r
988 @param Token A pointer to the token associated with the transaction.\r
989 If this field is NULL, synchronous/blocking IO is performed.\r
990 @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.\r
991 @param Buffer A pointer to the destination buffer for the data.\r
992 The caller is responsible either having implicit or explicit ownership of the buffer.\r
993\r
994 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device.\r
995 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.\r
996 Event will be signaled upon completion.\r
997 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
998 @retval EFI_NO_MEDIA There is no medium in the device.\r
999 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.\r
1000 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.\r
1001 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
1002\r
1003**/\r
1004EFI_STATUS\r
1005EFIAPI\r
1006DiskIo2ReadDiskEx (\r
1007 IN EFI_DISK_IO2_PROTOCOL *This,\r
1008 IN UINT32 MediaId,\r
1009 IN UINT64 Offset,\r
1010 IN OUT EFI_DISK_IO2_TOKEN *Token,\r
1011 IN UINTN BufferSize,\r
1012 OUT VOID *Buffer\r
1013 )\r
1014{\r
1015 return DiskIo2ReadWriteDisk (\r
1016 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),\r
1017 FALSE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer\r
1018 );\r
1019}\r
1020\r
1021/**\r
1022 Writes a specified number of bytes to a device.\r
1023\r
1024 @param This Indicates a pointer to the calling context.\r
1025 @param MediaId ID of the medium to be written.\r
1026 @param Offset The starting byte offset on the logical block I/O device to write to.\r
1027 @param Token A pointer to the token associated with the transaction.\r
1028 If this field is NULL, synchronous/blocking IO is performed.\r
1029 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.\r
1030 @param Buffer A pointer to the buffer containing the data to be written.\r
1031\r
1032 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to the device.\r
1033 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.\r
1034 Event will be signaled upon completion.\r
1035 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
1036 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.\r
1037 @retval EFI_NO_MEDIA There is no medium in the device.\r
1038 @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.\r
1039 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.\r
1040 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
1041\r
1042**/\r
1043EFI_STATUS\r
1044EFIAPI\r
1045DiskIo2WriteDiskEx (\r
1046 IN EFI_DISK_IO2_PROTOCOL *This,\r
1047 IN UINT32 MediaId,\r
1048 IN UINT64 Offset,\r
1049 IN OUT EFI_DISK_IO2_TOKEN *Token,\r
1050 IN UINTN BufferSize,\r
1051 IN VOID *Buffer\r
1052 )\r
1053{\r
1054 return DiskIo2ReadWriteDisk (\r
1055 DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),\r
1056 TRUE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer\r
1057 );\r
1058}\r
1059\r
1060/**\r
1061 The callback for the BlockIo2 FlushBlocksEx.\r
1062 @param Event Event whose notification function is being invoked.\r
1063 @param Context The pointer to the notification function's context,\r
1064 which points to the DISK_IO2_FLUSH_TASK instance.\r
1065**/\r
1066VOID\r
1067EFIAPI\r
1068DiskIo2OnFlushComplete (\r
1069 IN EFI_EVENT Event,\r
1070 IN VOID *Context\r
1071 )\r
1072{\r
1073 DISK_IO2_FLUSH_TASK *Task;\r
1074\r
1075 gBS->CloseEvent (Event);\r
1076\r
1077 Task = (DISK_IO2_FLUSH_TASK *) Context;\r
1078 ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);\r
1079 Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;\r
1080 gBS->SignalEvent (Task->Token->Event);\r
1081}\r
1082\r
1083/**\r
1084 Flushes all modified data to the physical device.\r
1085\r
1086 @param This Indicates a pointer to the calling context.\r
1087 @param Token A pointer to the token associated with the transaction.\r
1088 If this field is NULL, synchronous/blocking IO is performed.\r
1089\r
1090 @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device.\r
1091 If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.\r
1092 Event will be signaled upon completion.\r
1093 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
1094 @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.\r
1095 @retval EFI_NO_MEDIA There is no medium in the device.\r
1096 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
1097**/\r
1098EFI_STATUS\r
1099EFIAPI\r
1100DiskIo2FlushDiskEx (\r
1101 IN EFI_DISK_IO2_PROTOCOL *This,\r
1102 IN OUT EFI_DISK_IO2_TOKEN *Token\r
1103 )\r
1104{\r
1105 EFI_STATUS Status;\r
1106 DISK_IO2_FLUSH_TASK *Task;\r
1107 DISK_IO_PRIVATE_DATA *Private;\r
1108\r
1109 Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);\r
1110\r
1111 if ((Token != NULL) && (Token->Event != NULL)) {\r
1112 Task = AllocatePool (sizeof (DISK_IO2_FLUSH_TASK));\r
1113 if (Task == NULL) {\r
1114 return EFI_OUT_OF_RESOURCES;\r
1115 }\r
1116\r
1117 Status = gBS->CreateEvent (\r
1118 EVT_NOTIFY_SIGNAL,\r
1119 TPL_CALLBACK,\r
1120 DiskIo2OnFlushComplete,\r
1121 Task,\r
1122 &Task->BlockIo2Token.Event\r
1123 );\r
1124 if (EFI_ERROR (Status)) {\r
1125 FreePool (Task);\r
1126 return Status;\r
1127 }\r
1128 Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE;\r
1129 Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);\r
1130 if (EFI_ERROR (Status)) {\r
1131 gBS->CloseEvent (Task->BlockIo2Token.Event);\r
1132 FreePool (Task);\r
1133 }\r
1134 } else {\r
1135 Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, NULL);\r
adbcbf8f 1136 }\r
1137\r
1138 return Status;\r
1139}\r
1140\r
493d8e3a
RN
1141/**\r
1142 Read BufferSize bytes from Offset into Buffer.\r
1143 Reads may support reads that are not aligned on\r
1144 sector boundaries. There are three cases:\r
1145 UnderRun - The first byte is not on a sector boundary or the read request is\r
1146 less than a sector in length.\r
1147 Aligned - A read of N contiguous sectors.\r
1148 OverRun - The last byte is not on a sector boundary.\r
1149\r
1150 @param This Protocol instance pointer.\r
1151 @param MediaId Id of the media, changes every time the media is replaced.\r
1152 @param Offset The starting byte offset to read from\r
1153 @param BufferSize Size of Buffer\r
1154 @param Buffer Buffer containing read data\r
1155\r
1156 @retval EFI_SUCCESS The data was read correctly from the device.\r
1157 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
1158 @retval EFI_NO_MEDIA There is no media in the device.\r
1159 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
1160 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not\r
1161 valid for the device.\r
1162\r
1163**/\r
1164EFI_STATUS\r
1165EFIAPI\r
1166DiskIoReadDisk (\r
1167 IN EFI_DISK_IO_PROTOCOL *This,\r
1168 IN UINT32 MediaId,\r
1169 IN UINT64 Offset,\r
1170 IN UINTN BufferSize,\r
1171 OUT VOID *Buffer\r
1172 )\r
1173{\r
1174 return DiskIo2ReadWriteDisk (\r
1175 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),\r
1176 FALSE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer\r
1177 );\r
1178}\r
1179\r
1180\r
1181/**\r
1182 Writes BufferSize bytes from Buffer into Offset.\r
1183 Writes may require a read modify write to support writes that are not\r
1184 aligned on sector boundaries. There are three cases:\r
1185 UnderRun - The first byte is not on a sector boundary or the write request\r
1186 is less than a sector in length. Read modify write is required.\r
1187 Aligned - A write of N contiguous sectors.\r
1188 OverRun - The last byte is not on a sector boundary. Read modified write\r
1189 required.\r
1190\r
1191 @param This Protocol instance pointer.\r
1192 @param MediaId Id of the media, changes every time the media is replaced.\r
1193 @param Offset The starting byte offset to read from\r
1194 @param BufferSize Size of Buffer\r
1195 @param Buffer Buffer containing read data\r
1196\r
1197 @retval EFI_SUCCESS The data was written correctly to the device.\r
1198 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
1199 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
1200 @retval EFI_NO_MEDIA There is no media in the device.\r
1201 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
1202 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not\r
1203 valid for the device.\r
1204\r
1205**/\r
1206EFI_STATUS\r
1207EFIAPI\r
1208DiskIoWriteDisk (\r
1209 IN EFI_DISK_IO_PROTOCOL *This,\r
1210 IN UINT32 MediaId,\r
1211 IN UINT64 Offset,\r
1212 IN UINTN BufferSize,\r
1213 IN VOID *Buffer\r
1214 )\r
1215{\r
1216 return DiskIo2ReadWriteDisk (\r
1217 DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),\r
1218 TRUE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer\r
1219 );\r
1220}\r
adbcbf8f 1221\r
1222/**\r
1223 The user Entry Point for module DiskIo. The user code starts with this function.\r
1224\r
1225 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
1226 @param[in] SystemTable A pointer to the EFI System Table.\r
1227 \r
1228 @retval EFI_SUCCESS The entry point is executed successfully.\r
1229 @retval other Some error occurs when executing this entry point.\r
1230\r
1231**/\r
1232EFI_STATUS\r
1233EFIAPI\r
1234InitializeDiskIo (\r
1235 IN EFI_HANDLE ImageHandle,\r
1236 IN EFI_SYSTEM_TABLE *SystemTable\r
1237 )\r
1238{\r
1239 EFI_STATUS Status;\r
1240\r
1241 //\r
1242 // Install driver model protocol(s).\r
1243 //\r
d38a0f44 1244 Status = EfiLibInstallDriverBindingComponentName2 (\r
adbcbf8f 1245 ImageHandle,\r
1246 SystemTable,\r
1247 &gDiskIoDriverBinding,\r
1248 ImageHandle,\r
1249 &gDiskIoComponentName,\r
d38a0f44 1250 &gDiskIoComponentName2\r
adbcbf8f 1251 );\r
1252 ASSERT_EFI_ERROR (Status);\r
1253\r
adbcbf8f 1254 return Status;\r
1255}\r