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