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