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