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