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