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