1 /** @file
2   SCSI disk driver that layers on every SCSI IO protocol in the system.
3 
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 
10 #include "ScsiDisk.h"
11 
12 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {
13   ScsiDiskDriverBindingSupported,
14   ScsiDiskDriverBindingStart,
15   ScsiDiskDriverBindingStop,
16   0xa,
17   NULL,
18   NULL
19 };
20 
21 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = {
22   EFI_DISK_INFO_SCSI_INTERFACE_GUID,
23   ScsiDiskInfoInquiry,
24   ScsiDiskInfoIdentify,
25   ScsiDiskInfoSenseData,
26   ScsiDiskInfoWhichIde
27 };
28 
29 /**
30   Allocates an aligned buffer for SCSI disk.
31 
32   This function allocates an aligned buffer for the SCSI disk to perform
33   SCSI IO operations. The alignment requirement is from SCSI IO interface.
34 
35   @param  ScsiDiskDevice    The SCSI disk involved for the operation.
36   @param  BufferSize        The request buffer size.
37 
38   @return A pointer to the aligned buffer or NULL if the allocation fails.
39 
40 **/
41 VOID *
42 AllocateAlignedBuffer (
43   IN SCSI_DISK_DEV            *ScsiDiskDevice,
44   IN UINTN                    BufferSize
45   )
46 {
47   return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiDiskDevice->ScsiIo->IoAlign);
48 }
49 
50 /**
51   Frees an aligned buffer for SCSI disk.
52 
53   This function frees an aligned buffer for the SCSI disk to perform
54   SCSI IO operations.
55 
56   @param  Buffer            The aligned buffer to be freed.
57   @param  BufferSize        The request buffer size.
58 
59 **/
60 VOID
61 FreeAlignedBuffer (
62   IN VOID                     *Buffer,
63   IN UINTN                    BufferSize
64   )
65 {
66   if (Buffer != NULL) {
67     FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
68   }
69 }
70 
71 /**
72   The user Entry Point for module ScsiDisk.
73 
74   The user code starts with this function.
75 
76   @param  ImageHandle    The firmware allocated handle for the EFI image.
77   @param  SystemTable    A pointer to the EFI System Table.
78 
79   @retval EFI_SUCCESS       The entry point is executed successfully.
80   @retval other             Some error occurs when executing this entry point.
81 
82 **/
83 EFI_STATUS
84 EFIAPI
85 InitializeScsiDisk(
86   IN EFI_HANDLE           ImageHandle,
87   IN EFI_SYSTEM_TABLE     *SystemTable
88   )
89 {
90   EFI_STATUS              Status;
91 
92   //
93   // Install driver model protocol(s).
94   //
95   Status = EfiLibInstallDriverBindingComponentName2 (
96              ImageHandle,
97              SystemTable,
98              &gScsiDiskDriverBinding,
99              ImageHandle,
100              &gScsiDiskComponentName,
101              &gScsiDiskComponentName2
102              );
103   ASSERT_EFI_ERROR (Status);
104 
105 
106   return Status;
107 }
108 
109 /**
110   Test to see if this driver supports ControllerHandle.
111 
112   This service is called by the EFI boot service ConnectController(). In order
113   to make drivers as small as possible, there are a few calling restrictions for
114   this service. ConnectController() must follow these calling restrictions.
115   If any other agent wishes to call Supported() it must also follow these
116   calling restrictions.
117 
118   @param  This                Protocol instance pointer.
119   @param  ControllerHandle    Handle of device to test
120   @param  RemainingDevicePath Optional parameter use to pick a specific child
121                               device to start.
122 
123   @retval EFI_SUCCESS         This driver supports this device
124   @retval EFI_ALREADY_STARTED This driver is already running on this device
125   @retval other               This driver does not support this device
126 
127 **/
128 EFI_STATUS
129 EFIAPI
130 ScsiDiskDriverBindingSupported (
131   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
132   IN EFI_HANDLE                   Controller,
133   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL
134   )
135 {
136   EFI_STATUS            Status;
137   EFI_SCSI_IO_PROTOCOL  *ScsiIo;
138   UINT8                 DeviceType;
139 
140   Status = gBS->OpenProtocol (
141                   Controller,
142                   &gEfiScsiIoProtocolGuid,
143                   (VOID **) &ScsiIo,
144                   This->DriverBindingHandle,
145                   Controller,
146                   EFI_OPEN_PROTOCOL_BY_DRIVER
147                   );
148   if (EFI_ERROR (Status)) {
149     return Status;
150   }
151 
152   Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);
153   if (!EFI_ERROR (Status)) {
154     if ((DeviceType == EFI_SCSI_TYPE_DISK) ||
155         (DeviceType == EFI_SCSI_TYPE_CDROM) ||
156         (DeviceType == EFI_SCSI_TYPE_WLUN)) {
157       Status = EFI_SUCCESS;
158     } else {
159       Status = EFI_UNSUPPORTED;
160     }
161   }
162 
163   gBS->CloseProtocol (
164          Controller,
165          &gEfiScsiIoProtocolGuid,
166          This->DriverBindingHandle,
167          Controller
168          );
169   return Status;
170 }
171 
172 
173 /**
174   Start this driver on ControllerHandle.
175 
176   This service is called by the EFI boot service ConnectController(). In order
177   to make drivers as small as possible, there are a few calling restrictions for
178   this service. ConnectController() must follow these calling restrictions. If
179   any other agent wishes to call Start() it must also follow these calling
180   restrictions.
181 
182   @param  This                 Protocol instance pointer.
183   @param  ControllerHandle     Handle of device to bind driver to
184   @param  RemainingDevicePath  Optional parameter use to pick a specific child
185                                device to start.
186 
187   @retval EFI_SUCCESS          This driver is added to ControllerHandle
188   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
189   @retval other                This driver does not support this device
190 
191 **/
192 EFI_STATUS
193 EFIAPI
194 ScsiDiskDriverBindingStart (
195   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
196   IN EFI_HANDLE                   Controller,
197   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL
198   )
199 {
200   EFI_STATUS            Status;
201   EFI_SCSI_IO_PROTOCOL  *ScsiIo;
202   SCSI_DISK_DEV         *ScsiDiskDevice;
203   BOOLEAN               Temp;
204   UINT8                 Index;
205   UINT8                 MaxRetry;
206   BOOLEAN               NeedRetry;
207   BOOLEAN               MustReadCapacity;
208 
209   MustReadCapacity = TRUE;
210 
211   ScsiDiskDevice = (SCSI_DISK_DEV *) AllocateZeroPool (sizeof (SCSI_DISK_DEV));
212   if (ScsiDiskDevice == NULL) {
213     return EFI_OUT_OF_RESOURCES;
214   }
215 
216   Status = gBS->OpenProtocol (
217                   Controller,
218                   &gEfiScsiIoProtocolGuid,
219                   (VOID **) &ScsiIo,
220                   This->DriverBindingHandle,
221                   Controller,
222                   EFI_OPEN_PROTOCOL_BY_DRIVER
223                   );
224   if (EFI_ERROR (Status)) {
225     FreePool (ScsiDiskDevice);
226     return Status;
227   }
228 
229   ScsiDiskDevice->Signature                         = SCSI_DISK_DEV_SIGNATURE;
230   ScsiDiskDevice->ScsiIo                            = ScsiIo;
231   ScsiDiskDevice->BlkIo.Revision                    = EFI_BLOCK_IO_PROTOCOL_REVISION3;
232   ScsiDiskDevice->BlkIo.Media                       = &ScsiDiskDevice->BlkIoMedia;
233   ScsiDiskDevice->BlkIo.Media->IoAlign              = ScsiIo->IoAlign;
234   ScsiDiskDevice->BlkIo.Reset                       = ScsiDiskReset;
235   ScsiDiskDevice->BlkIo.ReadBlocks                  = ScsiDiskReadBlocks;
236   ScsiDiskDevice->BlkIo.WriteBlocks                 = ScsiDiskWriteBlocks;
237   ScsiDiskDevice->BlkIo.FlushBlocks                 = ScsiDiskFlushBlocks;
238   ScsiDiskDevice->BlkIo2.Media                      = &ScsiDiskDevice->BlkIoMedia;
239   ScsiDiskDevice->BlkIo2.Reset                      = ScsiDiskResetEx;
240   ScsiDiskDevice->BlkIo2.ReadBlocksEx               = ScsiDiskReadBlocksEx;
241   ScsiDiskDevice->BlkIo2.WriteBlocksEx              = ScsiDiskWriteBlocksEx;
242   ScsiDiskDevice->BlkIo2.FlushBlocksEx              = ScsiDiskFlushBlocksEx;
243   ScsiDiskDevice->StorageSecurity.ReceiveData       = ScsiDiskReceiveData;
244   ScsiDiskDevice->StorageSecurity.SendData          = ScsiDiskSendData;
245   ScsiDiskDevice->EraseBlock.Revision               = EFI_ERASE_BLOCK_PROTOCOL_REVISION;
246   ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
247   ScsiDiskDevice->EraseBlock.EraseBlocks            = ScsiDiskEraseBlocks;
248   ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt           = 1;
249   ScsiDiskDevice->BlockLimitsVpdSupported           = FALSE;
250   ScsiDiskDevice->Handle                            = Controller;
251   InitializeListHead (&ScsiDiskDevice->AsyncTaskQueue);
252 
253   ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));
254   switch (ScsiDiskDevice->DeviceType) {
255   case EFI_SCSI_TYPE_DISK:
256     ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
257     MustReadCapacity = TRUE;
258     break;
259 
260   case EFI_SCSI_TYPE_CDROM:
261     ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
262     ScsiDiskDevice->BlkIo.Media->ReadOnly  = TRUE;
263     MustReadCapacity = FALSE;
264     break;
265 
266   case EFI_SCSI_TYPE_WLUN:
267     MustReadCapacity = FALSE;
268     break;
269   }
270   //
271   // The Sense Data Array's initial size is 6
272   //
273   ScsiDiskDevice->SenseDataNumber = 6;
274   ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *) AllocateZeroPool (
275                                  sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber
276                                  );
277   if (ScsiDiskDevice->SenseData == NULL) {
278     gBS->CloseProtocol (
279           Controller,
280           &gEfiScsiIoProtocolGuid,
281           This->DriverBindingHandle,
282           Controller
283           );
284     FreePool (ScsiDiskDevice);
285     return EFI_OUT_OF_RESOURCES;
286   }
287 
288   //
289   // Retrieve device information
290   //
291   MaxRetry = 2;
292   for (Index = 0; Index < MaxRetry; Index++) {
293     Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);
294     if (!EFI_ERROR (Status)) {
295       break;
296     }
297 
298     if (!NeedRetry) {
299       FreePool (ScsiDiskDevice->SenseData);
300       gBS->CloseProtocol (
301              Controller,
302              &gEfiScsiIoProtocolGuid,
303              This->DriverBindingHandle,
304              Controller
305              );
306       FreePool (ScsiDiskDevice);
307       return EFI_DEVICE_ERROR;
308     }
309   }
310   //
311   // The second parameter "TRUE" means must
312   // retrieve media capacity
313   //
314   Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);
315   if (!EFI_ERROR (Status)) {
316     //
317     // Determine if Block IO & Block IO2 should be produced on this controller
318     // handle
319     //
320     if (DetermineInstallBlockIo (Controller)) {
321       InitializeInstallDiskInfo (ScsiDiskDevice, Controller);
322       Status = gBS->InstallMultipleProtocolInterfaces (
323                       &Controller,
324                       &gEfiBlockIoProtocolGuid,
325                       &ScsiDiskDevice->BlkIo,
326                       &gEfiBlockIo2ProtocolGuid,
327                       &ScsiDiskDevice->BlkIo2,
328                       &gEfiDiskInfoProtocolGuid,
329                       &ScsiDiskDevice->DiskInfo,
330                       NULL
331                       );
332       if (!EFI_ERROR (Status)) {
333         if (DetermineInstallEraseBlock (ScsiDiskDevice, Controller)) {
334           Status = gBS->InstallProtocolInterface (
335                           &Controller,
336                           &gEfiEraseBlockProtocolGuid,
337                           EFI_NATIVE_INTERFACE,
338                           &ScsiDiskDevice->EraseBlock
339                           );
340           if (EFI_ERROR (Status)) {
341             DEBUG ((DEBUG_ERROR, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", Status));
342           }
343         }
344         if (DetermineInstallStorageSecurity (ScsiDiskDevice, Controller)) {
345           Status = gBS->InstallProtocolInterface (
346                           &Controller,
347                           &gEfiStorageSecurityCommandProtocolGuid,
348                           EFI_NATIVE_INTERFACE,
349                           &ScsiDiskDevice->StorageSecurity
350                           );
351           if (EFI_ERROR (Status)) {
352             DEBUG ((DEBUG_ERROR, "ScsiDisk: Failed to install the Storage Security Command Protocol! Status = %r\n", Status));
353           }
354         }
355         ScsiDiskDevice->ControllerNameTable = NULL;
356         AddUnicodeString2 (
357           "eng",
358           gScsiDiskComponentName.SupportedLanguages,
359           &ScsiDiskDevice->ControllerNameTable,
360           L"SCSI Disk Device",
361           TRUE
362           );
363         AddUnicodeString2 (
364           "en",
365           gScsiDiskComponentName2.SupportedLanguages,
366           &ScsiDiskDevice->ControllerNameTable,
367           L"SCSI Disk Device",
368           FALSE
369           );
370         return EFI_SUCCESS;
371       }
372     }
373   }
374 
375   gBS->FreePool (ScsiDiskDevice->SenseData);
376   gBS->FreePool (ScsiDiskDevice);
377   gBS->CloseProtocol (
378          Controller,
379          &gEfiScsiIoProtocolGuid,
380          This->DriverBindingHandle,
381          Controller
382          );
383   return Status;
384 
385 }
386 
387 
388 /**
389   Stop this driver on ControllerHandle.
390 
391   This service is called by the EFI boot service DisconnectController().
392   In order to make drivers as small as possible, there are a few calling
393   restrictions for this service. DisconnectController() must follow these
394   calling restrictions. If any other agent wishes to call Stop() it must
395   also follow these calling restrictions.
396 
397   @param  This              Protocol instance pointer.
398   @param  ControllerHandle  Handle of device to stop driver on
399   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
400                             children is zero stop the entire bus driver.
401   @param  ChildHandleBuffer List of Child Handles to Stop.
402 
403   @retval EFI_SUCCESS       This driver is removed ControllerHandle
404   @retval other             This driver was not removed from this device
405 
406 **/
407 EFI_STATUS
408 EFIAPI
409 ScsiDiskDriverBindingStop (
410   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
411   IN  EFI_HANDLE                      Controller,
412   IN  UINTN                           NumberOfChildren,
413   IN  EFI_HANDLE                      *ChildHandleBuffer   OPTIONAL
414   )
415 {
416   EFI_BLOCK_IO_PROTOCOL      *BlkIo;
417   EFI_ERASE_BLOCK_PROTOCOL   *EraseBlock;
418   SCSI_DISK_DEV              *ScsiDiskDevice;
419   EFI_STATUS                 Status;
420 
421   Status = gBS->OpenProtocol (
422                   Controller,
423                   &gEfiBlockIoProtocolGuid,
424                   (VOID **) &BlkIo,
425                   This->DriverBindingHandle,
426                   Controller,
427                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
428                   );
429   if (EFI_ERROR (Status)) {
430     return Status;
431   }
432 
433   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlkIo);
434 
435   //
436   // Wait for the BlockIo2 requests queue to become empty
437   //
438   while (!IsListEmpty (&ScsiDiskDevice->AsyncTaskQueue));
439 
440   //
441   // If Erase Block Protocol is installed, then uninstall this protocol.
442   //
443   Status = gBS->OpenProtocol (
444                   Controller,
445                   &gEfiEraseBlockProtocolGuid,
446                   (VOID **) &EraseBlock,
447                   This->DriverBindingHandle,
448                   Controller,
449                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
450                   );
451 
452   if (!EFI_ERROR (Status)) {
453     Status = gBS->UninstallProtocolInterface (
454                     Controller,
455                     &gEfiEraseBlockProtocolGuid,
456                     &ScsiDiskDevice->EraseBlock
457                     );
458     if (EFI_ERROR (Status)) {
459       return Status;
460     }
461   }
462 
463   Status = gBS->UninstallMultipleProtocolInterfaces (
464                   Controller,
465                   &gEfiBlockIoProtocolGuid,
466                   &ScsiDiskDevice->BlkIo,
467                   &gEfiBlockIo2ProtocolGuid,
468                   &ScsiDiskDevice->BlkIo2,
469                   &gEfiDiskInfoProtocolGuid,
470                   &ScsiDiskDevice->DiskInfo,
471                   NULL
472                   );
473   if (!EFI_ERROR (Status)) {
474     gBS->CloseProtocol (
475            Controller,
476            &gEfiScsiIoProtocolGuid,
477            This->DriverBindingHandle,
478            Controller
479            );
480 
481     ReleaseScsiDiskDeviceResources (ScsiDiskDevice);
482 
483     return EFI_SUCCESS;
484   }
485   //
486   // errors met
487   //
488   return Status;
489 }
490 
491 /**
492   Reset SCSI Disk.
493 
494 
495   @param  This                 The pointer of EFI_BLOCK_IO_PROTOCOL
496   @param  ExtendedVerification The flag about if extend verificate
497 
498   @retval EFI_SUCCESS          The device was reset.
499   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
500                                not be reset.
501   @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
502 
503 **/
504 EFI_STATUS
505 EFIAPI
506 ScsiDiskReset (
507   IN  EFI_BLOCK_IO_PROTOCOL   *This,
508   IN  BOOLEAN                 ExtendedVerification
509   )
510 {
511   EFI_TPL       OldTpl;
512   SCSI_DISK_DEV *ScsiDiskDevice;
513   EFI_STATUS    Status;
514 
515   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
516 
517   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_BLKIO (This);
518 
519   Status          = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
520 
521   if (EFI_ERROR (Status)) {
522     if (Status == EFI_UNSUPPORTED) {
523       Status = EFI_SUCCESS;
524     } else {
525       Status = EFI_DEVICE_ERROR;
526       goto Done;
527     }
528   }
529 
530   if (!ExtendedVerification) {
531     goto Done;
532   }
533 
534   Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
535 
536   if (EFI_ERROR (Status)) {
537     Status = EFI_DEVICE_ERROR;
538     goto Done;
539   }
540 
541 Done:
542   gBS->RestoreTPL (OldTpl);
543   return Status;
544 }
545 
546 /**
547   The function is to Read Block from SCSI Disk.
548 
549   @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL.
550   @param  MediaId    The Id of Media detected
551   @param  Lba        The logic block address
552   @param  BufferSize The size of Buffer
553   @param  Buffer     The buffer to fill the read out data
554 
555   @retval EFI_SUCCESS           Successfully to read out block.
556   @retval EFI_DEVICE_ERROR      Fail to detect media.
557   @retval EFI_NO_MEDIA          Media is not present.
558   @retval EFI_MEDIA_CHANGED     Media has changed.
559   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
560   @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
561 
562 **/
563 EFI_STATUS
564 EFIAPI
565 ScsiDiskReadBlocks (
566   IN  EFI_BLOCK_IO_PROTOCOL   *This,
567   IN  UINT32                  MediaId,
568   IN  EFI_LBA                 Lba,
569   IN  UINTN                   BufferSize,
570   OUT VOID                    *Buffer
571   )
572 {
573   SCSI_DISK_DEV       *ScsiDiskDevice;
574   EFI_BLOCK_IO_MEDIA  *Media;
575   EFI_STATUS          Status;
576   UINTN               BlockSize;
577   UINTN               NumberOfBlocks;
578   BOOLEAN             MediaChange;
579   EFI_TPL             OldTpl;
580 
581   MediaChange    = FALSE;
582   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
583   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
584   Media          = ScsiDiskDevice->BlkIo.Media;
585 
586   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
587 
588     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
589     if (EFI_ERROR (Status)) {
590       Status = EFI_DEVICE_ERROR;
591       goto Done;
592     }
593 
594     if (MediaChange) {
595       gBS->ReinstallProtocolInterface (
596             ScsiDiskDevice->Handle,
597             &gEfiBlockIoProtocolGuid,
598             &ScsiDiskDevice->BlkIo,
599             &ScsiDiskDevice->BlkIo
600             );
601       gBS->ReinstallProtocolInterface (
602              ScsiDiskDevice->Handle,
603              &gEfiBlockIo2ProtocolGuid,
604              &ScsiDiskDevice->BlkIo2,
605              &ScsiDiskDevice->BlkIo2
606              );
607       if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
608         gBS->ReinstallProtocolInterface (
609                ScsiDiskDevice->Handle,
610                &gEfiEraseBlockProtocolGuid,
611                &ScsiDiskDevice->EraseBlock,
612                &ScsiDiskDevice->EraseBlock
613                );
614       }
615       if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
616         gBS->ReinstallProtocolInterface (
617                 ScsiDiskDevice->Handle,
618                 &gEfiStorageSecurityCommandProtocolGuid,
619                 &ScsiDiskDevice->StorageSecurity,
620                 &ScsiDiskDevice->StorageSecurity
621                 );
622       }
623       if (Media->MediaPresent) {
624         Status = EFI_MEDIA_CHANGED;
625       } else {
626         Status = EFI_NO_MEDIA;
627       }
628       goto Done;
629     }
630   }
631   //
632   // Get the intrinsic block size
633   //
634   BlockSize       = Media->BlockSize;
635 
636   if (BlockSize == 0) {
637     Status = EFI_DEVICE_ERROR;
638     goto Done;
639   }
640 
641   NumberOfBlocks  = BufferSize / BlockSize;
642 
643   if (!(Media->MediaPresent)) {
644     Status = EFI_NO_MEDIA;
645     goto Done;
646   }
647 
648   if (MediaId != Media->MediaId) {
649     Status = EFI_MEDIA_CHANGED;
650     goto Done;
651   }
652 
653   if (Buffer == NULL) {
654     Status = EFI_INVALID_PARAMETER;
655     goto Done;
656   }
657 
658   if (BufferSize == 0) {
659     Status = EFI_SUCCESS;
660     goto Done;
661   }
662 
663   if (BufferSize % BlockSize != 0) {
664     Status = EFI_BAD_BUFFER_SIZE;
665     goto Done;
666   }
667 
668   if (Lba > Media->LastBlock) {
669     Status = EFI_INVALID_PARAMETER;
670     goto Done;
671   }
672 
673   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
674     Status = EFI_INVALID_PARAMETER;
675     goto Done;
676   }
677 
678   if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
679     Status = EFI_INVALID_PARAMETER;
680     goto Done;
681   }
682 
683   //
684   // If all the parameters are valid, then perform read sectors command
685   // to transfer data from device to host.
686   //
687   Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
688 
689 Done:
690   gBS->RestoreTPL (OldTpl);
691   return Status;
692 }
693 
694 /**
695   The function is to Write Block to SCSI Disk.
696 
697   @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL
698   @param  MediaId    The Id of Media detected
699   @param  Lba        The logic block address
700   @param  BufferSize The size of Buffer
701   @param  Buffer     The buffer to fill the read out data
702 
703   @retval EFI_SUCCESS           Successfully to read out block.
704   @retval EFI_WRITE_PROTECTED   The device can not be written to.
705   @retval EFI_DEVICE_ERROR      Fail to detect media.
706   @retval EFI_NO_MEDIA          Media is not present.
707   @retval EFI_MEDIA_CHANGED     Media has changed.
708   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
709   @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
710 
711 **/
712 EFI_STATUS
713 EFIAPI
714 ScsiDiskWriteBlocks (
715   IN  EFI_BLOCK_IO_PROTOCOL   *This,
716   IN  UINT32                  MediaId,
717   IN  EFI_LBA                 Lba,
718   IN  UINTN                   BufferSize,
719   IN  VOID                    *Buffer
720   )
721 {
722   SCSI_DISK_DEV       *ScsiDiskDevice;
723   EFI_BLOCK_IO_MEDIA  *Media;
724   EFI_STATUS          Status;
725   UINTN               BlockSize;
726   UINTN               NumberOfBlocks;
727   BOOLEAN             MediaChange;
728   EFI_TPL             OldTpl;
729 
730   MediaChange    = FALSE;
731   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
732   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
733   Media          = ScsiDiskDevice->BlkIo.Media;
734 
735   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
736 
737     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
738     if (EFI_ERROR (Status)) {
739       Status = EFI_DEVICE_ERROR;
740       goto Done;
741     }
742 
743     if (MediaChange) {
744       gBS->ReinstallProtocolInterface (
745             ScsiDiskDevice->Handle,
746             &gEfiBlockIoProtocolGuid,
747             &ScsiDiskDevice->BlkIo,
748             &ScsiDiskDevice->BlkIo
749             );
750       gBS->ReinstallProtocolInterface (
751              ScsiDiskDevice->Handle,
752              &gEfiBlockIo2ProtocolGuid,
753              &ScsiDiskDevice->BlkIo2,
754              &ScsiDiskDevice->BlkIo2
755              );
756       if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
757         gBS->ReinstallProtocolInterface (
758                ScsiDiskDevice->Handle,
759                &gEfiEraseBlockProtocolGuid,
760                &ScsiDiskDevice->EraseBlock,
761                &ScsiDiskDevice->EraseBlock
762                );
763       }
764       if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
765         gBS->ReinstallProtocolInterface (
766                 ScsiDiskDevice->Handle,
767                 &gEfiStorageSecurityCommandProtocolGuid,
768                 &ScsiDiskDevice->StorageSecurity,
769                 &ScsiDiskDevice->StorageSecurity
770                 );
771       }
772       if (Media->MediaPresent) {
773         Status = EFI_MEDIA_CHANGED;
774       } else {
775         Status = EFI_NO_MEDIA;
776       }
777       goto Done;
778     }
779   }
780   //
781   // Get the intrinsic block size
782   //
783   BlockSize       = Media->BlockSize;
784 
785   if (BlockSize == 0) {
786     Status = EFI_DEVICE_ERROR;
787     goto Done;
788   }
789 
790   NumberOfBlocks  = BufferSize / BlockSize;
791 
792   if (!(Media->MediaPresent)) {
793     Status = EFI_NO_MEDIA;
794     goto Done;
795   }
796 
797   if (MediaId != Media->MediaId) {
798     Status = EFI_MEDIA_CHANGED;
799     goto Done;
800   }
801 
802   if (Media->ReadOnly) {
803     Status = EFI_WRITE_PROTECTED;
804     goto Done;
805   }
806 
807   if (BufferSize == 0) {
808     Status = EFI_SUCCESS;
809     goto Done;
810   }
811 
812   if (Buffer == NULL) {
813     Status = EFI_INVALID_PARAMETER;
814     goto Done;
815   }
816 
817   if (BufferSize % BlockSize != 0) {
818     Status = EFI_BAD_BUFFER_SIZE;
819     goto Done;
820   }
821 
822   if (Lba > Media->LastBlock) {
823     Status = EFI_INVALID_PARAMETER;
824     goto Done;
825   }
826 
827   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
828     Status = EFI_INVALID_PARAMETER;
829     goto Done;
830   }
831 
832   if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
833     Status = EFI_INVALID_PARAMETER;
834     goto Done;
835   }
836   //
837   // if all the parameters are valid, then perform read sectors command
838   // to transfer data from device to host.
839   //
840   Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
841 
842 Done:
843   gBS->RestoreTPL (OldTpl);
844   return Status;
845 }
846 
847 /**
848   Flush Block to Disk.
849 
850   EFI_SUCCESS is returned directly.
851 
852   @param  This              The pointer of EFI_BLOCK_IO_PROTOCOL
853 
854   @retval EFI_SUCCESS       All outstanding data was written to the device
855 
856 **/
857 EFI_STATUS
858 EFIAPI
859 ScsiDiskFlushBlocks (
860   IN  EFI_BLOCK_IO_PROTOCOL   *This
861   )
862 {
863   //
864   // return directly
865   //
866   return EFI_SUCCESS;
867 }
868 
869 
870 /**
871   Reset SCSI Disk.
872 
873   @param  This                 The pointer of EFI_BLOCK_IO2_PROTOCOL.
874   @param  ExtendedVerification The flag about if extend verificate.
875 
876   @retval EFI_SUCCESS          The device was reset.
877   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
878                                not be reset.
879   @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
880 
881 **/
882 EFI_STATUS
883 EFIAPI
884 ScsiDiskResetEx (
885   IN  EFI_BLOCK_IO2_PROTOCOL  *This,
886   IN  BOOLEAN                 ExtendedVerification
887   )
888 {
889   EFI_TPL       OldTpl;
890   SCSI_DISK_DEV *ScsiDiskDevice;
891   EFI_STATUS    Status;
892 
893   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
894 
895   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_BLKIO2 (This);
896 
897   Status          = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
898 
899   if (EFI_ERROR (Status)) {
900     if (Status == EFI_UNSUPPORTED) {
901       Status = EFI_SUCCESS;
902     } else {
903       Status = EFI_DEVICE_ERROR;
904       goto Done;
905     }
906   }
907 
908   if (!ExtendedVerification) {
909     goto Done;
910   }
911 
912   Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
913 
914   if (EFI_ERROR (Status)) {
915     Status = EFI_DEVICE_ERROR;
916     goto Done;
917   }
918 
919 Done:
920   gBS->RestoreTPL (OldTpl);
921   return Status;
922 }
923 
924 /**
925   The function is to Read Block from SCSI Disk.
926 
927   @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL.
928   @param  MediaId    The Id of Media detected.
929   @param  Lba        The logic block address.
930   @param  Token      A pointer to the token associated with the transaction.
931   @param  BufferSize The size of Buffer.
932   @param  Buffer     The buffer to fill the read out data.
933 
934   @retval EFI_SUCCESS           The read request was queued if Token-> Event is
935                                 not NULL. The data was read correctly from the
936                                 device if theToken-> Event is NULL.
937   @retval EFI_DEVICE_ERROR      The device reported an error while attempting
938                                 to perform the read operation.
939   @retval EFI_NO_MEDIA          There is no media in the device.
940   @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
941   @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of
942                                 the intrinsic block size of the device.
943   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
944                                 valid, or the buffer is not on proper
945                                 alignment.
946   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
947                                 lack of resources.
948 
949 **/
950 EFI_STATUS
951 EFIAPI
952 ScsiDiskReadBlocksEx (
953   IN     EFI_BLOCK_IO2_PROTOCOL   *This,
954   IN     UINT32                   MediaId,
955   IN     EFI_LBA                  Lba,
956   IN OUT EFI_BLOCK_IO2_TOKEN      *Token,
957   IN     UINTN                    BufferSize,
958   OUT    VOID                     *Buffer
959   )
960 {
961   SCSI_DISK_DEV       *ScsiDiskDevice;
962   EFI_BLOCK_IO_MEDIA  *Media;
963   EFI_STATUS          Status;
964   UINTN               BlockSize;
965   UINTN               NumberOfBlocks;
966   BOOLEAN             MediaChange;
967   EFI_TPL             OldTpl;
968 
969   MediaChange    = FALSE;
970   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
971   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
972   Media          = ScsiDiskDevice->BlkIo.Media;
973 
974   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
975 
976     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
977     if (EFI_ERROR (Status)) {
978       Status = EFI_DEVICE_ERROR;
979       goto Done;
980     }
981 
982     if (MediaChange) {
983       gBS->ReinstallProtocolInterface (
984             ScsiDiskDevice->Handle,
985             &gEfiBlockIoProtocolGuid,
986             &ScsiDiskDevice->BlkIo,
987             &ScsiDiskDevice->BlkIo
988             );
989       gBS->ReinstallProtocolInterface (
990              ScsiDiskDevice->Handle,
991              &gEfiBlockIo2ProtocolGuid,
992              &ScsiDiskDevice->BlkIo2,
993              &ScsiDiskDevice->BlkIo2
994              );
995       if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
996         gBS->ReinstallProtocolInterface (
997                ScsiDiskDevice->Handle,
998                &gEfiEraseBlockProtocolGuid,
999                &ScsiDiskDevice->EraseBlock,
1000                &ScsiDiskDevice->EraseBlock
1001                );
1002       }
1003       if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1004         gBS->ReinstallProtocolInterface (
1005                 ScsiDiskDevice->Handle,
1006                 &gEfiStorageSecurityCommandProtocolGuid,
1007                 &ScsiDiskDevice->StorageSecurity,
1008                 &ScsiDiskDevice->StorageSecurity
1009                 );
1010       }
1011       if (Media->MediaPresent) {
1012         Status = EFI_MEDIA_CHANGED;
1013       } else {
1014         Status = EFI_NO_MEDIA;
1015       }
1016       goto Done;
1017     }
1018   }
1019   //
1020   // Get the intrinsic block size
1021   //
1022   BlockSize       = Media->BlockSize;
1023 
1024   if (BlockSize == 0) {
1025     Status = EFI_DEVICE_ERROR;
1026     goto Done;
1027   }
1028 
1029   NumberOfBlocks  = BufferSize / BlockSize;
1030 
1031   if (!(Media->MediaPresent)) {
1032     Status = EFI_NO_MEDIA;
1033     goto Done;
1034   }
1035 
1036   if (MediaId != Media->MediaId) {
1037     Status = EFI_MEDIA_CHANGED;
1038     goto Done;
1039   }
1040 
1041   if (Buffer == NULL) {
1042     Status = EFI_INVALID_PARAMETER;
1043     goto Done;
1044   }
1045 
1046   if (BufferSize == 0) {
1047     if ((Token != NULL) && (Token->Event != NULL)) {
1048       Token->TransactionStatus = EFI_SUCCESS;
1049       gBS->SignalEvent (Token->Event);
1050     }
1051 
1052     Status = EFI_SUCCESS;
1053     goto Done;
1054   }
1055 
1056   if (BufferSize % BlockSize != 0) {
1057     Status = EFI_BAD_BUFFER_SIZE;
1058     goto Done;
1059   }
1060 
1061   if (Lba > Media->LastBlock) {
1062     Status = EFI_INVALID_PARAMETER;
1063     goto Done;
1064   }
1065 
1066   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1067     Status = EFI_INVALID_PARAMETER;
1068     goto Done;
1069   }
1070 
1071   if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
1072     Status = EFI_INVALID_PARAMETER;
1073     goto Done;
1074   }
1075 
1076   //
1077   // If all the parameters are valid, then perform read sectors command
1078   // to transfer data from device to host.
1079   //
1080   if ((Token != NULL) && (Token->Event != NULL)) {
1081     Token->TransactionStatus = EFI_SUCCESS;
1082     Status = ScsiDiskAsyncReadSectors (
1083                ScsiDiskDevice,
1084                Buffer,
1085                Lba,
1086                NumberOfBlocks,
1087                Token
1088                );
1089   } else {
1090     Status = ScsiDiskReadSectors (
1091                ScsiDiskDevice,
1092                Buffer,
1093                Lba,
1094                NumberOfBlocks
1095                );
1096   }
1097 
1098 Done:
1099   gBS->RestoreTPL (OldTpl);
1100   return Status;
1101 }
1102 
1103 /**
1104   The function is to Write Block to SCSI Disk.
1105 
1106   @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL.
1107   @param  MediaId    The Id of Media detected.
1108   @param  Lba        The logic block address.
1109   @param  Token      A pointer to the token associated with the transaction.
1110   @param  BufferSize The size of Buffer.
1111   @param  Buffer     The buffer to fill the read out data.
1112 
1113   @retval EFI_SUCCESS           The data were written correctly to the device.
1114   @retval EFI_WRITE_PROTECTED   The device cannot be written to.
1115   @retval EFI_NO_MEDIA          There is no media in the device.
1116   @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
1117   @retval EFI_DEVICE_ERROR      The device reported an error while attempting
1118                                 to perform the write operation.
1119   @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of
1120                                 the intrinsic block size of the device.
1121   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
1122                                 valid, or the buffer is not on proper
1123                                 alignment.
1124 
1125 **/
1126 EFI_STATUS
1127 EFIAPI
1128 ScsiDiskWriteBlocksEx (
1129   IN     EFI_BLOCK_IO2_PROTOCOL *This,
1130   IN     UINT32                 MediaId,
1131   IN     EFI_LBA                Lba,
1132   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
1133   IN     UINTN                  BufferSize,
1134   IN     VOID                   *Buffer
1135   )
1136 {
1137   SCSI_DISK_DEV       *ScsiDiskDevice;
1138   EFI_BLOCK_IO_MEDIA  *Media;
1139   EFI_STATUS          Status;
1140   UINTN               BlockSize;
1141   UINTN               NumberOfBlocks;
1142   BOOLEAN             MediaChange;
1143   EFI_TPL             OldTpl;
1144 
1145   MediaChange    = FALSE;
1146   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
1147   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
1148   Media          = ScsiDiskDevice->BlkIo.Media;
1149 
1150   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
1151 
1152     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1153     if (EFI_ERROR (Status)) {
1154       Status = EFI_DEVICE_ERROR;
1155       goto Done;
1156     }
1157 
1158     if (MediaChange) {
1159       gBS->ReinstallProtocolInterface (
1160             ScsiDiskDevice->Handle,
1161             &gEfiBlockIoProtocolGuid,
1162             &ScsiDiskDevice->BlkIo,
1163             &ScsiDiskDevice->BlkIo
1164             );
1165       gBS->ReinstallProtocolInterface (
1166              ScsiDiskDevice->Handle,
1167              &gEfiBlockIo2ProtocolGuid,
1168              &ScsiDiskDevice->BlkIo2,
1169              &ScsiDiskDevice->BlkIo2
1170              );
1171       if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1172         gBS->ReinstallProtocolInterface (
1173                ScsiDiskDevice->Handle,
1174                &gEfiEraseBlockProtocolGuid,
1175                &ScsiDiskDevice->EraseBlock,
1176                &ScsiDiskDevice->EraseBlock
1177                );
1178       }
1179       if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1180         gBS->ReinstallProtocolInterface (
1181                 ScsiDiskDevice->Handle,
1182                 &gEfiStorageSecurityCommandProtocolGuid,
1183                 &ScsiDiskDevice->StorageSecurity,
1184                 &ScsiDiskDevice->StorageSecurity
1185                 );
1186       }
1187       if (Media->MediaPresent) {
1188         Status = EFI_MEDIA_CHANGED;
1189       } else {
1190         Status = EFI_NO_MEDIA;
1191       }
1192       goto Done;
1193     }
1194   }
1195   //
1196   // Get the intrinsic block size
1197   //
1198   BlockSize       = Media->BlockSize;
1199 
1200   if (BlockSize == 0) {
1201     Status = EFI_DEVICE_ERROR;
1202     goto Done;
1203   }
1204 
1205   NumberOfBlocks  = BufferSize / BlockSize;
1206 
1207   if (!(Media->MediaPresent)) {
1208     Status = EFI_NO_MEDIA;
1209     goto Done;
1210   }
1211 
1212   if (MediaId != Media->MediaId) {
1213     Status = EFI_MEDIA_CHANGED;
1214     goto Done;
1215   }
1216 
1217   if (Media->ReadOnly) {
1218     Status = EFI_WRITE_PROTECTED;
1219     goto Done;
1220   }
1221 
1222   if (BufferSize == 0) {
1223     if ((Token != NULL) && (Token->Event != NULL)) {
1224       Token->TransactionStatus = EFI_SUCCESS;
1225       gBS->SignalEvent (Token->Event);
1226     }
1227 
1228     Status = EFI_SUCCESS;
1229     goto Done;
1230   }
1231 
1232   if (Buffer == NULL) {
1233     Status = EFI_INVALID_PARAMETER;
1234     goto Done;
1235   }
1236 
1237   if (BufferSize % BlockSize != 0) {
1238     Status = EFI_BAD_BUFFER_SIZE;
1239     goto Done;
1240   }
1241 
1242   if (Lba > Media->LastBlock) {
1243     Status = EFI_INVALID_PARAMETER;
1244     goto Done;
1245   }
1246 
1247   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1248     Status = EFI_INVALID_PARAMETER;
1249     goto Done;
1250   }
1251 
1252   if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
1253     Status = EFI_INVALID_PARAMETER;
1254     goto Done;
1255   }
1256 
1257   //
1258   // if all the parameters are valid, then perform write sectors command
1259   // to transfer data from device to host.
1260   //
1261   if ((Token != NULL) && (Token->Event != NULL)) {
1262     Token->TransactionStatus = EFI_SUCCESS;
1263     Status = ScsiDiskAsyncWriteSectors (
1264                ScsiDiskDevice,
1265                Buffer,
1266                Lba,
1267                NumberOfBlocks,
1268                Token
1269                );
1270   } else {
1271     Status = ScsiDiskWriteSectors (
1272                ScsiDiskDevice,
1273                Buffer,
1274                Lba,
1275                NumberOfBlocks
1276                );
1277   }
1278 
1279 Done:
1280   gBS->RestoreTPL (OldTpl);
1281   return Status;
1282 }
1283 
1284 /**
1285   Flush the Block Device.
1286 
1287   @param  This       Indicates a pointer to the calling context.
1288   @param  Token      A pointer to the token associated with the transaction.
1289 
1290   @retval EFI_SUCCESS         All outstanding data was written to the device.
1291   @retval EFI_DEVICE_ERROR    The device reported an error while attempting to
1292                               write data.
1293   @retval EFI_WRITE_PROTECTED The device cannot be written to.
1294   @retval EFI_NO_MEDIA        There is no media in the device.
1295   @retval EFI_MEDIA_CHANGED   The MediaId is not for the current media.
1296 
1297 **/
1298 EFI_STATUS
1299 EFIAPI
1300 ScsiDiskFlushBlocksEx (
1301   IN     EFI_BLOCK_IO2_PROTOCOL  *This,
1302   IN OUT EFI_BLOCK_IO2_TOKEN     *Token
1303   )
1304 {
1305   SCSI_DISK_DEV       *ScsiDiskDevice;
1306   EFI_BLOCK_IO_MEDIA  *Media;
1307   EFI_STATUS          Status;
1308   BOOLEAN             MediaChange;
1309   EFI_TPL             OldTpl;
1310 
1311   MediaChange    = FALSE;
1312   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
1313   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
1314   Media          = ScsiDiskDevice->BlkIo.Media;
1315 
1316   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
1317 
1318     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1319     if (EFI_ERROR (Status)) {
1320       Status = EFI_DEVICE_ERROR;
1321       goto Done;
1322     }
1323 
1324     if (MediaChange) {
1325       gBS->ReinstallProtocolInterface (
1326             ScsiDiskDevice->Handle,
1327             &gEfiBlockIoProtocolGuid,
1328             &ScsiDiskDevice->BlkIo,
1329             &ScsiDiskDevice->BlkIo
1330             );
1331       gBS->ReinstallProtocolInterface (
1332              ScsiDiskDevice->Handle,
1333              &gEfiBlockIo2ProtocolGuid,
1334              &ScsiDiskDevice->BlkIo2,
1335              &ScsiDiskDevice->BlkIo2
1336              );
1337       if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1338         gBS->ReinstallProtocolInterface (
1339                ScsiDiskDevice->Handle,
1340                &gEfiEraseBlockProtocolGuid,
1341                &ScsiDiskDevice->EraseBlock,
1342                &ScsiDiskDevice->EraseBlock
1343                );
1344       }
1345       if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1346         gBS->ReinstallProtocolInterface (
1347                 ScsiDiskDevice->Handle,
1348                 &gEfiStorageSecurityCommandProtocolGuid,
1349                 &ScsiDiskDevice->StorageSecurity,
1350                 &ScsiDiskDevice->StorageSecurity
1351                 );
1352       }
1353       if (Media->MediaPresent) {
1354         Status = EFI_MEDIA_CHANGED;
1355       } else {
1356         Status = EFI_NO_MEDIA;
1357       }
1358       goto Done;
1359     }
1360   }
1361 
1362   if (!(Media->MediaPresent)) {
1363     Status = EFI_NO_MEDIA;
1364     goto Done;
1365   }
1366 
1367   if (Media->ReadOnly) {
1368     Status = EFI_WRITE_PROTECTED;
1369     goto Done;
1370   }
1371 
1372   //
1373   // Wait for the BlockIo2 requests queue to become empty
1374   //
1375   while (!IsListEmpty (&ScsiDiskDevice->AsyncTaskQueue));
1376 
1377   Status = EFI_SUCCESS;
1378 
1379   //
1380   // Signal caller event
1381   //
1382   if ((Token != NULL) && (Token->Event != NULL)) {
1383     Token->TransactionStatus = EFI_SUCCESS;
1384     gBS->SignalEvent (Token->Event);
1385   }
1386 
1387 Done:
1388   gBS->RestoreTPL (OldTpl);
1389   return Status;
1390 }
1391 
1392 
1393 /**
1394   Internal helper notify function which process the result of an asynchronous
1395   SCSI UNMAP Command and signal the event passed from EraseBlocks.
1396 
1397   @param  Event    The instance of EFI_EVENT.
1398   @param  Context  The parameter passed in.
1399 
1400 **/
1401 VOID
1402 EFIAPI
1403 ScsiDiskAsyncUnmapNotify (
1404   IN  EFI_EVENT  Event,
1405   IN  VOID       *Context
1406   )
1407 {
1408   SCSI_ERASEBLK_REQUEST            *EraseBlkReq;
1409   EFI_SCSI_IO_SCSI_REQUEST_PACKET  *CommandPacket;
1410   EFI_ERASE_BLOCK_TOKEN            *Token;
1411   EFI_STATUS                       Status;
1412 
1413   gBS->CloseEvent (Event);
1414 
1415   EraseBlkReq              = (SCSI_ERASEBLK_REQUEST *) Context;
1416   CommandPacket            = &EraseBlkReq->CommandPacket;
1417   Token                    = EraseBlkReq->Token;
1418   Token->TransactionStatus = EFI_SUCCESS;
1419 
1420   Status = CheckHostAdapterStatus (CommandPacket->HostAdapterStatus);
1421   if (EFI_ERROR(Status)) {
1422     DEBUG ((
1423       EFI_D_ERROR,
1424       "ScsiDiskAsyncUnmapNotify: Host adapter indicating error status 0x%x.\n",
1425       CommandPacket->HostAdapterStatus
1426       ));
1427 
1428     Token->TransactionStatus = Status;
1429     goto Done;
1430   }
1431 
1432   Status = CheckTargetStatus (CommandPacket->TargetStatus);
1433   if (EFI_ERROR(Status)) {
1434     DEBUG ((
1435       EFI_D_ERROR,
1436       "ScsiDiskAsyncUnmapNotify: Target indicating error status 0x%x.\n",
1437       CommandPacket->HostAdapterStatus
1438       ));
1439 
1440     Token->TransactionStatus = Status;
1441     goto Done;
1442   }
1443 
1444 Done:
1445   RemoveEntryList (&EraseBlkReq->Link);
1446   FreePool (CommandPacket->OutDataBuffer);
1447   FreePool (EraseBlkReq->CommandPacket.Cdb);
1448   FreePool (EraseBlkReq);
1449 
1450   gBS->SignalEvent (Token->Event);
1451 }
1452 
1453 /**
1454   Require the device server to cause one or more LBAs to be unmapped.
1455 
1456   @param  ScsiDiskDevice         The pointer of ScsiDiskDevice.
1457   @param  Lba                    The start block number.
1458   @param  Blocks                 Total block number to be unmapped.
1459   @param  Token                  The pointer to the token associated with the
1460                                  non-blocking erase block request.
1461 
1462   @retval EFI_SUCCESS            Target blocks have been successfully unmapped.
1463   @retval EFI_DEVICE_ERROR       Fail to unmap the target blocks.
1464 
1465 **/
1466 EFI_STATUS
1467 ScsiDiskUnmap (
1468   IN SCSI_DISK_DEV                 *ScsiDiskDevice,
1469   IN UINT64                        Lba,
1470   IN UINTN                         Blocks,
1471   IN EFI_ERASE_BLOCK_TOKEN         *Token            OPTIONAL
1472   )
1473 {
1474   EFI_SCSI_IO_PROTOCOL             *ScsiIo;
1475   SCSI_ERASEBLK_REQUEST            *EraseBlkReq;
1476   EFI_SCSI_IO_SCSI_REQUEST_PACKET  *CommandPacket;
1477   EFI_SCSI_DISK_UNMAP_BLOCK_DESP   *BlkDespPtr;
1478   EFI_STATUS                       Status;
1479   EFI_STATUS                       ReturnStatus;
1480   UINT8                            *Cdb;
1481   UINT32                           MaxLbaCnt;
1482   UINT32                           MaxBlkDespCnt;
1483   UINT32                           BlkDespCnt;
1484   UINT16                           UnmapParamListLen;
1485   VOID                             *UnmapParamList;
1486   EFI_EVENT                        AsyncUnmapEvent;
1487   EFI_TPL                          OldTpl;
1488 
1489   ScsiIo          = ScsiDiskDevice->ScsiIo;
1490   MaxLbaCnt       = ScsiDiskDevice->UnmapInfo.MaxLbaCnt;
1491   MaxBlkDespCnt   = ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt;
1492   EraseBlkReq     = NULL;
1493   UnmapParamList  = NULL;
1494   AsyncUnmapEvent = NULL;
1495   ReturnStatus    = EFI_SUCCESS;
1496 
1497   if (Blocks / (UINTN) MaxLbaCnt > MaxBlkDespCnt) {
1498     ReturnStatus = EFI_DEVICE_ERROR;
1499     goto Done;
1500   }
1501 
1502   EraseBlkReq = AllocateZeroPool (sizeof (SCSI_ERASEBLK_REQUEST));
1503   if (EraseBlkReq == NULL) {
1504     ReturnStatus = EFI_DEVICE_ERROR;
1505     goto Done;
1506   }
1507 
1508   EraseBlkReq->CommandPacket.Cdb = AllocateZeroPool (0xA);
1509   if (EraseBlkReq->CommandPacket.Cdb == NULL) {
1510     ReturnStatus = EFI_DEVICE_ERROR;
1511     goto Done;
1512   }
1513 
1514   BlkDespCnt        = (UINT32) ((Blocks - 1) / MaxLbaCnt + 1);
1515   UnmapParamListLen = (UINT16) (sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER)
1516                       + BlkDespCnt * sizeof (EFI_SCSI_DISK_UNMAP_BLOCK_DESP));
1517   UnmapParamList    = AllocateZeroPool (UnmapParamListLen);
1518   if (UnmapParamList == NULL) {
1519     ReturnStatus = EFI_DEVICE_ERROR;
1520     goto Done;
1521   }
1522 
1523   *((UINT16 *)UnmapParamList)     = SwapBytes16 (UnmapParamListLen - 2);
1524   *((UINT16 *)UnmapParamList + 1) = SwapBytes16 (UnmapParamListLen - sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER));
1525 
1526   BlkDespPtr = (EFI_SCSI_DISK_UNMAP_BLOCK_DESP *)((UINT8 *)UnmapParamList + sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER));
1527   while (Blocks > 0) {
1528     if (Blocks > MaxLbaCnt) {
1529       *(UINT64 *)(&BlkDespPtr->Lba)      = SwapBytes64 (Lba);
1530       *(UINT32 *)(&BlkDespPtr->BlockNum) = SwapBytes32 (MaxLbaCnt);
1531       Blocks -= MaxLbaCnt;
1532       Lba    += MaxLbaCnt;
1533     } else {
1534       *(UINT64 *)(&BlkDespPtr->Lba)      = SwapBytes64 (Lba);
1535       *(UINT32 *)(&BlkDespPtr->BlockNum) = SwapBytes32 ((UINT32) Blocks);
1536       Blocks = 0;
1537     }
1538 
1539     BlkDespPtr++;
1540   }
1541 
1542   CommandPacket                    = &EraseBlkReq->CommandPacket;
1543   CommandPacket->Timeout           = SCSI_DISK_TIMEOUT;
1544   CommandPacket->OutDataBuffer     = UnmapParamList;
1545   CommandPacket->OutTransferLength = UnmapParamListLen;
1546   CommandPacket->CdbLength         = 0xA;
1547   CommandPacket->DataDirection     = EFI_SCSI_DATA_OUT;
1548   //
1549   // Fill Cdb for UNMAP Command
1550   //
1551   Cdb    = CommandPacket->Cdb;
1552   Cdb[0] = EFI_SCSI_OP_UNMAP;
1553   WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 (UnmapParamListLen));
1554 
1555   if ((Token != NULL) && (Token->Event != NULL)) {
1556     //
1557     // Non-blocking UNMAP request
1558     //
1559     Status = gBS->CreateEvent (
1560                     EVT_NOTIFY_SIGNAL,
1561                     TPL_NOTIFY,
1562                     ScsiDiskAsyncUnmapNotify,
1563                     EraseBlkReq,
1564                     &AsyncUnmapEvent
1565                     );
1566     if (EFI_ERROR(Status)) {
1567       ReturnStatus = EFI_DEVICE_ERROR;
1568       goto Done;
1569     }
1570 
1571     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1572     InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &EraseBlkReq->Link);
1573     gBS->RestoreTPL (OldTpl);
1574 
1575     EraseBlkReq->Token = Token;
1576 
1577     Status = ScsiIo->ExecuteScsiCommand (
1578                        ScsiIo,
1579                        CommandPacket,
1580                        AsyncUnmapEvent
1581                        );
1582     if (EFI_ERROR(Status)) {
1583       ReturnStatus = EFI_DEVICE_ERROR;
1584 
1585       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1586       RemoveEntryList (&EraseBlkReq->Link);
1587       gBS->RestoreTPL (OldTpl);
1588 
1589       goto Done;
1590     } else {
1591       //
1592       // Directly return if the non-blocking UNMAP request is queued.
1593       //
1594       return EFI_SUCCESS;
1595     }
1596   } else {
1597     //
1598     // Blocking UNMAP request
1599     //
1600     Status = ScsiIo->ExecuteScsiCommand (
1601                        ScsiIo,
1602                        CommandPacket,
1603                        NULL
1604                        );
1605     if (EFI_ERROR(Status)) {
1606       ReturnStatus = EFI_DEVICE_ERROR;
1607       goto Done;
1608     }
1609   }
1610 
1611   //
1612   // Only blocking UNMAP request will reach here.
1613   //
1614   Status = CheckHostAdapterStatus (CommandPacket->HostAdapterStatus);
1615   if (EFI_ERROR(Status)) {
1616     DEBUG ((
1617       EFI_D_ERROR,
1618       "ScsiDiskUnmap: Host adapter indicating error status 0x%x.\n",
1619       CommandPacket->HostAdapterStatus
1620       ));
1621 
1622     ReturnStatus = EFI_DEVICE_ERROR;
1623     goto Done;
1624   }
1625 
1626   Status = CheckTargetStatus (CommandPacket->TargetStatus);
1627   if (EFI_ERROR(Status)) {
1628     DEBUG ((
1629       EFI_D_ERROR,
1630       "ScsiDiskUnmap: Target indicating error status 0x%x.\n",
1631       CommandPacket->HostAdapterStatus
1632       ));
1633 
1634     ReturnStatus = EFI_DEVICE_ERROR;
1635     goto Done;
1636   }
1637 
1638 Done:
1639   if (EraseBlkReq != NULL) {
1640     if (EraseBlkReq->CommandPacket.Cdb != NULL) {
1641       FreePool (EraseBlkReq->CommandPacket.Cdb);
1642     }
1643     FreePool (EraseBlkReq);
1644   }
1645 
1646   if (UnmapParamList != NULL) {
1647     FreePool (UnmapParamList);
1648   }
1649 
1650   if (AsyncUnmapEvent != NULL) {
1651     gBS->CloseEvent (AsyncUnmapEvent);
1652   }
1653 
1654   return ReturnStatus;
1655 }
1656 
1657 /**
1658   Erase a specified number of device blocks.
1659 
1660   @param[in]       This           Indicates a pointer to the calling context.
1661   @param[in]       MediaId        The media ID that the erase request is for.
1662   @param[in]       Lba            The starting logical block address to be
1663                                   erased. The caller is responsible for erasing
1664                                   only legitimate locations.
1665   @param[in, out]  Token          A pointer to the token associated with the
1666                                   transaction.
1667   @param[in]       Size           The size in bytes to be erased. This must be
1668                                   a multiple of the physical block size of the
1669                                   device.
1670 
1671   @retval EFI_SUCCESS             The erase request was queued if Event is not
1672                                   NULL. The data was erased correctly to the
1673                                   device if the Event is NULL.to the device.
1674   @retval EFI_WRITE_PROTECTED     The device cannot be erased due to write
1675                                   protection.
1676   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
1677                                   to perform the erase operation.
1678   @retval EFI_INVALID_PARAMETER   The erase request contains LBAs that are not
1679                                   valid.
1680   @retval EFI_NO_MEDIA            There is no media in the device.
1681   @retval EFI_MEDIA_CHANGED       The MediaId is not for the current media.
1682 
1683 **/
1684 EFI_STATUS
1685 EFIAPI
1686 ScsiDiskEraseBlocks (
1687   IN     EFI_ERASE_BLOCK_PROTOCOL      *This,
1688   IN     UINT32                        MediaId,
1689   IN     EFI_LBA                       Lba,
1690   IN OUT EFI_ERASE_BLOCK_TOKEN         *Token,
1691   IN     UINTN                         Size
1692   )
1693 {
1694   SCSI_DISK_DEV       *ScsiDiskDevice;
1695   EFI_BLOCK_IO_MEDIA  *Media;
1696   EFI_STATUS          Status;
1697   UINTN               BlockSize;
1698   UINTN               NumberOfBlocks;
1699   BOOLEAN             MediaChange;
1700   EFI_TPL             OldTpl;
1701 
1702   MediaChange    = FALSE;
1703   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
1704   ScsiDiskDevice = SCSI_DISK_DEV_FROM_ERASEBLK (This);
1705 
1706   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
1707     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1708     if (EFI_ERROR (Status)) {
1709       Status = EFI_DEVICE_ERROR;
1710       goto Done;
1711     }
1712 
1713     if (MediaChange) {
1714       gBS->ReinstallProtocolInterface (
1715             ScsiDiskDevice->Handle,
1716             &gEfiBlockIoProtocolGuid,
1717             &ScsiDiskDevice->BlkIo,
1718             &ScsiDiskDevice->BlkIo
1719             );
1720       gBS->ReinstallProtocolInterface (
1721              ScsiDiskDevice->Handle,
1722              &gEfiBlockIo2ProtocolGuid,
1723              &ScsiDiskDevice->BlkIo2,
1724              &ScsiDiskDevice->BlkIo2
1725              );
1726       if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1727         gBS->ReinstallProtocolInterface (
1728                ScsiDiskDevice->Handle,
1729                &gEfiEraseBlockProtocolGuid,
1730                &ScsiDiskDevice->EraseBlock,
1731                &ScsiDiskDevice->EraseBlock
1732                );
1733       }
1734       if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1735         gBS->ReinstallProtocolInterface (
1736                 ScsiDiskDevice->Handle,
1737                 &gEfiStorageSecurityCommandProtocolGuid,
1738                 &ScsiDiskDevice->StorageSecurity,
1739                 &ScsiDiskDevice->StorageSecurity
1740                 );
1741       }
1742       Status = EFI_MEDIA_CHANGED;
1743       goto Done;
1744     }
1745   }
1746   //
1747   // Get the intrinsic block size
1748   //
1749   Media = ScsiDiskDevice->BlkIo.Media;
1750 
1751   if (!(Media->MediaPresent)) {
1752     Status = EFI_NO_MEDIA;
1753     goto Done;
1754   }
1755 
1756   if (MediaId != Media->MediaId) {
1757     Status = EFI_MEDIA_CHANGED;
1758     goto Done;
1759   }
1760 
1761   if (Media->ReadOnly) {
1762     Status = EFI_WRITE_PROTECTED;
1763     goto Done;
1764   }
1765 
1766   if (Size == 0) {
1767     if ((Token != NULL) && (Token->Event != NULL)) {
1768       Token->TransactionStatus = EFI_SUCCESS;
1769       gBS->SignalEvent (Token->Event);
1770     }
1771     Status = EFI_SUCCESS;
1772     goto Done;
1773   }
1774 
1775   BlockSize = Media->BlockSize;
1776   if ((Size % BlockSize) != 0) {
1777     Status = EFI_INVALID_PARAMETER;
1778     goto Done;
1779   }
1780 
1781   NumberOfBlocks = Size / BlockSize;
1782   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1783     Status = EFI_INVALID_PARAMETER;
1784     goto Done;
1785   }
1786 
1787   if ((Token != NULL) && (Token->Event != NULL)) {
1788     Status = ScsiDiskUnmap (ScsiDiskDevice, Lba, NumberOfBlocks, Token);
1789   } else {
1790     Status = ScsiDiskUnmap (ScsiDiskDevice, Lba, NumberOfBlocks, NULL);
1791   }
1792 
1793 Done:
1794   gBS->RestoreTPL (OldTpl);
1795   return Status;
1796 }
1797 
1798 /**
1799   Send a security protocol command to a device that receives data and/or the result
1800   of one or more commands sent by SendData.
1801 
1802   The ReceiveData function sends a security protocol command to the given MediaId.
1803   The security protocol command sent is defined by SecurityProtocolId and contains
1804   the security protocol specific data SecurityProtocolSpecificData. The function
1805   returns the data from the security protocol command in PayloadBuffer.
1806 
1807   For devices supporting the SCSI command set, the security protocol command is sent
1808   using the SECURITY PROTOCOL IN command defined in SPC-4.
1809 
1810   If PayloadBufferSize is too small to store the available data from the security
1811   protocol command, the function shall copy PayloadBufferSize bytes into the
1812   PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
1813 
1814   If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
1815   the function shall return EFI_INVALID_PARAMETER.
1816 
1817   If the given MediaId does not support security protocol commands, the function shall
1818   return EFI_UNSUPPORTED. If there is no media in the device, the function returns
1819   EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
1820   the function returns EFI_MEDIA_CHANGED.
1821 
1822   If the security protocol fails to complete within the Timeout period, the function
1823   shall return EFI_TIMEOUT.
1824 
1825   If the security protocol command completes without an error, the function shall
1826   return EFI_SUCCESS. If the security protocol command completes with an error, the
1827   function shall return EFI_DEVICE_ERROR.
1828 
1829   @param  This                         Indicates a pointer to the calling context.
1830   @param  MediaId                      ID of the medium to receive data from.
1831   @param  Timeout                      The timeout, in 100ns units, to use for the execution
1832                                        of the security protocol command. A Timeout value of 0
1833                                        means that this function will wait indefinitely for the
1834                                        security protocol command to execute. If Timeout is greater
1835                                        than zero, then this function will return EFI_TIMEOUT if the
1836                                        time required to execute the receive data command is greater than Timeout.
1837   @param  SecurityProtocolId           The value of the "Security Protocol" parameter of
1838                                        the security protocol command to be sent.
1839   @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1840                                        of the security protocol command to be sent.
1841   @param  PayloadBufferSize            Size in bytes of the payload data buffer.
1842   @param  PayloadBuffer                A pointer to a destination buffer to store the security
1843                                        protocol command specific payload data for the security
1844                                        protocol command. The caller is responsible for having
1845                                        either implicit or explicit ownership of the buffer.
1846   @param  PayloadTransferSize          A pointer to a buffer to store the size in bytes of the
1847                                        data written to the payload data buffer.
1848 
1849   @retval EFI_SUCCESS                  The security protocol command completed successfully.
1850   @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to store the available
1851                                        data from the device. The PayloadBuffer contains the truncated data.
1852   @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.
1853   @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.
1854   @retval EFI_NO_MEDIA                 There is no media in the device.
1855   @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.
1856   @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize is NULL and
1857                                        PayloadBufferSize is non-zero.
1858   @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security
1859                                        protocol command to execute.
1860 
1861 **/
1862 EFI_STATUS
1863 EFIAPI
1864 ScsiDiskReceiveData (
1865   IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
1866   IN UINT32                                   MediaId   OPTIONAL,
1867   IN UINT64                                   Timeout,
1868   IN UINT8                                    SecurityProtocolId,
1869   IN UINT16                                   SecurityProtocolSpecificData,
1870   IN UINTN                                    PayloadBufferSize,
1871   OUT VOID                                    *PayloadBuffer,
1872   OUT UINTN                                   *PayloadTransferSize
1873   )
1874 {
1875   SCSI_DISK_DEV       *ScsiDiskDevice;
1876   EFI_BLOCK_IO_MEDIA  *Media;
1877   EFI_STATUS          Status;
1878   BOOLEAN             MediaChange;
1879   EFI_TPL             OldTpl;
1880   UINT8               SenseDataLength;
1881   UINT8               HostAdapterStatus;
1882   UINT8               TargetStatus;
1883   VOID                *AlignedBuffer;
1884   BOOLEAN             AlignedBufferAllocated;
1885 
1886   AlignedBuffer           = NULL;
1887   MediaChange             = FALSE;
1888   AlignedBufferAllocated  = FALSE;
1889   OldTpl                  = gBS->RaiseTPL (TPL_CALLBACK);
1890   ScsiDiskDevice          = SCSI_DISK_DEV_FROM_STORSEC (This);
1891   Media                   = ScsiDiskDevice->BlkIo.Media;
1892 
1893   SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
1894 
1895   if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
1896     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
1897     if (EFI_ERROR (Status)) {
1898       Status = EFI_DEVICE_ERROR;
1899       goto Done;
1900     }
1901 
1902     if (MediaChange) {
1903       gBS->ReinstallProtocolInterface (
1904             ScsiDiskDevice->Handle,
1905             &gEfiBlockIoProtocolGuid,
1906             &ScsiDiskDevice->BlkIo,
1907             &ScsiDiskDevice->BlkIo
1908             );
1909       gBS->ReinstallProtocolInterface (
1910              ScsiDiskDevice->Handle,
1911              &gEfiBlockIo2ProtocolGuid,
1912              &ScsiDiskDevice->BlkIo2,
1913              &ScsiDiskDevice->BlkIo2
1914              );
1915       if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1916         gBS->ReinstallProtocolInterface (
1917                ScsiDiskDevice->Handle,
1918                &gEfiEraseBlockProtocolGuid,
1919                &ScsiDiskDevice->EraseBlock,
1920                &ScsiDiskDevice->EraseBlock
1921                );
1922       }
1923       if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
1924         gBS->ReinstallProtocolInterface (
1925                 ScsiDiskDevice->Handle,
1926                 &gEfiStorageSecurityCommandProtocolGuid,
1927                 &ScsiDiskDevice->StorageSecurity,
1928                 &ScsiDiskDevice->StorageSecurity
1929                 );
1930       }
1931       if (Media->MediaPresent) {
1932         Status = EFI_MEDIA_CHANGED;
1933       } else {
1934         Status = EFI_NO_MEDIA;
1935       }
1936       goto Done;
1937     }
1938   }
1939 
1940   //
1941   // Validate Media
1942   //
1943   if (!(Media->MediaPresent)) {
1944     Status = EFI_NO_MEDIA;
1945     goto Done;
1946   }
1947 
1948   if ((MediaId != 0) && (MediaId != Media->MediaId)) {
1949     Status = EFI_MEDIA_CHANGED;
1950     goto Done;
1951   }
1952 
1953   if (PayloadBufferSize != 0) {
1954     if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL)) {
1955       Status = EFI_INVALID_PARAMETER;
1956       goto Done;
1957     }
1958 
1959     if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
1960       AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
1961       if (AlignedBuffer == NULL) {
1962         Status = EFI_OUT_OF_RESOURCES;
1963         goto Done;
1964       }
1965       ZeroMem (AlignedBuffer, PayloadBufferSize);
1966       AlignedBufferAllocated = TRUE;
1967     } else {
1968       AlignedBuffer = PayloadBuffer;
1969     }
1970   }
1971 
1972   Status = ScsiSecurityProtocolInCommand (
1973             ScsiDiskDevice->ScsiIo,
1974             Timeout,
1975             ScsiDiskDevice->SenseData,
1976             &SenseDataLength,
1977             &HostAdapterStatus,
1978             &TargetStatus,
1979             SecurityProtocolId,
1980             SecurityProtocolSpecificData,
1981             FALSE,
1982             PayloadBufferSize,
1983             AlignedBuffer,
1984             PayloadTransferSize
1985           );
1986   if (EFI_ERROR (Status)) {
1987     goto Done;
1988   }
1989 
1990   if (AlignedBufferAllocated) {
1991     CopyMem (PayloadBuffer, AlignedBuffer, PayloadBufferSize);
1992   }
1993 
1994   if (PayloadBufferSize < *PayloadTransferSize) {
1995     Status = EFI_WARN_BUFFER_TOO_SMALL;
1996     goto Done;
1997   }
1998 
1999   Status = CheckHostAdapterStatus (HostAdapterStatus);
2000   if (EFI_ERROR (Status)) {
2001     goto Done;
2002   }
2003 
2004   Status = CheckTargetStatus (TargetStatus);
2005   if (EFI_ERROR (Status)) {
2006     goto Done;
2007   }
2008 
2009 Done:
2010   if (AlignedBufferAllocated) {
2011     ZeroMem (AlignedBuffer, PayloadBufferSize);
2012     FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);
2013   }
2014   gBS->RestoreTPL (OldTpl);
2015   return Status;
2016 }
2017 
2018 /**
2019   Send a security protocol command to a device.
2020 
2021   The SendData function sends a security protocol command containing the payload
2022   PayloadBuffer to the given MediaId. The security protocol command sent is
2023   defined by SecurityProtocolId and contains the security protocol specific data
2024   SecurityProtocolSpecificData. If the underlying protocol command requires a
2025   specific padding for the command payload, the SendData function shall add padding
2026   bytes to the command payload to satisfy the padding requirements.
2027 
2028   For devices supporting the SCSI command set, the security protocol command is sent
2029   using the SECURITY PROTOCOL OUT command defined in SPC-4.
2030 
2031   If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
2032   return EFI_INVALID_PARAMETER.
2033 
2034   If the given MediaId does not support security protocol commands, the function
2035   shall return EFI_UNSUPPORTED. If there is no media in the device, the function
2036   returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
2037   device, the function returns EFI_MEDIA_CHANGED.
2038 
2039   If the security protocol fails to complete within the Timeout period, the function
2040   shall return EFI_TIMEOUT.
2041 
2042   If the security protocol command completes without an error, the function shall return
2043   EFI_SUCCESS. If the security protocol command completes with an error, the function
2044   shall return EFI_DEVICE_ERROR.
2045 
2046   @param  This                         Indicates a pointer to the calling context.
2047   @param  MediaId                      ID of the medium to receive data from.
2048   @param  Timeout                      The timeout, in 100ns units, to use for the execution
2049                                        of the security protocol command. A Timeout value of 0
2050                                        means that this function will wait indefinitely for the
2051                                        security protocol command to execute. If Timeout is greater
2052                                        than zero, then this function will return EFI_TIMEOUT if the
2053                                        time required to execute the receive data command is greater than Timeout.
2054   @param  SecurityProtocolId           The value of the "Security Protocol" parameter of
2055                                        the security protocol command to be sent.
2056   @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
2057                                        of the security protocol command to be sent.
2058   @param  PayloadBufferSize            Size in bytes of the payload data buffer.
2059   @param  PayloadBuffer                A pointer to a destination buffer to store the security
2060                                        protocol command specific payload data for the security
2061                                        protocol command.
2062 
2063   @retval EFI_SUCCESS                  The security protocol command completed successfully.
2064   @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.
2065   @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.
2066   @retval EFI_NO_MEDIA                 There is no media in the device.
2067   @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.
2068   @retval EFI_INVALID_PARAMETER        The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
2069   @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security
2070                                        protocol command to execute.
2071 
2072 **/
2073 EFI_STATUS
2074 EFIAPI
2075 ScsiDiskSendData (
2076   IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
2077   IN UINT32                                   MediaId   OPTIONAL,
2078   IN UINT64                                   Timeout,
2079   IN UINT8                                    SecurityProtocolId,
2080   IN UINT16                                   SecurityProtocolSpecificData,
2081   IN UINTN                                    PayloadBufferSize,
2082   OUT VOID                                    *PayloadBuffer
2083   )
2084 {
2085   SCSI_DISK_DEV       *ScsiDiskDevice;
2086   EFI_BLOCK_IO_MEDIA  *Media;
2087   EFI_STATUS          Status;
2088   BOOLEAN             MediaChange;
2089   EFI_TPL             OldTpl;
2090   UINT8               SenseDataLength;
2091   UINT8               HostAdapterStatus;
2092   UINT8               TargetStatus;
2093   VOID                *AlignedBuffer;
2094   BOOLEAN             AlignedBufferAllocated;
2095 
2096   AlignedBuffer           = NULL;
2097   MediaChange             = FALSE;
2098   AlignedBufferAllocated  = FALSE;
2099   OldTpl                  = gBS->RaiseTPL (TPL_CALLBACK);
2100   ScsiDiskDevice          = SCSI_DISK_DEV_FROM_STORSEC (This);
2101   Media                   = ScsiDiskDevice->BlkIo.Media;
2102 
2103   SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
2104 
2105   if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
2106     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
2107     if (EFI_ERROR (Status)) {
2108       Status = EFI_DEVICE_ERROR;
2109       goto Done;
2110     }
2111 
2112     if (MediaChange) {
2113       gBS->ReinstallProtocolInterface (
2114             ScsiDiskDevice->Handle,
2115             &gEfiBlockIoProtocolGuid,
2116             &ScsiDiskDevice->BlkIo,
2117             &ScsiDiskDevice->BlkIo
2118             );
2119       gBS->ReinstallProtocolInterface (
2120              ScsiDiskDevice->Handle,
2121              &gEfiBlockIo2ProtocolGuid,
2122              &ScsiDiskDevice->BlkIo2,
2123              &ScsiDiskDevice->BlkIo2
2124              );
2125       if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
2126         gBS->ReinstallProtocolInterface (
2127                ScsiDiskDevice->Handle,
2128                &gEfiEraseBlockProtocolGuid,
2129                &ScsiDiskDevice->EraseBlock,
2130                &ScsiDiskDevice->EraseBlock
2131                );
2132       }
2133       if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
2134         gBS->ReinstallProtocolInterface (
2135                 ScsiDiskDevice->Handle,
2136                 &gEfiStorageSecurityCommandProtocolGuid,
2137                 &ScsiDiskDevice->StorageSecurity,
2138                 &ScsiDiskDevice->StorageSecurity
2139                 );
2140       }
2141       if (Media->MediaPresent) {
2142         Status = EFI_MEDIA_CHANGED;
2143       } else {
2144         Status = EFI_NO_MEDIA;
2145       }
2146       goto Done;
2147     }
2148   }
2149 
2150   //
2151   // Validate Media
2152   //
2153   if (!(Media->MediaPresent)) {
2154     Status = EFI_NO_MEDIA;
2155     goto Done;
2156   }
2157 
2158   if ((MediaId != 0) && (MediaId != Media->MediaId)) {
2159     Status = EFI_MEDIA_CHANGED;
2160     goto Done;
2161   }
2162 
2163   if (Media->ReadOnly) {
2164     Status = EFI_WRITE_PROTECTED;
2165     goto Done;
2166   }
2167 
2168   if (PayloadBufferSize != 0) {
2169     if (PayloadBuffer == NULL) {
2170       Status = EFI_INVALID_PARAMETER;
2171       goto Done;
2172     }
2173 
2174     if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
2175       AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
2176       if (AlignedBuffer == NULL) {
2177         Status = EFI_OUT_OF_RESOURCES;
2178         goto Done;
2179       }
2180       CopyMem (AlignedBuffer, PayloadBuffer, PayloadBufferSize);
2181       AlignedBufferAllocated = TRUE;
2182     } else {
2183       AlignedBuffer = PayloadBuffer;
2184     }
2185   }
2186 
2187   Status = ScsiSecurityProtocolOutCommand (
2188             ScsiDiskDevice->ScsiIo,
2189             Timeout,
2190             ScsiDiskDevice->SenseData,
2191             &SenseDataLength,
2192             &HostAdapterStatus,
2193             &TargetStatus,
2194             SecurityProtocolId,
2195             SecurityProtocolSpecificData,
2196             FALSE,
2197             PayloadBufferSize,
2198             AlignedBuffer
2199           );
2200   if (EFI_ERROR (Status)) {
2201     goto Done;
2202   }
2203 
2204   Status = CheckHostAdapterStatus (HostAdapterStatus);
2205   if (EFI_ERROR (Status)) {
2206     goto Done;
2207   }
2208 
2209   Status = CheckTargetStatus (TargetStatus);
2210   if (EFI_ERROR (Status)) {
2211     goto Done;
2212   }
2213 
2214 Done:
2215   if (AlignedBufferAllocated) {
2216     ZeroMem (AlignedBuffer, PayloadBufferSize);
2217     FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);
2218   }
2219   gBS->RestoreTPL (OldTpl);
2220   return Status;
2221 }
2222 
2223 
2224 /**
2225   Detect Device and read out capacity ,if error occurs, parse the sense key.
2226 
2227   @param  ScsiDiskDevice    The pointer of SCSI_DISK_DEV
2228   @param  MustReadCapacity  The flag about reading device capacity
2229   @param  MediaChange       The pointer of flag indicates if media has changed
2230 
2231   @retval EFI_DEVICE_ERROR  Indicates that error occurs
2232   @retval EFI_SUCCESS       Successfully to detect media
2233 
2234 **/
2235 EFI_STATUS
2236 ScsiDiskDetectMedia (
2237   IN   SCSI_DISK_DEV   *ScsiDiskDevice,
2238   IN   BOOLEAN         MustReadCapacity,
2239   OUT  BOOLEAN         *MediaChange
2240   )
2241 {
2242   EFI_STATUS          Status;
2243   EFI_SCSI_SENSE_DATA *SenseData;
2244   UINTN               NumberOfSenseKeys;
2245   BOOLEAN             NeedRetry;
2246   BOOLEAN             NeedReadCapacity;
2247   UINT8               Retry;
2248   UINT8               MaxRetry;
2249   EFI_BLOCK_IO_MEDIA  OldMedia;
2250   UINTN               Action;
2251   EFI_EVENT           TimeoutEvt;
2252 
2253   Status              = EFI_SUCCESS;
2254   SenseData           = NULL;
2255   NumberOfSenseKeys   = 0;
2256   Retry               = 0;
2257   MaxRetry            = 3;
2258   Action              = ACTION_NO_ACTION;
2259   NeedReadCapacity    = FALSE;
2260   *MediaChange        = FALSE;
2261   TimeoutEvt          = NULL;
2262 
2263   CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
2264 
2265   Status = gBS->CreateEvent (
2266                   EVT_TIMER,
2267                   TPL_CALLBACK,
2268                   NULL,
2269                   NULL,
2270                   &TimeoutEvt
2271                   );
2272   if (EFI_ERROR (Status)) {
2273     return Status;
2274   }
2275 
2276   Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(120));
2277   if (EFI_ERROR (Status)) {
2278     goto EXIT;
2279   }
2280 
2281   //
2282   // Sending Test_Unit cmd to poll device status.
2283   // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
2284   // We limit the upper boundary to 120 seconds.
2285   //
2286   while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
2287     Status = ScsiDiskTestUnitReady (
2288               ScsiDiskDevice,
2289               &NeedRetry,
2290               &SenseData,
2291               &NumberOfSenseKeys
2292               );
2293     if (!EFI_ERROR (Status)) {
2294       Status = DetectMediaParsingSenseKeys (
2295                  ScsiDiskDevice,
2296                  SenseData,
2297                  NumberOfSenseKeys,
2298                  &Action
2299                  );
2300       if (EFI_ERROR (Status)) {
2301         goto EXIT;
2302       } else if (Action == ACTION_RETRY_COMMAND_LATER) {
2303         continue;
2304       } else {
2305         break;
2306       }
2307     } else {
2308       Retry++;
2309       if (!NeedRetry || (Retry >= MaxRetry)) {
2310         goto EXIT;
2311       }
2312     }
2313   }
2314 
2315   if (EFI_ERROR (Status)) {
2316     goto EXIT;
2317   }
2318 
2319   //
2320   // ACTION_NO_ACTION: need not read capacity
2321   // other action code: need read capacity
2322   //
2323   if (Action == ACTION_READ_CAPACITY) {
2324     NeedReadCapacity = TRUE;
2325   }
2326 
2327   //
2328   // READ_CAPACITY command is not supported by any of the UFS WLUNs.
2329   //
2330   if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) {
2331     NeedReadCapacity = FALSE;
2332     MustReadCapacity = FALSE;
2333     ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
2334   }
2335 
2336   //
2337   // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
2338   // retrieve capacity via Read Capacity command
2339   //
2340   if (NeedReadCapacity || MustReadCapacity) {
2341     //
2342     // retrieve media information
2343     //
2344     for (Retry = 0; Retry < MaxRetry; Retry++) {
2345       Status = ScsiDiskReadCapacity (
2346                  ScsiDiskDevice,
2347                  &NeedRetry,
2348                  &SenseData,
2349                  &NumberOfSenseKeys
2350                  );
2351       if (!EFI_ERROR (Status)) {
2352         //
2353         // analyze sense key to action
2354         //
2355         Status = DetectMediaParsingSenseKeys (
2356                    ScsiDiskDevice,
2357                    SenseData,
2358                    NumberOfSenseKeys,
2359                    &Action
2360                    );
2361         if (EFI_ERROR (Status)) {
2362           //
2363           // if Status is error, it may indicate crisis error,
2364           // so return without retry.
2365           //
2366           goto EXIT;
2367         } else if (Action == ACTION_RETRY_COMMAND_LATER) {
2368           Retry = 0;
2369           continue;
2370         } else {
2371           break;
2372         }
2373       } else {
2374         Retry++;
2375         if (!NeedRetry || (Retry >= MaxRetry)) {
2376           goto EXIT;
2377         }
2378       }
2379     }
2380 
2381     if (EFI_ERROR (Status)) {
2382       goto EXIT;
2383     }
2384   }
2385 
2386   if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {
2387     //
2388     // Media change information got from the device
2389     //
2390     *MediaChange = TRUE;
2391   }
2392 
2393   if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {
2394     *MediaChange = TRUE;
2395     ScsiDiskDevice->BlkIo.Media->MediaId += 1;
2396   }
2397 
2398   if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {
2399     *MediaChange = TRUE;
2400     ScsiDiskDevice->BlkIo.Media->MediaId += 1;
2401   }
2402 
2403   if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {
2404     *MediaChange = TRUE;
2405     ScsiDiskDevice->BlkIo.Media->MediaId += 1;
2406   }
2407 
2408   if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {
2409     if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {
2410       //
2411       // when change from no media to media present, reset the MediaId to 1.
2412       //
2413       ScsiDiskDevice->BlkIo.Media->MediaId = 1;
2414     } else {
2415       //
2416       // when no media, reset the MediaId to zero.
2417       //
2418       ScsiDiskDevice->BlkIo.Media->MediaId = 0;
2419     }
2420 
2421     *MediaChange = TRUE;
2422   }
2423 
2424 EXIT:
2425   if (TimeoutEvt != NULL) {
2426     gBS->CloseEvent (TimeoutEvt);
2427   }
2428   return Status;
2429 }
2430 
2431 
2432 /**
2433   Send out Inquiry command to Device.
2434 
2435   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
2436   @param  NeedRetry       Indicates if needs try again when error happens
2437 
2438   @retval  EFI_DEVICE_ERROR  Indicates that error occurs
2439   @retval  EFI_SUCCESS       Successfully to detect media
2440 
2441 **/
2442 EFI_STATUS
2443 ScsiDiskInquiryDevice (
2444   IN OUT  SCSI_DISK_DEV   *ScsiDiskDevice,
2445      OUT  BOOLEAN         *NeedRetry
2446   )
2447 {
2448   UINT32                                InquiryDataLength;
2449   UINT8                                 SenseDataLength;
2450   UINT8                                 HostAdapterStatus;
2451   UINT8                                 TargetStatus;
2452   EFI_SCSI_SENSE_DATA                   *SenseDataArray;
2453   UINTN                                 NumberOfSenseKeys;
2454   EFI_STATUS                            Status;
2455   UINT8                                 MaxRetry;
2456   UINT8                                 Index;
2457   EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE *SupportedVpdPages;
2458   EFI_SCSI_BLOCK_LIMITS_VPD_PAGE        *BlockLimits;
2459   UINTN                                 PageLength;
2460 
2461   InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
2462   SenseDataLength   = 0;
2463 
2464   Status = ScsiInquiryCommand (
2465             ScsiDiskDevice->ScsiIo,
2466             SCSI_DISK_TIMEOUT,
2467             NULL,
2468             &SenseDataLength,
2469             &HostAdapterStatus,
2470             &TargetStatus,
2471             (VOID *) &(ScsiDiskDevice->InquiryData),
2472             &InquiryDataLength,
2473             FALSE
2474             );
2475     //
2476     // no need to check HostAdapterStatus and TargetStatus
2477     //
2478   if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
2479     ParseInquiryData (ScsiDiskDevice);
2480 
2481     if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
2482       //
2483       // Check whether the device supports Block Limits VPD page (0xB0)
2484       //
2485       SupportedVpdPages = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2486       if (SupportedVpdPages == NULL) {
2487         *NeedRetry = FALSE;
2488         return EFI_DEVICE_ERROR;
2489       }
2490       ZeroMem (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2491       InquiryDataLength = sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE);
2492       SenseDataLength   = 0;
2493       Status = ScsiInquiryCommandEx (
2494                  ScsiDiskDevice->ScsiIo,
2495                  SCSI_DISK_TIMEOUT,
2496                  NULL,
2497                  &SenseDataLength,
2498                  &HostAdapterStatus,
2499                  &TargetStatus,
2500                  (VOID *) SupportedVpdPages,
2501                  &InquiryDataLength,
2502                  TRUE,
2503                  EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
2504                  );
2505       if (!EFI_ERROR (Status)) {
2506         PageLength = (SupportedVpdPages->PageLength2 << 8)
2507                    |  SupportedVpdPages->PageLength1;
2508 
2509         //
2510         // Sanity checks for coping with broken devices
2511         //
2512         if (PageLength > sizeof SupportedVpdPages->SupportedVpdPageList) {
2513           DEBUG ((EFI_D_WARN,
2514             "%a: invalid PageLength (%u) in Supported VPD Pages page\n",
2515             __FUNCTION__, (UINT32)PageLength));
2516           PageLength = 0;
2517         }
2518 
2519         if ((PageLength > 0) &&
2520             (SupportedVpdPages->SupportedVpdPageList[0] !=
2521              EFI_SCSI_PAGE_CODE_SUPPORTED_VPD)) {
2522           DEBUG ((EFI_D_WARN,
2523             "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",
2524             __FUNCTION__, EFI_SCSI_PAGE_CODE_SUPPORTED_VPD));
2525           PageLength = 0;
2526         }
2527 
2528         //
2529         // Locate the code for the Block Limits VPD page
2530         //
2531         for (Index = 0; Index < PageLength; Index++) {
2532           //
2533           // Sanity check
2534           //
2535           if ((Index > 0) &&
2536               (SupportedVpdPages->SupportedVpdPageList[Index] <=
2537                SupportedVpdPages->SupportedVpdPageList[Index - 1])) {
2538             DEBUG ((EFI_D_WARN,
2539               "%a: non-ascending code in Supported VPD Pages page @ %u\n",
2540               __FUNCTION__, Index));
2541             Index = 0;
2542             PageLength = 0;
2543             break;
2544           }
2545 
2546           if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {
2547             break;
2548           }
2549         }
2550 
2551         //
2552         // Query the Block Limits VPD page
2553         //
2554         if (Index < PageLength) {
2555           BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
2556           if (BlockLimits == NULL) {
2557             FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2558             *NeedRetry = FALSE;
2559             return EFI_DEVICE_ERROR;
2560           }
2561           ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
2562           InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE);
2563           SenseDataLength   = 0;
2564           Status = ScsiInquiryCommandEx (
2565                      ScsiDiskDevice->ScsiIo,
2566                      SCSI_DISK_TIMEOUT,
2567                      NULL,
2568                      &SenseDataLength,
2569                      &HostAdapterStatus,
2570                      &TargetStatus,
2571                      (VOID *) BlockLimits,
2572                      &InquiryDataLength,
2573                      TRUE,
2574                      EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
2575                      );
2576           if (!EFI_ERROR (Status)) {
2577             ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity =
2578               (BlockLimits->OptimalTransferLengthGranularity2 << 8) |
2579                BlockLimits->OptimalTransferLengthGranularity1;
2580 
2581             ScsiDiskDevice->UnmapInfo.MaxLbaCnt =
2582               (BlockLimits->MaximumUnmapLbaCount4 << 24) |
2583               (BlockLimits->MaximumUnmapLbaCount3 << 16) |
2584               (BlockLimits->MaximumUnmapLbaCount2 << 8)  |
2585               BlockLimits->MaximumUnmapLbaCount1;
2586             ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt =
2587               (BlockLimits->MaximumUnmapBlockDescriptorCount4 << 24) |
2588               (BlockLimits->MaximumUnmapBlockDescriptorCount3 << 16) |
2589               (BlockLimits->MaximumUnmapBlockDescriptorCount2 << 8)  |
2590               BlockLimits->MaximumUnmapBlockDescriptorCount1;
2591             ScsiDiskDevice->EraseBlock.EraseLengthGranularity =
2592               (BlockLimits->OptimalUnmapGranularity4 << 24) |
2593               (BlockLimits->OptimalUnmapGranularity3 << 16) |
2594               (BlockLimits->OptimalUnmapGranularity2 << 8)  |
2595               BlockLimits->OptimalUnmapGranularity1;
2596             if (BlockLimits->UnmapGranularityAlignmentValid != 0) {
2597               ScsiDiskDevice->UnmapInfo.GranularityAlignment =
2598                 (BlockLimits->UnmapGranularityAlignment4 << 24) |
2599                 (BlockLimits->UnmapGranularityAlignment3 << 16) |
2600                 (BlockLimits->UnmapGranularityAlignment2 << 8)  |
2601                 BlockLimits->UnmapGranularityAlignment1;
2602             }
2603 
2604             if (ScsiDiskDevice->EraseBlock.EraseLengthGranularity == 0) {
2605               //
2606               // A value of 0 indicates that the optimal unmap granularity is
2607               // not reported.
2608               //
2609               ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
2610             }
2611 
2612             ScsiDiskDevice->BlockLimitsVpdSupported = TRUE;
2613           }
2614 
2615           FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
2616         }
2617       }
2618 
2619       FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
2620     }
2621   }
2622 
2623   if (!EFI_ERROR (Status)) {
2624     return EFI_SUCCESS;
2625 
2626   } else if (Status == EFI_NOT_READY) {
2627     *NeedRetry = TRUE;
2628     return EFI_DEVICE_ERROR;
2629 
2630   } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
2631     *NeedRetry = FALSE;
2632     return EFI_DEVICE_ERROR;
2633   }
2634   //
2635   // go ahead to check HostAdapterStatus and TargetStatus
2636   // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
2637   //
2638 
2639   Status = CheckHostAdapterStatus (HostAdapterStatus);
2640   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2641     *NeedRetry = TRUE;
2642     return EFI_DEVICE_ERROR;
2643   } else if (Status == EFI_DEVICE_ERROR) {
2644       //
2645       // reset the scsi channel
2646       //
2647     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2648     *NeedRetry = FALSE;
2649     return EFI_DEVICE_ERROR;
2650   }
2651 
2652   Status = CheckTargetStatus (TargetStatus);
2653   if (Status == EFI_NOT_READY) {
2654     //
2655     // reset the scsi device
2656     //
2657     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2658     *NeedRetry = TRUE;
2659     return EFI_DEVICE_ERROR;
2660 
2661   } else if (Status == EFI_DEVICE_ERROR) {
2662     *NeedRetry = FALSE;
2663     return EFI_DEVICE_ERROR;
2664   }
2665 
2666   //
2667   // if goes here, meant ScsiInquiryCommand() failed.
2668   // if ScsiDiskRequestSenseKeys() succeeds at last,
2669   // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
2670   //
2671   MaxRetry = 3;
2672   for (Index = 0; Index < MaxRetry; Index++) {
2673     Status = ScsiDiskRequestSenseKeys (
2674               ScsiDiskDevice,
2675               NeedRetry,
2676               &SenseDataArray,
2677               &NumberOfSenseKeys,
2678               TRUE
2679               );
2680     if (!EFI_ERROR (Status)) {
2681       *NeedRetry = TRUE;
2682       return EFI_DEVICE_ERROR;
2683     }
2684 
2685     if (!*NeedRetry) {
2686       return EFI_DEVICE_ERROR;
2687     }
2688   }
2689   //
2690   // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2691   // set *NeedRetry = FALSE to avoid the outside caller try again.
2692   //
2693   *NeedRetry = FALSE;
2694   return EFI_DEVICE_ERROR;
2695 }
2696 
2697 /**
2698   To test device.
2699 
2700   When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
2701   When Test Unit Ready command encounters any error caused by host adapter or
2702   target, return error without retrieving Sense Keys.
2703 
2704   @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV
2705   @param  NeedRetry          The pointer of flag indicates try again
2706   @param  SenseDataArray     The pointer of an array of sense data
2707   @param  NumberOfSenseKeys  The pointer of the number of sense data array
2708 
2709   @retval EFI_DEVICE_ERROR   Indicates that error occurs
2710   @retval EFI_SUCCESS        Successfully to test unit
2711 
2712 **/
2713 EFI_STATUS
2714 ScsiDiskTestUnitReady (
2715   IN  SCSI_DISK_DEV         *ScsiDiskDevice,
2716   OUT BOOLEAN               *NeedRetry,
2717   OUT EFI_SCSI_SENSE_DATA   **SenseDataArray,
2718   OUT UINTN                 *NumberOfSenseKeys
2719   )
2720 {
2721   EFI_STATUS  Status;
2722   UINT8       SenseDataLength;
2723   UINT8       HostAdapterStatus;
2724   UINT8       TargetStatus;
2725   UINT8       Index;
2726   UINT8       MaxRetry;
2727 
2728   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
2729   *NumberOfSenseKeys  = 0;
2730 
2731   //
2732   // Parameter 3 and 4: do not require sense data, retrieve it when needed.
2733   //
2734   Status = ScsiTestUnitReadyCommand (
2735             ScsiDiskDevice->ScsiIo,
2736             SCSI_DISK_TIMEOUT,
2737             ScsiDiskDevice->SenseData,
2738             &SenseDataLength,
2739             &HostAdapterStatus,
2740             &TargetStatus
2741             );
2742   //
2743   // no need to check HostAdapterStatus and TargetStatus
2744   //
2745   if (Status == EFI_NOT_READY) {
2746     *NeedRetry = TRUE;
2747     return EFI_DEVICE_ERROR;
2748 
2749   } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
2750     *NeedRetry = FALSE;
2751     return EFI_DEVICE_ERROR;
2752   }
2753   //
2754   // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
2755   //
2756 
2757   Status = CheckHostAdapterStatus (HostAdapterStatus);
2758   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
2759     *NeedRetry = TRUE;
2760     return EFI_DEVICE_ERROR;
2761 
2762   } else if (Status == EFI_DEVICE_ERROR) {
2763     //
2764     // reset the scsi channel
2765     //
2766     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
2767     *NeedRetry = FALSE;
2768     return EFI_DEVICE_ERROR;
2769   }
2770 
2771   Status = CheckTargetStatus (TargetStatus);
2772   if (Status == EFI_NOT_READY) {
2773     //
2774     // reset the scsi device
2775     //
2776     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
2777     *NeedRetry = TRUE;
2778     return EFI_DEVICE_ERROR;
2779 
2780   } else if (Status == EFI_DEVICE_ERROR) {
2781     *NeedRetry = FALSE;
2782     return EFI_DEVICE_ERROR;
2783   }
2784 
2785   if (SenseDataLength != 0) {
2786     *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA);
2787     *SenseDataArray    = ScsiDiskDevice->SenseData;
2788     return EFI_SUCCESS;
2789   }
2790 
2791   MaxRetry = 3;
2792   for (Index = 0; Index < MaxRetry; Index++) {
2793     Status = ScsiDiskRequestSenseKeys (
2794               ScsiDiskDevice,
2795               NeedRetry,
2796               SenseDataArray,
2797               NumberOfSenseKeys,
2798               FALSE
2799               );
2800     if (!EFI_ERROR (Status)) {
2801       return EFI_SUCCESS;
2802     }
2803 
2804     if (!*NeedRetry) {
2805       return EFI_DEVICE_ERROR;
2806     }
2807   }
2808   //
2809   // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2810   // set *NeedRetry = FALSE to avoid the outside caller try again.
2811   //
2812   *NeedRetry = FALSE;
2813   return EFI_DEVICE_ERROR;
2814 }
2815 
2816 /**
2817   Parsing Sense Keys which got from request sense command.
2818 
2819   @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV
2820   @param  SenseData          The pointer of EFI_SCSI_SENSE_DATA
2821   @param  NumberOfSenseKeys  The number of sense key
2822   @param  Action             The pointer of action which indicates what is need to do next
2823 
2824   @retval EFI_DEVICE_ERROR   Indicates that error occurs
2825   @retval EFI_SUCCESS        Successfully to complete the parsing
2826 
2827 **/
2828 EFI_STATUS
2829 DetectMediaParsingSenseKeys (
2830   OUT  SCSI_DISK_DEV           *ScsiDiskDevice,
2831   IN   EFI_SCSI_SENSE_DATA     *SenseData,
2832   IN   UINTN                   NumberOfSenseKeys,
2833   OUT  UINTN                   *Action
2834   )
2835 {
2836   BOOLEAN RetryLater;
2837 
2838   //
2839   // Default is to read capacity, unless..
2840   //
2841   *Action = ACTION_READ_CAPACITY;
2842 
2843   if (NumberOfSenseKeys == 0) {
2844     if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
2845       *Action = ACTION_NO_ACTION;
2846     }
2847     return EFI_SUCCESS;
2848   }
2849 
2850   if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
2851     //
2852     // No Sense Key returned from last submitted command
2853     //
2854     if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
2855       *Action = ACTION_NO_ACTION;
2856     }
2857     return EFI_SUCCESS;
2858   }
2859 
2860   if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
2861     ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
2862     ScsiDiskDevice->BlkIo.Media->LastBlock    = 0;
2863     *Action = ACTION_NO_ACTION;
2864     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));
2865     return EFI_SUCCESS;
2866   }
2867 
2868   if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
2869     ScsiDiskDevice->BlkIo.Media->MediaId++;
2870     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
2871     return EFI_SUCCESS;
2872   }
2873 
2874   if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
2875     *Action = ACTION_RETRY_COMMAND_LATER;
2876     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
2877     return EFI_SUCCESS;
2878   }
2879 
2880   if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
2881     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));
2882     *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
2883     return EFI_DEVICE_ERROR;
2884   }
2885 
2886   if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
2887     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));
2888     *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
2889     return EFI_DEVICE_ERROR;
2890   }
2891 
2892   if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
2893     if (RetryLater) {
2894       *Action = ACTION_RETRY_COMMAND_LATER;
2895       DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
2896       return EFI_SUCCESS;
2897     }
2898     *Action = ACTION_NO_ACTION;
2899     return EFI_DEVICE_ERROR;
2900   }
2901 
2902   *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
2903   DEBUG ((EFI_D_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
2904   return EFI_SUCCESS;
2905 }
2906 
2907 
2908 /**
2909   Send read capacity command to device and get the device parameter.
2910 
2911   @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV
2912   @param  NeedRetry          The pointer of flag indicates if need a retry
2913   @param  SenseDataArray     The pointer of an array of sense data
2914   @param  NumberOfSenseKeys  The number of sense key
2915 
2916   @retval EFI_DEVICE_ERROR   Indicates that error occurs
2917   @retval EFI_SUCCESS        Successfully to read capacity or sense data is received.
2918 
2919 **/
2920 EFI_STATUS
2921 ScsiDiskReadCapacity (
2922   IN  OUT  SCSI_DISK_DEV           *ScsiDiskDevice,
2923       OUT  BOOLEAN                 *NeedRetry,
2924       OUT  EFI_SCSI_SENSE_DATA     **SenseDataArray,
2925       OUT  UINTN                   *NumberOfSenseKeys
2926   )
2927 {
2928   UINT8                         HostAdapterStatus;
2929   UINT8                         TargetStatus;
2930   EFI_STATUS                    CommandStatus;
2931   EFI_STATUS                    Status;
2932   UINT8                         Index;
2933   UINT8                         MaxRetry;
2934   UINT8                         SenseDataLength;
2935   UINT32                        DataLength10;
2936   UINT32                        DataLength16;
2937   EFI_SCSI_DISK_CAPACITY_DATA   *CapacityData10;
2938   EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
2939 
2940   CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
2941   if (CapacityData10 == NULL) {
2942     *NeedRetry = FALSE;
2943     return EFI_DEVICE_ERROR;
2944   }
2945   CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
2946   if (CapacityData16 == NULL) {
2947     FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
2948     *NeedRetry = FALSE;
2949     return EFI_DEVICE_ERROR;
2950   }
2951 
2952   SenseDataLength       = 0;
2953   DataLength10          = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
2954   DataLength16          = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
2955   ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
2956   ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
2957 
2958   *NumberOfSenseKeys  = 0;
2959   *NeedRetry          = FALSE;
2960 
2961   //
2962   // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
2963   // 16 byte command should be used to access large hard disk >2TB
2964   //
2965   CommandStatus = ScsiReadCapacityCommand (
2966                     ScsiDiskDevice->ScsiIo,
2967                     SCSI_DISK_TIMEOUT,
2968                     NULL,
2969                     &SenseDataLength,
2970                     &HostAdapterStatus,
2971                     &TargetStatus,
2972                     (VOID *) CapacityData10,
2973                     &DataLength10,
2974                     FALSE
2975                     );
2976 
2977   ScsiDiskDevice->Cdb16Byte = FALSE;
2978   if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) &&
2979       (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff)) {
2980     //
2981     // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
2982     //
2983     ScsiDiskDevice->Cdb16Byte = TRUE;
2984     //
2985     // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
2986     // and LowestAlignedLba
2987     //
2988     CommandStatus = ScsiReadCapacity16Command (
2989                       ScsiDiskDevice->ScsiIo,
2990                       SCSI_DISK_TIMEOUT,
2991                       NULL,
2992                       &SenseDataLength,
2993                       &HostAdapterStatus,
2994                       &TargetStatus,
2995                       (VOID *) CapacityData16,
2996                       &DataLength16,
2997                       FALSE
2998                       );
2999   }
3000 
3001     //
3002     // no need to check HostAdapterStatus and TargetStatus
3003     //
3004    if (CommandStatus == EFI_SUCCESS) {
3005      GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16);
3006      FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
3007      FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
3008      return EFI_SUCCESS;
3009    }
3010 
3011    FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
3012    FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
3013 
3014    if (CommandStatus == EFI_NOT_READY) {
3015      *NeedRetry = TRUE;
3016      return EFI_DEVICE_ERROR;
3017    } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
3018      *NeedRetry = FALSE;
3019      return EFI_DEVICE_ERROR;
3020    }
3021 
3022    //
3023    // go ahead to check HostAdapterStatus and TargetStatus
3024    // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3025    //
3026 
3027    Status = CheckHostAdapterStatus (HostAdapterStatus);
3028    if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3029      *NeedRetry = TRUE;
3030      return EFI_DEVICE_ERROR;
3031 
3032    } else if (Status == EFI_DEVICE_ERROR) {
3033     //
3034     // reset the scsi channel
3035     //
3036     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
3037     *NeedRetry = FALSE;
3038     return EFI_DEVICE_ERROR;
3039   }
3040 
3041   Status = CheckTargetStatus (TargetStatus);
3042   if (Status == EFI_NOT_READY) {
3043     //
3044     // reset the scsi device
3045     //
3046     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3047     *NeedRetry = TRUE;
3048     return EFI_DEVICE_ERROR;
3049 
3050   } else if (Status == EFI_DEVICE_ERROR) {
3051     *NeedRetry = FALSE;
3052     return EFI_DEVICE_ERROR;
3053   }
3054 
3055   //
3056   // if goes here, meant ScsiReadCapacityCommand() failed.
3057   // if ScsiDiskRequestSenseKeys() succeeds at last,
3058   // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
3059   //
3060   MaxRetry = 3;
3061   for (Index = 0; Index < MaxRetry; Index++) {
3062 
3063     Status = ScsiDiskRequestSenseKeys (
3064               ScsiDiskDevice,
3065               NeedRetry,
3066               SenseDataArray,
3067               NumberOfSenseKeys,
3068               TRUE
3069               );
3070     if (!EFI_ERROR (Status)) {
3071       return EFI_SUCCESS;
3072     }
3073 
3074     if (!*NeedRetry) {
3075       return EFI_DEVICE_ERROR;
3076     }
3077   }
3078   //
3079   // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
3080   // set *NeedRetry = FALSE to avoid the outside caller try again.
3081   //
3082   *NeedRetry = FALSE;
3083   return EFI_DEVICE_ERROR;
3084 }
3085 
3086 /**
3087   Check the HostAdapter status and re-interpret it in EFI_STATUS.
3088 
3089   @param  HostAdapterStatus  Host Adapter status
3090 
3091   @retval  EFI_SUCCESS       Host adapter is OK.
3092   @retval  EFI_TIMEOUT       Timeout.
3093   @retval  EFI_NOT_READY     Adapter NOT ready.
3094   @retval  EFI_DEVICE_ERROR  Adapter device error.
3095 
3096 **/
3097 EFI_STATUS
3098 CheckHostAdapterStatus (
3099   IN UINT8   HostAdapterStatus
3100   )
3101 {
3102   switch (HostAdapterStatus) {
3103   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
3104     return EFI_SUCCESS;
3105 
3106   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
3107   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
3108   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
3109     return EFI_TIMEOUT;
3110 
3111   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
3112   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
3113   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
3114   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
3115   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
3116     return EFI_NOT_READY;
3117 
3118   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
3119   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
3120     return EFI_DEVICE_ERROR;
3121 
3122   default:
3123     return EFI_SUCCESS;
3124   }
3125 }
3126 
3127 
3128 /**
3129   Check the target status and re-interpret it in EFI_STATUS.
3130 
3131   @param  TargetStatus  Target status
3132 
3133   @retval EFI_NOT_READY       Device is NOT ready.
3134   @retval EFI_DEVICE_ERROR
3135   @retval EFI_SUCCESS
3136 
3137 **/
3138 EFI_STATUS
3139 CheckTargetStatus (
3140   IN  UINT8   TargetStatus
3141   )
3142 {
3143   switch (TargetStatus) {
3144   case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
3145   case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
3146   case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
3147     return EFI_SUCCESS;
3148 
3149   case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
3150   case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
3151   case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
3152   case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
3153     return EFI_NOT_READY;
3154 
3155   case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
3156     return EFI_DEVICE_ERROR;
3157 
3158   default:
3159     return EFI_SUCCESS;
3160   }
3161 }
3162 
3163 
3164 /**
3165   Retrieve all sense keys from the device.
3166 
3167   When encountering error during the process, if retrieve sense keys before
3168   error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
3169   and NeedRetry set to FALSE; otherwise, return the proper return status.
3170 
3171   @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV
3172   @param  NeedRetry          The pointer of flag indicates if need a retry
3173   @param  SenseDataArray     The pointer of an array of sense data
3174   @param  NumberOfSenseKeys  The number of sense key
3175   @param  AskResetIfError    The flag indicates if need reset when error occurs
3176 
3177   @retval EFI_DEVICE_ERROR   Indicates that error occurs
3178   @retval EFI_SUCCESS        Successfully to request sense key
3179 
3180 **/
3181 EFI_STATUS
3182 ScsiDiskRequestSenseKeys (
3183   IN  OUT  SCSI_DISK_DEV           *ScsiDiskDevice,
3184       OUT  BOOLEAN                 *NeedRetry,
3185       OUT  EFI_SCSI_SENSE_DATA     **SenseDataArray,
3186       OUT  UINTN                   *NumberOfSenseKeys,
3187   IN       BOOLEAN                 AskResetIfError
3188   )
3189 {
3190   EFI_SCSI_SENSE_DATA *PtrSenseData;
3191   UINT8               SenseDataLength;
3192   BOOLEAN             SenseReq;
3193   EFI_STATUS          Status;
3194   EFI_STATUS          FallStatus;
3195   UINT8               HostAdapterStatus;
3196   UINT8               TargetStatus;
3197 
3198   FallStatus      = EFI_SUCCESS;
3199   SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA);
3200 
3201   ZeroMem (
3202     ScsiDiskDevice->SenseData,
3203     sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
3204     );
3205 
3206   *NumberOfSenseKeys  = 0;
3207   *SenseDataArray     = ScsiDiskDevice->SenseData;
3208   Status              = EFI_SUCCESS;
3209   PtrSenseData        = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));
3210   if (PtrSenseData == NULL) {
3211     return EFI_DEVICE_ERROR;
3212   }
3213 
3214   for (SenseReq = TRUE; SenseReq;) {
3215     ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
3216     Status = ScsiRequestSenseCommand (
3217               ScsiDiskDevice->ScsiIo,
3218               SCSI_DISK_TIMEOUT,
3219               PtrSenseData,
3220               &SenseDataLength,
3221               &HostAdapterStatus,
3222               &TargetStatus
3223               );
3224      if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
3225         FallStatus = EFI_SUCCESS;
3226 
3227      } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
3228        *NeedRetry  = TRUE;
3229        FallStatus  = EFI_DEVICE_ERROR;
3230 
3231      } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
3232        *NeedRetry  = FALSE;
3233        FallStatus  = EFI_DEVICE_ERROR;
3234 
3235      } else if (Status == EFI_DEVICE_ERROR) {
3236         if (AskResetIfError) {
3237           ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
3238         }
3239 
3240         FallStatus = EFI_DEVICE_ERROR;
3241     }
3242 
3243     if (EFI_ERROR (FallStatus)) {
3244       if (*NumberOfSenseKeys != 0) {
3245         *NeedRetry = FALSE;
3246         Status = EFI_SUCCESS;
3247         goto EXIT;
3248       } else {
3249         Status = EFI_DEVICE_ERROR;
3250         goto EXIT;
3251       }
3252     }
3253 
3254     CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);
3255     (*NumberOfSenseKeys) += 1;
3256 
3257     //
3258     // no more sense key or number of sense keys exceeds predefined,
3259     // skip the loop.
3260     //
3261     if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
3262         (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
3263       SenseReq = FALSE;
3264     }
3265   }
3266 
3267 EXIT:
3268   FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
3269   return Status;
3270 }
3271 
3272 
3273 /**
3274   Get information from media read capacity command.
3275 
3276   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
3277   @param  Capacity10      The pointer of EFI_SCSI_DISK_CAPACITY_DATA
3278   @param  Capacity16      The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
3279 
3280 **/
3281 VOID
3282 GetMediaInfo (
3283   IN OUT SCSI_DISK_DEV                  *ScsiDiskDevice,
3284   IN     EFI_SCSI_DISK_CAPACITY_DATA    *Capacity10,
3285   IN     EFI_SCSI_DISK_CAPACITY_DATA16  *Capacity16
3286   )
3287 {
3288   UINT8       *Ptr;
3289 
3290   if (!ScsiDiskDevice->Cdb16Byte) {
3291     ScsiDiskDevice->BlkIo.Media->LastBlock =  ((UINT32) Capacity10->LastLba3 << 24) |
3292                                               (Capacity10->LastLba2 << 16) |
3293                                               (Capacity10->LastLba1 << 8)  |
3294                                                Capacity10->LastLba0;
3295 
3296     ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |
3297                                              (Capacity10->BlockSize2 << 16) |
3298                                              (Capacity10->BlockSize1 << 8)  |
3299                                               Capacity10->BlockSize0;
3300     ScsiDiskDevice->BlkIo.Media->LowestAlignedLba               = 0;
3301     ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock  = 0;
3302     if (!ScsiDiskDevice->BlockLimitsVpdSupported) {
3303       ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32) ScsiDiskDevice->BlkIo.Media->LastBlock;
3304     }
3305   } else {
3306     Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;
3307     *Ptr++ = Capacity16->LastLba0;
3308     *Ptr++ = Capacity16->LastLba1;
3309     *Ptr++ = Capacity16->LastLba2;
3310     *Ptr++ = Capacity16->LastLba3;
3311     *Ptr++ = Capacity16->LastLba4;
3312     *Ptr++ = Capacity16->LastLba5;
3313     *Ptr++ = Capacity16->LastLba6;
3314     *Ptr   = Capacity16->LastLba7;
3315 
3316     ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |
3317                                              (Capacity16->BlockSize2 << 16) |
3318                                              (Capacity16->BlockSize1 << 8)  |
3319                                               Capacity16->BlockSize0;
3320 
3321     ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) |
3322                                                      Capacity16->LowestAlignLogic1;
3323     ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock  = (1 << Capacity16->LogicPerPhysical);
3324     if (!ScsiDiskDevice->BlockLimitsVpdSupported) {
3325       if (ScsiDiskDevice->BlkIo.Media->LastBlock > (UINT32) -1) {
3326         ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32) -1;
3327       } else {
3328         ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32) ScsiDiskDevice->BlkIo.Media->LastBlock;
3329       }
3330     }
3331   }
3332 
3333   ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
3334 }
3335 
3336 /**
3337   Parse Inquiry data.
3338 
3339   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
3340 
3341 **/
3342 VOID
3343 ParseInquiryData (
3344   IN OUT SCSI_DISK_DEV   *ScsiDiskDevice
3345   )
3346 {
3347   ScsiDiskDevice->FixedDevice               = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);
3348   ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);
3349 }
3350 
3351 /**
3352   Read sector from SCSI Disk.
3353 
3354   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
3355   @param  Buffer          The buffer to fill in the read out data
3356   @param  Lba             Logic block address
3357   @param  NumberOfBlocks  The number of blocks to read
3358 
3359   @retval EFI_DEVICE_ERROR  Indicates a device error.
3360   @retval EFI_SUCCESS       Operation is successful.
3361 
3362 **/
3363 EFI_STATUS
3364 ScsiDiskReadSectors (
3365   IN   SCSI_DISK_DEV     *ScsiDiskDevice,
3366   OUT  VOID              *Buffer,
3367   IN   EFI_LBA           Lba,
3368   IN   UINTN             NumberOfBlocks
3369   )
3370 {
3371   UINTN               BlocksRemaining;
3372   UINT8               *PtrBuffer;
3373   UINT32              BlockSize;
3374   UINT32              ByteCount;
3375   UINT32              MaxBlock;
3376   UINT32              SectorCount;
3377   UINT32              NextSectorCount;
3378   UINT64              Timeout;
3379   EFI_STATUS          Status;
3380   UINT8               Index;
3381   UINT8               MaxRetry;
3382   BOOLEAN             NeedRetry;
3383 
3384   Status            = EFI_SUCCESS;
3385 
3386   BlocksRemaining   = NumberOfBlocks;
3387   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;
3388 
3389   //
3390   // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3391   //
3392   if (!ScsiDiskDevice->Cdb16Byte) {
3393     MaxBlock         = 0xFFFF;
3394   } else {
3395     MaxBlock         = 0xFFFFFFFF;
3396   }
3397 
3398   PtrBuffer = Buffer;
3399 
3400   while (BlocksRemaining > 0) {
3401 
3402     if (BlocksRemaining <= MaxBlock) {
3403       if (!ScsiDiskDevice->Cdb16Byte) {
3404         SectorCount = (UINT16) BlocksRemaining;
3405       } else {
3406         SectorCount = (UINT32) BlocksRemaining;
3407       }
3408     } else {
3409       SectorCount = MaxBlock;
3410     }
3411 
3412     ByteCount = SectorCount * BlockSize;
3413     //
3414     // |------------------------|-----------------|------------------|-----------------|
3415     // |   ATA Transfer Mode    |  Transfer Rate  |  SCSI Interface  |  Transfer Rate  |
3416     // |------------------------|-----------------|------------------|-----------------|
3417     // |       PIO Mode 0       |  3.3Mbytes/sec  |     SCSI-1       |    5Mbytes/sec  |
3418     // |------------------------|-----------------|------------------|-----------------|
3419     // |       PIO Mode 1       |  5.2Mbytes/sec  |    Fast SCSI     |   10Mbytes/sec  |
3420     // |------------------------|-----------------|------------------|-----------------|
3421     // |       PIO Mode 2       |  8.3Mbytes/sec  |  Fast-Wide SCSI  |   20Mbytes/sec  |
3422     // |------------------------|-----------------|------------------|-----------------|
3423     // |       PIO Mode 3       | 11.1Mbytes/sec  |    Ultra SCSI    |   20Mbytes/sec  |
3424     // |------------------------|-----------------|------------------|-----------------|
3425     // |       PIO Mode 4       | 16.6Mbytes/sec  |  Ultra Wide SCSI |   40Mbytes/sec  |
3426     // |------------------------|-----------------|------------------|-----------------|
3427     // | Single-word DMA Mode 0 |  2.1Mbytes/sec  |    Ultra2 SCSI   |   40Mbytes/sec  |
3428     // |------------------------|-----------------|------------------|-----------------|
3429     // | Single-word DMA Mode 1 |  4.2Mbytes/sec  | Ultra2 Wide SCSI |   80Mbytes/sec  |
3430     // |------------------------|-----------------|------------------|-----------------|
3431     // | Single-word DMA Mode 2 |  8.4Mbytes/sec  |    Ultra3 SCSI   |  160Mbytes/sec  |
3432     // |------------------------|-----------------|------------------|-----------------|
3433     // | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |  Ultra-320 SCSI  |  320Mbytes/sec  |
3434     // |------------------------|-----------------|------------------|-----------------|
3435     // | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |  Ultra-640 SCSI  |  640Mbytes/sec  |
3436     // |------------------------|-----------------|------------------|-----------------|
3437     //
3438     // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3439     // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3440     // From the above table, we could know 2.1Mbytes per second is lowest one.
3441     // The timeout value is rounded up to nearest integer and here an additional 30s is added
3442     // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3443     // commands in the Standby/Idle mode.
3444     //
3445     Timeout   = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
3446 
3447     MaxRetry  = 2;
3448     for (Index = 0; Index < MaxRetry; Index++) {
3449       if (!ScsiDiskDevice->Cdb16Byte) {
3450         Status = ScsiDiskRead10 (
3451                   ScsiDiskDevice,
3452                   &NeedRetry,
3453                   Timeout,
3454                   PtrBuffer,
3455                   &ByteCount,
3456                   (UINT32) Lba,
3457                   SectorCount
3458                   );
3459       } else {
3460         Status = ScsiDiskRead16 (
3461                   ScsiDiskDevice,
3462                   &NeedRetry,
3463                   Timeout,
3464                   PtrBuffer,
3465                   &ByteCount,
3466                   Lba,
3467                   SectorCount
3468                   );
3469       }
3470       if (!EFI_ERROR (Status)) {
3471         break;
3472       }
3473 
3474       if (!NeedRetry) {
3475         return EFI_DEVICE_ERROR;
3476       }
3477 
3478       //
3479       // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
3480       // lowered ByteCount on output, we must make sure that we lower
3481       // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3482       // it is invalid to request more sectors in the CDB than the entire
3483       // transfer (ie. ByteCount) can carry.
3484       //
3485       // In addition, ByteCount is only expected to go down, or stay unchanged.
3486       // Therefore we don't need to update Timeout: the original timeout should
3487       // accommodate shorter transfers too.
3488       //
3489       NextSectorCount = ByteCount / BlockSize;
3490       if (NextSectorCount < SectorCount) {
3491         SectorCount = NextSectorCount;
3492         //
3493         // Account for any rounding down.
3494         //
3495         ByteCount = SectorCount * BlockSize;
3496       }
3497     }
3498 
3499     if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
3500       return EFI_DEVICE_ERROR;
3501     }
3502 
3503     //
3504     // actual transferred sectors
3505     //
3506     SectorCount = ByteCount / BlockSize;
3507 
3508     Lba += SectorCount;
3509     PtrBuffer = PtrBuffer + SectorCount * BlockSize;
3510     BlocksRemaining -= SectorCount;
3511   }
3512 
3513   return EFI_SUCCESS;
3514 }
3515 
3516 /**
3517   Write sector to SCSI Disk.
3518 
3519   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
3520   @param  Buffer          The buffer of data to be written into SCSI Disk
3521   @param  Lba             Logic block address
3522   @param  NumberOfBlocks  The number of blocks to read
3523 
3524   @retval EFI_DEVICE_ERROR  Indicates a device error.
3525   @retval EFI_SUCCESS       Operation is successful.
3526 
3527 **/
3528 EFI_STATUS
3529 ScsiDiskWriteSectors (
3530   IN  SCSI_DISK_DEV     *ScsiDiskDevice,
3531   IN  VOID              *Buffer,
3532   IN  EFI_LBA           Lba,
3533   IN  UINTN             NumberOfBlocks
3534   )
3535 {
3536   UINTN               BlocksRemaining;
3537   UINT8               *PtrBuffer;
3538   UINT32              BlockSize;
3539   UINT32              ByteCount;
3540   UINT32              MaxBlock;
3541   UINT32              SectorCount;
3542   UINT32              NextSectorCount;
3543   UINT64              Timeout;
3544   EFI_STATUS          Status;
3545   UINT8               Index;
3546   UINT8               MaxRetry;
3547   BOOLEAN             NeedRetry;
3548 
3549   Status            = EFI_SUCCESS;
3550 
3551   BlocksRemaining   = NumberOfBlocks;
3552   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;
3553 
3554   //
3555   // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3556   //
3557   if (!ScsiDiskDevice->Cdb16Byte) {
3558     MaxBlock         = 0xFFFF;
3559   } else {
3560     MaxBlock         = 0xFFFFFFFF;
3561   }
3562 
3563   PtrBuffer = Buffer;
3564 
3565   while (BlocksRemaining > 0) {
3566 
3567     if (BlocksRemaining <= MaxBlock) {
3568       if (!ScsiDiskDevice->Cdb16Byte) {
3569         SectorCount = (UINT16) BlocksRemaining;
3570       } else {
3571         SectorCount = (UINT32) BlocksRemaining;
3572       }
3573     } else {
3574       SectorCount = MaxBlock;
3575     }
3576 
3577     ByteCount = SectorCount * BlockSize;
3578     //
3579     // |------------------------|-----------------|------------------|-----------------|
3580     // |   ATA Transfer Mode    |  Transfer Rate  |  SCSI Interface  |  Transfer Rate  |
3581     // |------------------------|-----------------|------------------|-----------------|
3582     // |       PIO Mode 0       |  3.3Mbytes/sec  |     SCSI-1       |    5Mbytes/sec  |
3583     // |------------------------|-----------------|------------------|-----------------|
3584     // |       PIO Mode 1       |  5.2Mbytes/sec  |    Fast SCSI     |   10Mbytes/sec  |
3585     // |------------------------|-----------------|------------------|-----------------|
3586     // |       PIO Mode 2       |  8.3Mbytes/sec  |  Fast-Wide SCSI  |   20Mbytes/sec  |
3587     // |------------------------|-----------------|------------------|-----------------|
3588     // |       PIO Mode 3       | 11.1Mbytes/sec  |    Ultra SCSI    |   20Mbytes/sec  |
3589     // |------------------------|-----------------|------------------|-----------------|
3590     // |       PIO Mode 4       | 16.6Mbytes/sec  |  Ultra Wide SCSI |   40Mbytes/sec  |
3591     // |------------------------|-----------------|------------------|-----------------|
3592     // | Single-word DMA Mode 0 |  2.1Mbytes/sec  |    Ultra2 SCSI   |   40Mbytes/sec  |
3593     // |------------------------|-----------------|------------------|-----------------|
3594     // | Single-word DMA Mode 1 |  4.2Mbytes/sec  | Ultra2 Wide SCSI |   80Mbytes/sec  |
3595     // |------------------------|-----------------|------------------|-----------------|
3596     // | Single-word DMA Mode 2 |  8.4Mbytes/sec  |    Ultra3 SCSI   |  160Mbytes/sec  |
3597     // |------------------------|-----------------|------------------|-----------------|
3598     // | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |  Ultra-320 SCSI  |  320Mbytes/sec  |
3599     // |------------------------|-----------------|------------------|-----------------|
3600     // | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |  Ultra-640 SCSI  |  640Mbytes/sec  |
3601     // |------------------------|-----------------|------------------|-----------------|
3602     //
3603     // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3604     // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3605     // From the above table, we could know 2.1Mbytes per second is lowest one.
3606     // The timeout value is rounded up to nearest integer and here an additional 30s is added
3607     // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3608     // commands in the Standby/Idle mode.
3609     //
3610     Timeout   = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
3611     MaxRetry  = 2;
3612     for (Index = 0; Index < MaxRetry; Index++) {
3613       if (!ScsiDiskDevice->Cdb16Byte) {
3614         Status = ScsiDiskWrite10 (
3615                   ScsiDiskDevice,
3616                   &NeedRetry,
3617                   Timeout,
3618                   PtrBuffer,
3619                   &ByteCount,
3620                   (UINT32) Lba,
3621                   SectorCount
3622                   );
3623       } else {
3624         Status = ScsiDiskWrite16 (
3625                   ScsiDiskDevice,
3626                   &NeedRetry,
3627                   Timeout,
3628                   PtrBuffer,
3629                   &ByteCount,
3630                   Lba,
3631                   SectorCount
3632                   );
3633         }
3634       if (!EFI_ERROR (Status)) {
3635         break;
3636       }
3637 
3638       if (!NeedRetry) {
3639         return EFI_DEVICE_ERROR;
3640       }
3641 
3642       //
3643       // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
3644       // has lowered ByteCount on output, we must make sure that we lower
3645       // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3646       // it is invalid to request more sectors in the CDB than the entire
3647       // transfer (ie. ByteCount) can carry.
3648       //
3649       // In addition, ByteCount is only expected to go down, or stay unchanged.
3650       // Therefore we don't need to update Timeout: the original timeout should
3651       // accommodate shorter transfers too.
3652       //
3653       NextSectorCount = ByteCount / BlockSize;
3654       if (NextSectorCount < SectorCount) {
3655         SectorCount = NextSectorCount;
3656         //
3657         // Account for any rounding down.
3658         //
3659         ByteCount = SectorCount * BlockSize;
3660       }
3661     }
3662 
3663     if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
3664       return EFI_DEVICE_ERROR;
3665     }
3666     //
3667     // actual transferred sectors
3668     //
3669     SectorCount = ByteCount / BlockSize;
3670 
3671     Lba += SectorCount;
3672     PtrBuffer = PtrBuffer + SectorCount * BlockSize;
3673     BlocksRemaining -= SectorCount;
3674   }
3675 
3676   return EFI_SUCCESS;
3677 }
3678 
3679 /**
3680   Asynchronously read sector from SCSI Disk.
3681 
3682   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV.
3683   @param  Buffer          The buffer to fill in the read out data.
3684   @param  Lba             Logic block address.
3685   @param  NumberOfBlocks  The number of blocks to read.
3686   @param  Token           A pointer to the token associated with the
3687                           non-blocking read request.
3688 
3689   @retval EFI_INVALID_PARAMETER  Token is NULL or Token->Event is NULL.
3690   @retval EFI_DEVICE_ERROR       Indicates a device error.
3691   @retval EFI_SUCCESS            Operation is successful.
3692 
3693 **/
3694 EFI_STATUS
3695 ScsiDiskAsyncReadSectors (
3696   IN   SCSI_DISK_DEV         *ScsiDiskDevice,
3697   OUT  VOID                  *Buffer,
3698   IN   EFI_LBA               Lba,
3699   IN   UINTN                 NumberOfBlocks,
3700   IN   EFI_BLOCK_IO2_TOKEN   *Token
3701   )
3702 {
3703   UINTN                 BlocksRemaining;
3704   UINT8                 *PtrBuffer;
3705   UINT32                BlockSize;
3706   UINT32                ByteCount;
3707   UINT32                MaxBlock;
3708   UINT32                SectorCount;
3709   UINT64                Timeout;
3710   SCSI_BLKIO2_REQUEST   *BlkIo2Req;
3711   EFI_STATUS            Status;
3712   EFI_TPL               OldTpl;
3713 
3714   if ((Token == NULL) || (Token->Event == NULL)) {
3715     return EFI_INVALID_PARAMETER;
3716   }
3717 
3718   BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
3719   if (BlkIo2Req == NULL) {
3720     return EFI_OUT_OF_RESOURCES;
3721   }
3722 
3723   BlkIo2Req->Token  = Token;
3724 
3725   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3726   InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);
3727   gBS->RestoreTPL (OldTpl);
3728 
3729   InitializeListHead (&BlkIo2Req->ScsiRWQueue);
3730 
3731   Status            = EFI_SUCCESS;
3732 
3733   BlocksRemaining   = NumberOfBlocks;
3734   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;
3735 
3736   //
3737   // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3738   // Command
3739   //
3740   if (!ScsiDiskDevice->Cdb16Byte) {
3741     MaxBlock         = 0xFFFF;
3742   } else {
3743     MaxBlock         = 0xFFFFFFFF;
3744   }
3745 
3746   PtrBuffer = Buffer;
3747 
3748   while (BlocksRemaining > 0) {
3749 
3750     if (BlocksRemaining <= MaxBlock) {
3751       if (!ScsiDiskDevice->Cdb16Byte) {
3752         SectorCount = (UINT16) BlocksRemaining;
3753       } else {
3754         SectorCount = (UINT32) BlocksRemaining;
3755       }
3756     } else {
3757       SectorCount = MaxBlock;
3758     }
3759 
3760     ByteCount = SectorCount * BlockSize;
3761     //
3762     // |------------------------|-----------------|------------------|-----------------|
3763     // |   ATA Transfer Mode    |  Transfer Rate  |  SCSI Interface  |  Transfer Rate  |
3764     // |------------------------|-----------------|------------------|-----------------|
3765     // |       PIO Mode 0       |  3.3Mbytes/sec  |     SCSI-1       |    5Mbytes/sec  |
3766     // |------------------------|-----------------|------------------|-----------------|
3767     // |       PIO Mode 1       |  5.2Mbytes/sec  |    Fast SCSI     |   10Mbytes/sec  |
3768     // |------------------------|-----------------|------------------|-----------------|
3769     // |       PIO Mode 2       |  8.3Mbytes/sec  |  Fast-Wide SCSI  |   20Mbytes/sec  |
3770     // |------------------------|-----------------|------------------|-----------------|
3771     // |       PIO Mode 3       | 11.1Mbytes/sec  |    Ultra SCSI    |   20Mbytes/sec  |
3772     // |------------------------|-----------------|------------------|-----------------|
3773     // |       PIO Mode 4       | 16.6Mbytes/sec  |  Ultra Wide SCSI |   40Mbytes/sec  |
3774     // |------------------------|-----------------|------------------|-----------------|
3775     // | Single-word DMA Mode 0 |  2.1Mbytes/sec  |    Ultra2 SCSI   |   40Mbytes/sec  |
3776     // |------------------------|-----------------|------------------|-----------------|
3777     // | Single-word DMA Mode 1 |  4.2Mbytes/sec  | Ultra2 Wide SCSI |   80Mbytes/sec  |
3778     // |------------------------|-----------------|------------------|-----------------|
3779     // | Single-word DMA Mode 2 |  8.4Mbytes/sec  |    Ultra3 SCSI   |  160Mbytes/sec  |
3780     // |------------------------|-----------------|------------------|-----------------|
3781     // | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |  Ultra-320 SCSI  |  320Mbytes/sec  |
3782     // |------------------------|-----------------|------------------|-----------------|
3783     // | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |  Ultra-640 SCSI  |  640Mbytes/sec  |
3784     // |------------------------|-----------------|------------------|-----------------|
3785     //
3786     // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3787     // we have to use the lowest transfer rate to calculate the possible
3788     // maximum timeout value for each operation.
3789     // From the above table, we could know 2.1Mbytes per second is lowest one.
3790     // The timeout value is rounded up to nearest integer and here an additional
3791     // 30s is added to follow ATA spec in which it mentioned that the device
3792     // may take up to 30s to respond commands in the Standby/Idle mode.
3793     //
3794     Timeout   = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
3795 
3796     if (!ScsiDiskDevice->Cdb16Byte) {
3797       Status = ScsiDiskAsyncRead10 (
3798                  ScsiDiskDevice,
3799                  Timeout,
3800                  0,
3801                  PtrBuffer,
3802                  ByteCount,
3803                  (UINT32) Lba,
3804                  SectorCount,
3805                  BlkIo2Req,
3806                  Token
3807                  );
3808     } else {
3809       Status = ScsiDiskAsyncRead16 (
3810                  ScsiDiskDevice,
3811                  Timeout,
3812                  0,
3813                  PtrBuffer,
3814                  ByteCount,
3815                  Lba,
3816                  SectorCount,
3817                  BlkIo2Req,
3818                  Token
3819                  );
3820     }
3821     if (EFI_ERROR (Status)) {
3822       //
3823       // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3824       // length of a SCSI I/O command is too large.
3825       // In this case, we retry sending the SCSI command with a data length
3826       // half of its previous value.
3827       //
3828       if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
3829         if ((MaxBlock > 1) && (SectorCount > 1)) {
3830           MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
3831           continue;
3832         }
3833       }
3834 
3835       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3836       if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
3837         //
3838         // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3839         // SCSI sub-task running. Otherwise, it will be freed in the callback
3840         // function ScsiDiskNotify().
3841         //
3842         RemoveEntryList (&BlkIo2Req->Link);
3843         FreePool (BlkIo2Req);
3844         BlkIo2Req = NULL;
3845         gBS->RestoreTPL (OldTpl);
3846 
3847         //
3848         // It is safe to return error status to the caller, since there is no
3849         // previous SCSI sub-task executing.
3850         //
3851         Status = EFI_DEVICE_ERROR;
3852         goto Done;
3853       } else {
3854         gBS->RestoreTPL (OldTpl);
3855 
3856         //
3857         // There are previous SCSI commands still running, EFI_SUCCESS should
3858         // be returned to make sure that the caller does not free resources
3859         // still using by these SCSI commands.
3860         //
3861         Status = EFI_SUCCESS;
3862         goto Done;
3863       }
3864     }
3865 
3866     //
3867     // Sectors submitted for transfer
3868     //
3869     SectorCount = ByteCount / BlockSize;
3870 
3871     Lba += SectorCount;
3872     PtrBuffer = PtrBuffer + SectorCount * BlockSize;
3873     BlocksRemaining -= SectorCount;
3874   }
3875 
3876   Status = EFI_SUCCESS;
3877 
3878 Done:
3879   if (BlkIo2Req != NULL) {
3880     BlkIo2Req->LastScsiRW = TRUE;
3881 
3882     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3883     if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
3884       RemoveEntryList (&BlkIo2Req->Link);
3885       FreePool (BlkIo2Req);
3886       BlkIo2Req = NULL;
3887 
3888       gBS->SignalEvent (Token->Event);
3889     }
3890     gBS->RestoreTPL (OldTpl);
3891   }
3892 
3893   return Status;
3894 }
3895 
3896 /**
3897   Asynchronously write sector to SCSI Disk.
3898 
3899   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV.
3900   @param  Buffer          The buffer of data to be written into SCSI Disk.
3901   @param  Lba             Logic block address.
3902   @param  NumberOfBlocks  The number of blocks to read.
3903   @param  Token           A pointer to the token associated with the
3904                           non-blocking read request.
3905 
3906   @retval EFI_INVALID_PARAMETER  Token is NULL or Token->Event is NULL
3907   @retval EFI_DEVICE_ERROR  Indicates a device error.
3908   @retval EFI_SUCCESS       Operation is successful.
3909 
3910 **/
3911 EFI_STATUS
3912 ScsiDiskAsyncWriteSectors (
3913   IN  SCSI_DISK_DEV          *ScsiDiskDevice,
3914   IN  VOID                   *Buffer,
3915   IN  EFI_LBA                Lba,
3916   IN  UINTN                  NumberOfBlocks,
3917   IN  EFI_BLOCK_IO2_TOKEN    *Token
3918   )
3919 {
3920   UINTN                 BlocksRemaining;
3921   UINT8                 *PtrBuffer;
3922   UINT32                BlockSize;
3923   UINT32                ByteCount;
3924   UINT32                MaxBlock;
3925   UINT32                SectorCount;
3926   UINT64                Timeout;
3927   SCSI_BLKIO2_REQUEST   *BlkIo2Req;
3928   EFI_STATUS            Status;
3929   EFI_TPL               OldTpl;
3930 
3931   if ((Token == NULL) || (Token->Event == NULL)) {
3932     return EFI_INVALID_PARAMETER;
3933   }
3934 
3935   BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
3936   if (BlkIo2Req == NULL) {
3937     return EFI_OUT_OF_RESOURCES;
3938   }
3939 
3940   BlkIo2Req->Token  = Token;
3941 
3942   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
3943   InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);
3944   gBS->RestoreTPL (OldTpl);
3945 
3946   InitializeListHead (&BlkIo2Req->ScsiRWQueue);
3947 
3948   Status            = EFI_SUCCESS;
3949 
3950   BlocksRemaining   = NumberOfBlocks;
3951   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;
3952 
3953   //
3954   // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3955   // Command
3956   //
3957   if (!ScsiDiskDevice->Cdb16Byte) {
3958     MaxBlock         = 0xFFFF;
3959   } else {
3960     MaxBlock         = 0xFFFFFFFF;
3961   }
3962 
3963   PtrBuffer = Buffer;
3964 
3965   while (BlocksRemaining > 0) {
3966 
3967     if (BlocksRemaining <= MaxBlock) {
3968       if (!ScsiDiskDevice->Cdb16Byte) {
3969         SectorCount = (UINT16) BlocksRemaining;
3970       } else {
3971         SectorCount = (UINT32) BlocksRemaining;
3972       }
3973     } else {
3974       SectorCount = MaxBlock;
3975     }
3976 
3977     ByteCount = SectorCount * BlockSize;
3978     //
3979     // |------------------------|-----------------|------------------|-----------------|
3980     // |   ATA Transfer Mode    |  Transfer Rate  |  SCSI Interface  |  Transfer Rate  |
3981     // |------------------------|-----------------|------------------|-----------------|
3982     // |       PIO Mode 0       |  3.3Mbytes/sec  |     SCSI-1       |    5Mbytes/sec  |
3983     // |------------------------|-----------------|------------------|-----------------|
3984     // |       PIO Mode 1       |  5.2Mbytes/sec  |    Fast SCSI     |   10Mbytes/sec  |
3985     // |------------------------|-----------------|------------------|-----------------|
3986     // |       PIO Mode 2       |  8.3Mbytes/sec  |  Fast-Wide SCSI  |   20Mbytes/sec  |
3987     // |------------------------|-----------------|------------------|-----------------|
3988     // |       PIO Mode 3       | 11.1Mbytes/sec  |    Ultra SCSI    |   20Mbytes/sec  |
3989     // |------------------------|-----------------|------------------|-----------------|
3990     // |       PIO Mode 4       | 16.6Mbytes/sec  |  Ultra Wide SCSI |   40Mbytes/sec  |
3991     // |------------------------|-----------------|------------------|-----------------|
3992     // | Single-word DMA Mode 0 |  2.1Mbytes/sec  |    Ultra2 SCSI   |   40Mbytes/sec  |
3993     // |------------------------|-----------------|------------------|-----------------|
3994     // | Single-word DMA Mode 1 |  4.2Mbytes/sec  | Ultra2 Wide SCSI |   80Mbytes/sec  |
3995     // |------------------------|-----------------|------------------|-----------------|
3996     // | Single-word DMA Mode 2 |  8.4Mbytes/sec  |    Ultra3 SCSI   |  160Mbytes/sec  |
3997     // |------------------------|-----------------|------------------|-----------------|
3998     // | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |  Ultra-320 SCSI  |  320Mbytes/sec  |
3999     // |------------------------|-----------------|------------------|-----------------|
4000     // | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |  Ultra-640 SCSI  |  640Mbytes/sec  |
4001     // |------------------------|-----------------|------------------|-----------------|
4002     //
4003     // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
4004     // we have to use the lowest transfer rate to calculate the possible
4005     // maximum timeout value for each operation.
4006     // From the above table, we could know 2.1Mbytes per second is lowest one.
4007     // The timeout value is rounded up to nearest integer and here an additional
4008     // 30s is added to follow ATA spec in which it mentioned that the device
4009     // may take up to 30s to respond commands in the Standby/Idle mode.
4010     //
4011     Timeout   = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
4012 
4013     if (!ScsiDiskDevice->Cdb16Byte) {
4014       Status = ScsiDiskAsyncWrite10 (
4015                  ScsiDiskDevice,
4016                  Timeout,
4017                  0,
4018                  PtrBuffer,
4019                  ByteCount,
4020                  (UINT32) Lba,
4021                  SectorCount,
4022                  BlkIo2Req,
4023                  Token
4024                  );
4025     } else {
4026       Status = ScsiDiskAsyncWrite16 (
4027                  ScsiDiskDevice,
4028                  Timeout,
4029                  0,
4030                  PtrBuffer,
4031                  ByteCount,
4032                  Lba,
4033                  SectorCount,
4034                  BlkIo2Req,
4035                  Token
4036                  );
4037     }
4038     if (EFI_ERROR (Status)) {
4039       //
4040       // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
4041       // length of a SCSI I/O command is too large.
4042       // In this case, we retry sending the SCSI command with a data length
4043       // half of its previous value.
4044       //
4045       if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
4046         if ((MaxBlock > 1) && (SectorCount > 1)) {
4047           MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
4048           continue;
4049         }
4050       }
4051 
4052       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4053       if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
4054         //
4055         // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
4056         // SCSI sub-task running. Otherwise, it will be freed in the callback
4057         // function ScsiDiskNotify().
4058         //
4059         RemoveEntryList (&BlkIo2Req->Link);
4060         FreePool (BlkIo2Req);
4061         BlkIo2Req = NULL;
4062         gBS->RestoreTPL (OldTpl);
4063 
4064         //
4065         // It is safe to return error status to the caller, since there is no
4066         // previous SCSI sub-task executing.
4067         //
4068         Status = EFI_DEVICE_ERROR;
4069         goto Done;
4070       } else {
4071         gBS->RestoreTPL (OldTpl);
4072 
4073         //
4074         // There are previous SCSI commands still running, EFI_SUCCESS should
4075         // be returned to make sure that the caller does not free resources
4076         // still using by these SCSI commands.
4077         //
4078         Status = EFI_SUCCESS;
4079         goto Done;
4080       }
4081     }
4082 
4083     //
4084     // Sectors submitted for transfer
4085     //
4086     SectorCount = ByteCount / BlockSize;
4087 
4088     Lba += SectorCount;
4089     PtrBuffer = PtrBuffer + SectorCount * BlockSize;
4090     BlocksRemaining -= SectorCount;
4091   }
4092 
4093   Status = EFI_SUCCESS;
4094 
4095 Done:
4096   if (BlkIo2Req != NULL) {
4097     BlkIo2Req->LastScsiRW = TRUE;
4098 
4099     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4100     if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
4101       RemoveEntryList (&BlkIo2Req->Link);
4102       FreePool (BlkIo2Req);
4103       BlkIo2Req = NULL;
4104 
4105       gBS->SignalEvent (Token->Event);
4106     }
4107     gBS->RestoreTPL (OldTpl);
4108   }
4109 
4110   return Status;
4111 }
4112 
4113 
4114 /**
4115   Submit Read(10) command.
4116 
4117   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice
4118   @param  NeedRetry          The pointer of flag indicates if needs retry if error happens
4119   @param  Timeout            The time to complete the command
4120   @param  DataBuffer         The buffer to fill with the read out data
4121   @param  DataLength         The length of buffer
4122   @param  StartLba           The start logic block address
4123   @param  SectorCount        The number of blocks to read
4124 
4125   @return  EFI_STATUS is returned by calling ScsiRead10Command().
4126 **/
4127 EFI_STATUS
4128 ScsiDiskRead10 (
4129   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
4130      OUT BOOLEAN               *NeedRetry,
4131   IN     UINT64                Timeout,
4132      OUT UINT8                 *DataBuffer,
4133   IN OUT UINT32                *DataLength,
4134   IN     UINT32                StartLba,
4135   IN     UINT32                SectorCount
4136   )
4137 {
4138   UINT8       SenseDataLength;
4139   EFI_STATUS  Status;
4140   EFI_STATUS  ReturnStatus;
4141   UINT8       HostAdapterStatus;
4142   UINT8       TargetStatus;
4143   UINTN       Action;
4144 
4145   //
4146   // Implement a backoff algorithm to resolve some compatibility issues that
4147   // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4148   // big data in a single operation.
4149   // This algorithm will at first try to execute original request. If the request fails
4150   // with media error sense data or else, it will reduce the transfer length to half and
4151   // try again till the operation succeeds or fails with one sector transfer length.
4152   //
4153 BackOff:
4154   *NeedRetry          = FALSE;
4155   Action              = ACTION_NO_ACTION;
4156   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4157   ReturnStatus = ScsiRead10Command (
4158                    ScsiDiskDevice->ScsiIo,
4159                    Timeout,
4160                    ScsiDiskDevice->SenseData,
4161                    &SenseDataLength,
4162                    &HostAdapterStatus,
4163                    &TargetStatus,
4164                    DataBuffer,
4165                    DataLength,
4166                    StartLba,
4167                    SectorCount
4168                    );
4169 
4170   if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
4171     *NeedRetry = TRUE;
4172     return EFI_DEVICE_ERROR;
4173   } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4174     *NeedRetry = FALSE;
4175     return ReturnStatus;
4176   }
4177 
4178   //
4179   // go ahead to check HostAdapterStatus and TargetStatus
4180   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4181   //
4182   Status = CheckHostAdapterStatus (HostAdapterStatus);
4183   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4184     *NeedRetry = TRUE;
4185     return EFI_DEVICE_ERROR;
4186   } else if (Status == EFI_DEVICE_ERROR) {
4187     //
4188     // reset the scsi channel
4189     //
4190     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4191     *NeedRetry = FALSE;
4192     return EFI_DEVICE_ERROR;
4193   }
4194 
4195   Status = CheckTargetStatus (TargetStatus);
4196   if (Status == EFI_NOT_READY) {
4197     //
4198     // reset the scsi device
4199     //
4200     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4201     *NeedRetry = TRUE;
4202     return EFI_DEVICE_ERROR;
4203   } else if (Status == EFI_DEVICE_ERROR) {
4204     *NeedRetry = FALSE;
4205     return EFI_DEVICE_ERROR;
4206   }
4207 
4208   if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4209     DEBUG ((EFI_D_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));
4210     Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4211     if (Action == ACTION_RETRY_COMMAND_LATER) {
4212       *NeedRetry = TRUE;
4213       return EFI_DEVICE_ERROR;
4214     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4215       if (SectorCount <= 1) {
4216         //
4217         // Jump out if the operation still fails with one sector transfer length.
4218         //
4219         *NeedRetry = FALSE;
4220         return EFI_DEVICE_ERROR;
4221       }
4222       //
4223       // Try again with half length if the sense data shows we need to retry.
4224       //
4225       SectorCount >>= 1;
4226       *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4227       goto BackOff;
4228     } else {
4229       *NeedRetry = FALSE;
4230       return EFI_DEVICE_ERROR;
4231     }
4232   }
4233 
4234   return ReturnStatus;
4235 }
4236 
4237 
4238 /**
4239   Submit Write(10) Command.
4240 
4241   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice
4242   @param  NeedRetry          The pointer of flag indicates if needs retry if error happens
4243   @param  Timeout            The time to complete the command
4244   @param  DataBuffer         The buffer to fill with the read out data
4245   @param  DataLength         The length of buffer
4246   @param  StartLba           The start logic block address
4247   @param  SectorCount        The number of blocks to write
4248 
4249   @return  EFI_STATUS is returned by calling ScsiWrite10Command().
4250 
4251 **/
4252 EFI_STATUS
4253 ScsiDiskWrite10 (
4254   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
4255      OUT BOOLEAN               *NeedRetry,
4256   IN     UINT64                Timeout,
4257   IN     UINT8                 *DataBuffer,
4258   IN OUT UINT32                *DataLength,
4259   IN     UINT32                StartLba,
4260   IN     UINT32                SectorCount
4261   )
4262 {
4263   EFI_STATUS  Status;
4264   EFI_STATUS  ReturnStatus;
4265   UINT8       SenseDataLength;
4266   UINT8       HostAdapterStatus;
4267   UINT8       TargetStatus;
4268   UINTN       Action;
4269 
4270   //
4271   // Implement a backoff algorithm to resolve some compatibility issues that
4272   // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4273   // big data in a single operation.
4274   // This algorithm will at first try to execute original request. If the request fails
4275   // with media error sense data or else, it will reduce the transfer length to half and
4276   // try again till the operation succeeds or fails with one sector transfer length.
4277   //
4278 BackOff:
4279   *NeedRetry          = FALSE;
4280   Action              = ACTION_NO_ACTION;
4281   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4282   ReturnStatus = ScsiWrite10Command (
4283                    ScsiDiskDevice->ScsiIo,
4284                    Timeout,
4285                    ScsiDiskDevice->SenseData,
4286                    &SenseDataLength,
4287                    &HostAdapterStatus,
4288                    &TargetStatus,
4289                    DataBuffer,
4290                    DataLength,
4291                    StartLba,
4292                    SectorCount
4293                    );
4294   if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
4295     *NeedRetry = TRUE;
4296     return EFI_DEVICE_ERROR;
4297   } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4298     *NeedRetry = FALSE;
4299     return ReturnStatus;
4300   }
4301 
4302   //
4303   // go ahead to check HostAdapterStatus and TargetStatus
4304   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4305   //
4306   Status = CheckHostAdapterStatus (HostAdapterStatus);
4307   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4308     *NeedRetry = TRUE;
4309     return EFI_DEVICE_ERROR;
4310   } else if (Status == EFI_DEVICE_ERROR) {
4311     //
4312     // reset the scsi channel
4313     //
4314     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4315     *NeedRetry = FALSE;
4316     return EFI_DEVICE_ERROR;
4317   }
4318 
4319   Status = CheckTargetStatus (TargetStatus);
4320   if (Status == EFI_NOT_READY) {
4321     //
4322     // reset the scsi device
4323     //
4324     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4325     *NeedRetry = TRUE;
4326     return EFI_DEVICE_ERROR;
4327   } else if (Status == EFI_DEVICE_ERROR) {
4328     *NeedRetry = FALSE;
4329     return EFI_DEVICE_ERROR;
4330   }
4331 
4332   if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4333     DEBUG ((EFI_D_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));
4334     Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4335     if (Action == ACTION_RETRY_COMMAND_LATER) {
4336       *NeedRetry = TRUE;
4337       return EFI_DEVICE_ERROR;
4338     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4339       if (SectorCount <= 1) {
4340         //
4341         // Jump out if the operation still fails with one sector transfer length.
4342         //
4343         *NeedRetry = FALSE;
4344         return EFI_DEVICE_ERROR;
4345       }
4346       //
4347       // Try again with half length if the sense data shows we need to retry.
4348       //
4349       SectorCount >>= 1;
4350       *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4351       goto BackOff;
4352     } else {
4353       *NeedRetry = FALSE;
4354       return EFI_DEVICE_ERROR;
4355     }
4356   }
4357 
4358   return ReturnStatus;
4359 }
4360 
4361 
4362 /**
4363   Submit Read(16) command.
4364 
4365   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice
4366   @param  NeedRetry          The pointer of flag indicates if needs retry if error happens
4367   @param  Timeout            The time to complete the command
4368   @param  DataBuffer         The buffer to fill with the read out data
4369   @param  DataLength         The length of buffer
4370   @param  StartLba           The start logic block address
4371   @param  SectorCount        The number of blocks to read
4372 
4373   @return  EFI_STATUS is returned by calling ScsiRead16Command().
4374 **/
4375 EFI_STATUS
4376 ScsiDiskRead16 (
4377   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
4378      OUT BOOLEAN               *NeedRetry,
4379   IN     UINT64                Timeout,
4380      OUT UINT8                 *DataBuffer,
4381   IN OUT UINT32                *DataLength,
4382   IN     UINT64                StartLba,
4383   IN     UINT32                SectorCount
4384   )
4385 {
4386   UINT8       SenseDataLength;
4387   EFI_STATUS  Status;
4388   EFI_STATUS  ReturnStatus;
4389   UINT8       HostAdapterStatus;
4390   UINT8       TargetStatus;
4391   UINTN       Action;
4392 
4393   //
4394   // Implement a backoff algorithm to resolve some compatibility issues that
4395   // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4396   // big data in a single operation.
4397   // This algorithm will at first try to execute original request. If the request fails
4398   // with media error sense data or else, it will reduce the transfer length to half and
4399   // try again till the operation succeeds or fails with one sector transfer length.
4400   //
4401 BackOff:
4402   *NeedRetry          = FALSE;
4403   Action              = ACTION_NO_ACTION;
4404   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4405   ReturnStatus = ScsiRead16Command (
4406                    ScsiDiskDevice->ScsiIo,
4407                    Timeout,
4408                    ScsiDiskDevice->SenseData,
4409                    &SenseDataLength,
4410                    &HostAdapterStatus,
4411                    &TargetStatus,
4412                    DataBuffer,
4413                    DataLength,
4414                    StartLba,
4415                    SectorCount
4416                    );
4417   if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
4418     *NeedRetry = TRUE;
4419     return EFI_DEVICE_ERROR;
4420   } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4421     *NeedRetry = FALSE;
4422     return ReturnStatus;
4423   }
4424 
4425   //
4426   // go ahead to check HostAdapterStatus and TargetStatus
4427   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4428   //
4429   Status = CheckHostAdapterStatus (HostAdapterStatus);
4430   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4431     *NeedRetry = TRUE;
4432     return EFI_DEVICE_ERROR;
4433   } else if (Status == EFI_DEVICE_ERROR) {
4434     //
4435     // reset the scsi channel
4436     //
4437     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4438     *NeedRetry = FALSE;
4439     return EFI_DEVICE_ERROR;
4440   }
4441 
4442   Status = CheckTargetStatus (TargetStatus);
4443   if (Status == EFI_NOT_READY) {
4444     //
4445     // reset the scsi device
4446     //
4447     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4448     *NeedRetry = TRUE;
4449     return EFI_DEVICE_ERROR;
4450   } else if (Status == EFI_DEVICE_ERROR) {
4451     *NeedRetry = FALSE;
4452     return EFI_DEVICE_ERROR;
4453   }
4454 
4455   if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4456     DEBUG ((EFI_D_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));
4457     Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4458     if (Action == ACTION_RETRY_COMMAND_LATER) {
4459       *NeedRetry = TRUE;
4460       return EFI_DEVICE_ERROR;
4461     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4462       if (SectorCount <= 1) {
4463         //
4464         // Jump out if the operation still fails with one sector transfer length.
4465         //
4466         *NeedRetry = FALSE;
4467         return EFI_DEVICE_ERROR;
4468       }
4469       //
4470       // Try again with half length if the sense data shows we need to retry.
4471       //
4472       SectorCount >>= 1;
4473       *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4474       goto BackOff;
4475     } else {
4476       *NeedRetry = FALSE;
4477       return EFI_DEVICE_ERROR;
4478     }
4479   }
4480 
4481   return ReturnStatus;
4482 }
4483 
4484 
4485 /**
4486   Submit Write(16) Command.
4487 
4488   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice
4489   @param  NeedRetry          The pointer of flag indicates if needs retry if error happens
4490   @param  Timeout            The time to complete the command
4491   @param  DataBuffer         The buffer to fill with the read out data
4492   @param  DataLength         The length of buffer
4493   @param  StartLba           The start logic block address
4494   @param  SectorCount        The number of blocks to write
4495 
4496   @return  EFI_STATUS is returned by calling ScsiWrite16Command().
4497 
4498 **/
4499 EFI_STATUS
4500 ScsiDiskWrite16 (
4501   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
4502      OUT BOOLEAN               *NeedRetry,
4503   IN     UINT64                Timeout,
4504   IN     UINT8                 *DataBuffer,
4505   IN OUT UINT32                *DataLength,
4506   IN     UINT64                StartLba,
4507   IN     UINT32                SectorCount
4508   )
4509 {
4510   EFI_STATUS  Status;
4511   EFI_STATUS  ReturnStatus;
4512   UINT8       SenseDataLength;
4513   UINT8       HostAdapterStatus;
4514   UINT8       TargetStatus;
4515   UINTN       Action;
4516 
4517   //
4518   // Implement a backoff algorithm to resolve some compatibility issues that
4519   // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4520   // big data in a single operation.
4521   // This algorithm will at first try to execute original request. If the request fails
4522   // with media error sense data or else, it will reduce the transfer length to half and
4523   // try again till the operation succeeds or fails with one sector transfer length.
4524   //
4525 BackOff:
4526   *NeedRetry          = FALSE;
4527   Action              = ACTION_NO_ACTION;
4528   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
4529   ReturnStatus = ScsiWrite16Command (
4530                    ScsiDiskDevice->ScsiIo,
4531                    Timeout,
4532                    ScsiDiskDevice->SenseData,
4533                    &SenseDataLength,
4534                    &HostAdapterStatus,
4535                    &TargetStatus,
4536                    DataBuffer,
4537                    DataLength,
4538                    StartLba,
4539                    SectorCount
4540                    );
4541   if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
4542     *NeedRetry = TRUE;
4543     return EFI_DEVICE_ERROR;
4544   } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
4545     *NeedRetry = FALSE;
4546     return ReturnStatus;
4547   }
4548 
4549   //
4550   // go ahead to check HostAdapterStatus and TargetStatus
4551   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4552   //
4553   Status = CheckHostAdapterStatus (HostAdapterStatus);
4554   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4555     *NeedRetry = TRUE;
4556     return EFI_DEVICE_ERROR;
4557   } else if (Status == EFI_DEVICE_ERROR) {
4558     //
4559     // reset the scsi channel
4560     //
4561     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4562     *NeedRetry = FALSE;
4563     return EFI_DEVICE_ERROR;
4564   }
4565 
4566   Status = CheckTargetStatus (TargetStatus);
4567   if (Status == EFI_NOT_READY) {
4568     //
4569     // reset the scsi device
4570     //
4571     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4572     *NeedRetry = TRUE;
4573     return EFI_DEVICE_ERROR;
4574   } else if (Status == EFI_DEVICE_ERROR) {
4575     *NeedRetry = FALSE;
4576     return EFI_DEVICE_ERROR;
4577   }
4578 
4579   if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
4580     DEBUG ((EFI_D_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));
4581     Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
4582     if (Action == ACTION_RETRY_COMMAND_LATER) {
4583       *NeedRetry = TRUE;
4584       return EFI_DEVICE_ERROR;
4585     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4586       if (SectorCount <= 1) {
4587         //
4588         // Jump out if the operation still fails with one sector transfer length.
4589         //
4590         *NeedRetry = FALSE;
4591         return EFI_DEVICE_ERROR;
4592       }
4593       //
4594       // Try again with half length if the sense data shows we need to retry.
4595       //
4596       SectorCount >>= 1;
4597       *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4598       goto BackOff;
4599     } else {
4600       *NeedRetry = FALSE;
4601       return EFI_DEVICE_ERROR;
4602     }
4603   }
4604 
4605   return ReturnStatus;
4606 }
4607 
4608 
4609 /**
4610   Internal helper notify function in which determine whether retry of a SCSI
4611   Read/Write command is needed and signal the event passed from Block I/O(2) if
4612   the SCSI I/O operation completes.
4613 
4614   @param  Event    The instance of EFI_EVENT.
4615   @param  Context  The parameter passed in.
4616 
4617 **/
4618 VOID
4619 EFIAPI
4620 ScsiDiskNotify (
4621   IN  EFI_EVENT  Event,
4622   IN  VOID       *Context
4623   )
4624 {
4625   EFI_STATUS                       Status;
4626   SCSI_ASYNC_RW_REQUEST            *Request;
4627   SCSI_DISK_DEV                    *ScsiDiskDevice;
4628   EFI_BLOCK_IO2_TOKEN              *Token;
4629   UINTN                            Action;
4630   UINT32                           OldDataLength;
4631   UINT32                           OldSectorCount;
4632   UINT8                            MaxRetry;
4633 
4634   gBS->CloseEvent (Event);
4635 
4636   Request         = (SCSI_ASYNC_RW_REQUEST *) Context;
4637   ScsiDiskDevice  = Request->ScsiDiskDevice;
4638   Token           = Request->BlkIo2Req->Token;
4639   OldDataLength   = Request->DataLength;
4640   OldSectorCount  = Request->SectorCount;
4641   MaxRetry        = 2;
4642 
4643   //
4644   // If previous sub-tasks already fails, no need to process this sub-task.
4645   //
4646   if (Token->TransactionStatus != EFI_SUCCESS) {
4647     goto Exit;
4648   }
4649 
4650   //
4651   // Check HostAdapterStatus and TargetStatus
4652   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4653   //
4654   Status = CheckHostAdapterStatus (Request->HostAdapterStatus);
4655   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
4656     if (++Request->TimesRetry > MaxRetry) {
4657       Token->TransactionStatus = EFI_DEVICE_ERROR;
4658       goto Exit;
4659     } else {
4660       goto Retry;
4661     }
4662   } else if (Status == EFI_DEVICE_ERROR) {
4663     //
4664     // reset the scsi channel
4665     //
4666     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
4667     Token->TransactionStatus = EFI_DEVICE_ERROR;
4668     goto Exit;
4669   }
4670 
4671   Status = CheckTargetStatus (Request->TargetStatus);
4672   if (Status == EFI_NOT_READY) {
4673     //
4674     // reset the scsi device
4675     //
4676     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
4677     if (++Request->TimesRetry > MaxRetry) {
4678       Token->TransactionStatus = EFI_DEVICE_ERROR;
4679       goto Exit;
4680     } else {
4681       goto Retry;
4682     }
4683   } else if (Status == EFI_DEVICE_ERROR) {
4684     Token->TransactionStatus = EFI_DEVICE_ERROR;
4685     goto Exit;
4686   }
4687 
4688   if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
4689     DEBUG ((EFI_D_ERROR, "ScsiDiskNotify: Check Condition happened!\n"));
4690 
4691     Status = DetectMediaParsingSenseKeys (
4692                ScsiDiskDevice,
4693                Request->SenseData,
4694                Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA),
4695                &Action
4696                );
4697     if (Action == ACTION_RETRY_COMMAND_LATER) {
4698       if (++Request->TimesRetry > MaxRetry) {
4699         Token->TransactionStatus = EFI_DEVICE_ERROR;
4700         goto Exit;
4701       } else {
4702         goto Retry;
4703       }
4704     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
4705       if (Request->SectorCount <= 1) {
4706         //
4707         // Jump out if the operation still fails with one sector transfer
4708         // length.
4709         //
4710         Token->TransactionStatus = EFI_DEVICE_ERROR;
4711         goto Exit;
4712       }
4713       //
4714       // Try again with two half length request if the sense data shows we need
4715       // to retry.
4716       //
4717       Request->SectorCount >>= 1;
4718       Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
4719       Request->TimesRetry  = 0;
4720 
4721       goto Retry;
4722     } else {
4723       Token->TransactionStatus = EFI_DEVICE_ERROR;
4724       goto Exit;
4725     }
4726   }
4727 
4728   //
4729   // This sub-task succeeds, no need to retry.
4730   //
4731   goto Exit;
4732 
4733 Retry:
4734   if (Request->InBuffer != NULL) {
4735     //
4736     // SCSI read command
4737     //
4738     if (!ScsiDiskDevice->Cdb16Byte) {
4739       Status = ScsiDiskAsyncRead10 (
4740                  ScsiDiskDevice,
4741                  Request->Timeout,
4742                  Request->TimesRetry,
4743                  Request->InBuffer,
4744                  Request->DataLength,
4745                  (UINT32) Request->StartLba,
4746                  Request->SectorCount,
4747                  Request->BlkIo2Req,
4748                  Token
4749                  );
4750     } else {
4751       Status = ScsiDiskAsyncRead16 (
4752                  ScsiDiskDevice,
4753                  Request->Timeout,
4754                  Request->TimesRetry,
4755                  Request->InBuffer,
4756                  Request->DataLength,
4757                  Request->StartLba,
4758                  Request->SectorCount,
4759                  Request->BlkIo2Req,
4760                  Token
4761                  );
4762     }
4763 
4764     if (EFI_ERROR (Status)) {
4765       Token->TransactionStatus = EFI_DEVICE_ERROR;
4766       goto Exit;
4767     } else if (OldSectorCount != Request->SectorCount) {
4768       //
4769       // Original sub-task will be split into two new sub-tasks with smaller
4770       // DataLength
4771       //
4772       if (!ScsiDiskDevice->Cdb16Byte) {
4773         Status = ScsiDiskAsyncRead10 (
4774                    ScsiDiskDevice,
4775                    Request->Timeout,
4776                    0,
4777                    Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4778                    OldDataLength - Request->DataLength,
4779                    (UINT32) Request->StartLba + Request->SectorCount,
4780                    OldSectorCount - Request->SectorCount,
4781                    Request->BlkIo2Req,
4782                    Token
4783                    );
4784       } else {
4785         Status = ScsiDiskAsyncRead16 (
4786                    ScsiDiskDevice,
4787                    Request->Timeout,
4788                    0,
4789                    Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4790                    OldDataLength - Request->DataLength,
4791                    Request->StartLba + Request->SectorCount,
4792                    OldSectorCount - Request->SectorCount,
4793                    Request->BlkIo2Req,
4794                    Token
4795                    );
4796       }
4797       if (EFI_ERROR (Status)) {
4798         Token->TransactionStatus = EFI_DEVICE_ERROR;
4799         goto Exit;
4800       }
4801     }
4802   } else {
4803     //
4804     // SCSI write command
4805     //
4806     if (!ScsiDiskDevice->Cdb16Byte) {
4807       Status = ScsiDiskAsyncWrite10 (
4808                  ScsiDiskDevice,
4809                  Request->Timeout,
4810                  Request->TimesRetry,
4811                  Request->OutBuffer,
4812                  Request->DataLength,
4813                  (UINT32) Request->StartLba,
4814                  Request->SectorCount,
4815                  Request->BlkIo2Req,
4816                  Token
4817                  );
4818     } else {
4819       Status = ScsiDiskAsyncWrite16 (
4820                  ScsiDiskDevice,
4821                  Request->Timeout,
4822                  Request->TimesRetry,
4823                  Request->OutBuffer,
4824                  Request->DataLength,
4825                  Request->StartLba,
4826                  Request->SectorCount,
4827                  Request->BlkIo2Req,
4828                  Token
4829                  );
4830     }
4831 
4832     if (EFI_ERROR (Status)) {
4833       Token->TransactionStatus = EFI_DEVICE_ERROR;
4834       goto Exit;
4835     } else if (OldSectorCount != Request->SectorCount) {
4836       //
4837       // Original sub-task will be split into two new sub-tasks with smaller
4838       // DataLength
4839       //
4840       if (!ScsiDiskDevice->Cdb16Byte) {
4841         Status = ScsiDiskAsyncWrite10 (
4842                    ScsiDiskDevice,
4843                    Request->Timeout,
4844                    0,
4845                    Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4846                    OldDataLength - Request->DataLength,
4847                    (UINT32) Request->StartLba + Request->SectorCount,
4848                    OldSectorCount - Request->SectorCount,
4849                    Request->BlkIo2Req,
4850                    Token
4851                    );
4852       } else {
4853         Status = ScsiDiskAsyncWrite16 (
4854                    ScsiDiskDevice,
4855                    Request->Timeout,
4856                    0,
4857                    Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
4858                    OldDataLength - Request->DataLength,
4859                    Request->StartLba + Request->SectorCount,
4860                    OldSectorCount - Request->SectorCount,
4861                    Request->BlkIo2Req,
4862                    Token
4863                    );
4864       }
4865       if (EFI_ERROR (Status)) {
4866         Token->TransactionStatus = EFI_DEVICE_ERROR;
4867         goto Exit;
4868       }
4869     }
4870   }
4871 
4872 Exit:
4873   RemoveEntryList (&Request->Link);
4874   if ((IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) &&
4875       (Request->BlkIo2Req->LastScsiRW)) {
4876     //
4877     // The last SCSI R/W command of a BlockIo2 request completes
4878     //
4879     RemoveEntryList (&Request->BlkIo2Req->Link);
4880     FreePool (Request->BlkIo2Req);  // Should be freed only once
4881     gBS->SignalEvent (Token->Event);
4882   }
4883 
4884   FreePool (Request->SenseData);
4885   FreePool (Request);
4886 }
4887 
4888 
4889 /**
4890   Submit Async Read(10) command.
4891 
4892   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.
4893   @param  Timeout            The time to complete the command.
4894   @param  TimesRetry         The number of times the command has been retried.
4895   @param  DataBuffer         The buffer to fill with the read out data.
4896   @param  DataLength         The length of buffer.
4897   @param  StartLba           The start logic block address.
4898   @param  SectorCount        The number of blocks to read.
4899   @param  BlkIo2Req          The upstream BlockIo2 request.
4900   @param  Token              The pointer to the token associated with the
4901                              non-blocking read request.
4902 
4903   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
4904                                 lack of resources.
4905   @return others                Status returned by calling
4906                                 ScsiRead10CommandEx().
4907 
4908 **/
4909 EFI_STATUS
4910 ScsiDiskAsyncRead10 (
4911   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
4912   IN     UINT64                Timeout,
4913   IN     UINT8                 TimesRetry,
4914      OUT UINT8                 *DataBuffer,
4915   IN     UINT32                DataLength,
4916   IN     UINT32                StartLba,
4917   IN     UINT32                SectorCount,
4918   IN OUT SCSI_BLKIO2_REQUEST   *BlkIo2Req,
4919   IN     EFI_BLOCK_IO2_TOKEN   *Token
4920   )
4921 {
4922   EFI_STATUS                   Status;
4923   SCSI_ASYNC_RW_REQUEST        *Request;
4924   EFI_EVENT                    AsyncIoEvent;
4925   EFI_TPL                      OldTpl;
4926 
4927   AsyncIoEvent = NULL;
4928 
4929   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
4930   if (Request == NULL) {
4931     return EFI_OUT_OF_RESOURCES;
4932   }
4933 
4934   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4935   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
4936   gBS->RestoreTPL (OldTpl);
4937 
4938   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
4939   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);
4940   if (Request->SenseData == NULL) {
4941     Status = EFI_OUT_OF_RESOURCES;
4942     goto ErrorExit;
4943   }
4944 
4945   Request->ScsiDiskDevice  = ScsiDiskDevice;
4946   Request->Timeout         = Timeout;
4947   Request->TimesRetry      = TimesRetry;
4948   Request->InBuffer        = DataBuffer;
4949   Request->DataLength      = DataLength;
4950   Request->StartLba        = StartLba;
4951   Request->SectorCount     = SectorCount;
4952   Request->BlkIo2Req       = BlkIo2Req;
4953 
4954   //
4955   // Create Event
4956   //
4957   Status = gBS->CreateEvent (
4958                   EVT_NOTIFY_SIGNAL,
4959                   TPL_NOTIFY,
4960                   ScsiDiskNotify,
4961                   Request,
4962                   &AsyncIoEvent
4963                   );
4964   if (EFI_ERROR(Status)) {
4965     goto ErrorExit;
4966   }
4967 
4968   Status = ScsiRead10CommandEx (
4969              ScsiDiskDevice->ScsiIo,
4970              Request->Timeout,
4971              Request->SenseData,
4972              &Request->SenseDataLength,
4973              &Request->HostAdapterStatus,
4974              &Request->TargetStatus,
4975              Request->InBuffer,
4976              &Request->DataLength,
4977              (UINT32) Request->StartLba,
4978              Request->SectorCount,
4979              AsyncIoEvent
4980              );
4981   if (EFI_ERROR(Status)) {
4982     goto ErrorExit;
4983   }
4984 
4985   return EFI_SUCCESS;
4986 
4987 ErrorExit:
4988   if (AsyncIoEvent != NULL) {
4989     gBS->CloseEvent (AsyncIoEvent);
4990   }
4991 
4992   if (Request != NULL) {
4993     if (Request->SenseData != NULL) {
4994       FreePool (Request->SenseData);
4995     }
4996 
4997     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
4998     RemoveEntryList (&Request->Link);
4999     gBS->RestoreTPL (OldTpl);
5000 
5001     FreePool (Request);
5002   }
5003 
5004   return Status;
5005 }
5006 
5007 
5008 /**
5009   Submit Async Write(10) command.
5010 
5011   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.
5012   @param  Timeout            The time to complete the command.
5013   @param  TimesRetry         The number of times the command has been retried.
5014   @param  DataBuffer         The buffer contains the data to write.
5015   @param  DataLength         The length of buffer.
5016   @param  StartLba           The start logic block address.
5017   @param  SectorCount        The number of blocks to write.
5018   @param  BlkIo2Req          The upstream BlockIo2 request.
5019   @param  Token              The pointer to the token associated with the
5020                              non-blocking read request.
5021 
5022   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
5023                                 lack of resources.
5024   @return others                Status returned by calling
5025                                 ScsiWrite10CommandEx().
5026 
5027 **/
5028 EFI_STATUS
5029 ScsiDiskAsyncWrite10 (
5030   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
5031   IN     UINT64                Timeout,
5032   IN     UINT8                 TimesRetry,
5033   IN     UINT8                 *DataBuffer,
5034   IN     UINT32                DataLength,
5035   IN     UINT32                StartLba,
5036   IN     UINT32                SectorCount,
5037   IN OUT SCSI_BLKIO2_REQUEST   *BlkIo2Req,
5038   IN     EFI_BLOCK_IO2_TOKEN   *Token
5039   )
5040 {
5041   EFI_STATUS                   Status;
5042   SCSI_ASYNC_RW_REQUEST        *Request;
5043   EFI_EVENT                    AsyncIoEvent;
5044   EFI_TPL                      OldTpl;
5045 
5046   AsyncIoEvent = NULL;
5047 
5048   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
5049   if (Request == NULL) {
5050     return EFI_OUT_OF_RESOURCES;
5051   }
5052 
5053   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5054   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
5055   gBS->RestoreTPL (OldTpl);
5056 
5057   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
5058   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);
5059   if (Request->SenseData == NULL) {
5060     Status = EFI_OUT_OF_RESOURCES;
5061     goto ErrorExit;
5062   }
5063 
5064   Request->ScsiDiskDevice  = ScsiDiskDevice;
5065   Request->Timeout         = Timeout;
5066   Request->TimesRetry      = TimesRetry;
5067   Request->OutBuffer       = DataBuffer;
5068   Request->DataLength      = DataLength;
5069   Request->StartLba        = StartLba;
5070   Request->SectorCount     = SectorCount;
5071   Request->BlkIo2Req       = BlkIo2Req;
5072 
5073   //
5074   // Create Event
5075   //
5076   Status = gBS->CreateEvent (
5077                   EVT_NOTIFY_SIGNAL,
5078                   TPL_NOTIFY,
5079                   ScsiDiskNotify,
5080                   Request,
5081                   &AsyncIoEvent
5082                   );
5083   if (EFI_ERROR(Status)) {
5084     goto ErrorExit;
5085   }
5086 
5087   Status = ScsiWrite10CommandEx (
5088              ScsiDiskDevice->ScsiIo,
5089              Request->Timeout,
5090              Request->SenseData,
5091              &Request->SenseDataLength,
5092              &Request->HostAdapterStatus,
5093              &Request->TargetStatus,
5094              Request->OutBuffer,
5095              &Request->DataLength,
5096              (UINT32) Request->StartLba,
5097              Request->SectorCount,
5098              AsyncIoEvent
5099              );
5100   if (EFI_ERROR(Status)) {
5101     goto ErrorExit;
5102   }
5103 
5104   return EFI_SUCCESS;
5105 
5106 ErrorExit:
5107   if (AsyncIoEvent != NULL) {
5108     gBS->CloseEvent (AsyncIoEvent);
5109   }
5110 
5111   if (Request != NULL) {
5112     if (Request->SenseData != NULL) {
5113       FreePool (Request->SenseData);
5114     }
5115 
5116     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5117     RemoveEntryList (&Request->Link);
5118     gBS->RestoreTPL (OldTpl);
5119 
5120     FreePool (Request);
5121   }
5122 
5123   return Status;
5124 }
5125 
5126 
5127 /**
5128   Submit Async Read(16) command.
5129 
5130   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.
5131   @param  Timeout            The time to complete the command.
5132   @param  TimesRetry         The number of times the command has been retried.
5133   @param  DataBuffer         The buffer to fill with the read out data.
5134   @param  DataLength         The length of buffer.
5135   @param  StartLba           The start logic block address.
5136   @param  SectorCount        The number of blocks to read.
5137   @param  BlkIo2Req          The upstream BlockIo2 request.
5138   @param  Token              The pointer to the token associated with the
5139                              non-blocking read request.
5140 
5141   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
5142                                 lack of resources.
5143   @return others                Status returned by calling
5144                                 ScsiRead16CommandEx().
5145 
5146 **/
5147 EFI_STATUS
5148 ScsiDiskAsyncRead16 (
5149   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
5150   IN     UINT64                Timeout,
5151   IN     UINT8                 TimesRetry,
5152      OUT UINT8                 *DataBuffer,
5153   IN     UINT32                DataLength,
5154   IN     UINT64                StartLba,
5155   IN     UINT32                SectorCount,
5156   IN OUT SCSI_BLKIO2_REQUEST   *BlkIo2Req,
5157   IN     EFI_BLOCK_IO2_TOKEN   *Token
5158   )
5159 {
5160   EFI_STATUS                   Status;
5161   SCSI_ASYNC_RW_REQUEST        *Request;
5162   EFI_EVENT                    AsyncIoEvent;
5163   EFI_TPL                      OldTpl;
5164 
5165   AsyncIoEvent = NULL;
5166 
5167   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
5168   if (Request == NULL) {
5169     return EFI_OUT_OF_RESOURCES;
5170   }
5171 
5172   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5173   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
5174   gBS->RestoreTPL (OldTpl);
5175 
5176   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
5177   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);
5178   if (Request->SenseData == NULL) {
5179     Status = EFI_OUT_OF_RESOURCES;
5180     goto ErrorExit;
5181   }
5182 
5183   Request->ScsiDiskDevice  = ScsiDiskDevice;
5184   Request->Timeout         = Timeout;
5185   Request->TimesRetry      = TimesRetry;
5186   Request->InBuffer        = DataBuffer;
5187   Request->DataLength      = DataLength;
5188   Request->StartLba        = StartLba;
5189   Request->SectorCount     = SectorCount;
5190   Request->BlkIo2Req       = BlkIo2Req;
5191 
5192   //
5193   // Create Event
5194   //
5195   Status = gBS->CreateEvent (
5196                   EVT_NOTIFY_SIGNAL,
5197                   TPL_NOTIFY,
5198                   ScsiDiskNotify,
5199                   Request,
5200                   &AsyncIoEvent
5201                   );
5202   if (EFI_ERROR(Status)) {
5203     goto ErrorExit;
5204   }
5205 
5206   Status = ScsiRead16CommandEx (
5207              ScsiDiskDevice->ScsiIo,
5208              Request->Timeout,
5209              Request->SenseData,
5210              &Request->SenseDataLength,
5211              &Request->HostAdapterStatus,
5212              &Request->TargetStatus,
5213              Request->InBuffer,
5214              &Request->DataLength,
5215              Request->StartLba,
5216              Request->SectorCount,
5217              AsyncIoEvent
5218              );
5219   if (EFI_ERROR(Status)) {
5220     goto ErrorExit;
5221   }
5222 
5223   return EFI_SUCCESS;
5224 
5225 ErrorExit:
5226   if (AsyncIoEvent != NULL) {
5227     gBS->CloseEvent (AsyncIoEvent);
5228   }
5229 
5230   if (Request != NULL) {
5231     if (Request->SenseData != NULL) {
5232       FreePool (Request->SenseData);
5233     }
5234 
5235     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5236     RemoveEntryList (&Request->Link);
5237     gBS->RestoreTPL (OldTpl);
5238 
5239     FreePool (Request);
5240   }
5241 
5242   return Status;
5243 }
5244 
5245 
5246 /**
5247   Submit Async Write(16) command.
5248 
5249   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.
5250   @param  Timeout            The time to complete the command.
5251   @param  TimesRetry         The number of times the command has been retried.
5252   @param  DataBuffer         The buffer contains the data to write.
5253   @param  DataLength         The length of buffer.
5254   @param  StartLba           The start logic block address.
5255   @param  SectorCount        The number of blocks to write.
5256   @param  BlkIo2Req          The upstream BlockIo2 request.
5257   @param  Token              The pointer to the token associated with the
5258                              non-blocking read request.
5259 
5260   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
5261                                 lack of resources.
5262   @return others                Status returned by calling
5263                                 ScsiWrite16CommandEx().
5264 
5265 **/
5266 EFI_STATUS
5267 ScsiDiskAsyncWrite16 (
5268   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
5269   IN     UINT64                Timeout,
5270   IN     UINT8                 TimesRetry,
5271   IN     UINT8                 *DataBuffer,
5272   IN     UINT32                DataLength,
5273   IN     UINT64                StartLba,
5274   IN     UINT32                SectorCount,
5275   IN OUT SCSI_BLKIO2_REQUEST   *BlkIo2Req,
5276   IN     EFI_BLOCK_IO2_TOKEN   *Token
5277   )
5278 {
5279   EFI_STATUS                   Status;
5280   SCSI_ASYNC_RW_REQUEST        *Request;
5281   EFI_EVENT                    AsyncIoEvent;
5282   EFI_TPL                      OldTpl;
5283 
5284   AsyncIoEvent = NULL;
5285 
5286   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
5287   if (Request == NULL) {
5288     return EFI_OUT_OF_RESOURCES;
5289   }
5290 
5291   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5292   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
5293   gBS->RestoreTPL (OldTpl);
5294 
5295   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
5296   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);
5297   if (Request->SenseData == NULL) {
5298     Status = EFI_OUT_OF_RESOURCES;
5299     goto ErrorExit;
5300   }
5301 
5302   Request->ScsiDiskDevice  = ScsiDiskDevice;
5303   Request->Timeout         = Timeout;
5304   Request->TimesRetry      = TimesRetry;
5305   Request->OutBuffer       = DataBuffer;
5306   Request->DataLength      = DataLength;
5307   Request->StartLba        = StartLba;
5308   Request->SectorCount     = SectorCount;
5309   Request->BlkIo2Req       = BlkIo2Req;
5310 
5311   //
5312   // Create Event
5313   //
5314   Status = gBS->CreateEvent (
5315                   EVT_NOTIFY_SIGNAL,
5316                   TPL_NOTIFY,
5317                   ScsiDiskNotify,
5318                   Request,
5319                   &AsyncIoEvent
5320                   );
5321   if (EFI_ERROR(Status)) {
5322     goto ErrorExit;
5323   }
5324 
5325   Status = ScsiWrite16CommandEx (
5326              ScsiDiskDevice->ScsiIo,
5327              Request->Timeout,
5328              Request->SenseData,
5329              &Request->SenseDataLength,
5330              &Request->HostAdapterStatus,
5331              &Request->TargetStatus,
5332              Request->OutBuffer,
5333              &Request->DataLength,
5334              Request->StartLba,
5335              Request->SectorCount,
5336              AsyncIoEvent
5337              );
5338   if (EFI_ERROR(Status)) {
5339     goto ErrorExit;
5340   }
5341 
5342   return EFI_SUCCESS;
5343 
5344 ErrorExit:
5345   if (AsyncIoEvent != NULL) {
5346     gBS->CloseEvent (AsyncIoEvent);
5347   }
5348 
5349   if (Request != NULL) {
5350     if (Request->SenseData != NULL) {
5351       FreePool (Request->SenseData);
5352     }
5353 
5354     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
5355     RemoveEntryList (&Request->Link);
5356     gBS->RestoreTPL (OldTpl);
5357 
5358     FreePool (Request);
5359   }
5360 
5361   return Status;
5362 }
5363 
5364 
5365 /**
5366   Check sense key to find if media presents.
5367 
5368   @param  SenseData   The pointer of EFI_SCSI_SENSE_DATA
5369   @param  SenseCounts The number of sense key
5370 
5371   @retval TRUE    NOT any media
5372   @retval FALSE   Media presents
5373 **/
5374 BOOLEAN
5375 ScsiDiskIsNoMedia (
5376   IN  EFI_SCSI_SENSE_DATA   *SenseData,
5377   IN  UINTN                 SenseCounts
5378   )
5379 {
5380   EFI_SCSI_SENSE_DATA *SensePtr;
5381   UINTN               Index;
5382   BOOLEAN             IsNoMedia;
5383 
5384   IsNoMedia = FALSE;
5385   SensePtr  = SenseData;
5386 
5387   for (Index = 0; Index < SenseCounts; Index++) {
5388     //
5389     // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
5390     // Additional Sense Code is ASC_NO_MEDIA (0x3A)
5391     //
5392     if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
5393         (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
5394       IsNoMedia = TRUE;
5395     }
5396     SensePtr++;
5397   }
5398 
5399   return IsNoMedia;
5400 }
5401 
5402 
5403 /**
5404   Parse sense key.
5405 
5406   @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA
5407   @param  SenseCounts  The number of sense key
5408 
5409   @retval TRUE   Error
5410   @retval FALSE  NOT error
5411 
5412 **/
5413 BOOLEAN
5414 ScsiDiskIsMediaError (
5415   IN  EFI_SCSI_SENSE_DATA   *SenseData,
5416   IN  UINTN                 SenseCounts
5417   )
5418 {
5419   EFI_SCSI_SENSE_DATA *SensePtr;
5420   UINTN               Index;
5421   BOOLEAN             IsError;
5422 
5423   IsError   = FALSE;
5424   SensePtr  = SenseData;
5425 
5426   for (Index = 0; Index < SenseCounts; Index++) {
5427 
5428     switch (SensePtr->Sense_Key) {
5429 
5430     case EFI_SCSI_SK_MEDIUM_ERROR:
5431       //
5432       // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
5433       //
5434       switch (SensePtr->Addnl_Sense_Code) {
5435 
5436       //
5437       // fall through
5438       //
5439       case EFI_SCSI_ASC_MEDIA_ERR1:
5440 
5441       //
5442       // fall through
5443       //
5444       case EFI_SCSI_ASC_MEDIA_ERR2:
5445 
5446       //
5447       // fall through
5448       //
5449       case EFI_SCSI_ASC_MEDIA_ERR3:
5450       case EFI_SCSI_ASC_MEDIA_ERR4:
5451         IsError = TRUE;
5452         break;
5453 
5454       default:
5455         break;
5456       }
5457 
5458       break;
5459 
5460     case EFI_SCSI_SK_NOT_READY:
5461       //
5462       // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5463       //
5464       switch (SensePtr->Addnl_Sense_Code) {
5465       //
5466       // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
5467       //
5468       case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
5469         IsError = TRUE;
5470         break;
5471 
5472       default:
5473         break;
5474       }
5475       break;
5476 
5477     default:
5478       break;
5479     }
5480 
5481     SensePtr++;
5482   }
5483 
5484   return IsError;
5485 }
5486 
5487 
5488 /**
5489   Check sense key to find if hardware error happens.
5490 
5491   @param  SenseData     The pointer of EFI_SCSI_SENSE_DATA
5492   @param  SenseCounts   The number of sense key
5493 
5494   @retval TRUE  Hardware error exits.
5495   @retval FALSE NO error.
5496 
5497 **/
5498 BOOLEAN
5499 ScsiDiskIsHardwareError (
5500   IN  EFI_SCSI_SENSE_DATA   *SenseData,
5501   IN  UINTN                 SenseCounts
5502   )
5503 {
5504   EFI_SCSI_SENSE_DATA *SensePtr;
5505   UINTN               Index;
5506   BOOLEAN             IsError;
5507 
5508   IsError   = FALSE;
5509   SensePtr  = SenseData;
5510 
5511   for (Index = 0; Index < SenseCounts; Index++) {
5512 
5513     //
5514     // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
5515     //
5516     if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
5517       IsError = TRUE;
5518     }
5519 
5520     SensePtr++;
5521   }
5522 
5523   return IsError;
5524 }
5525 
5526 
5527 /**
5528   Check sense key to find if media has changed.
5529 
5530   @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA
5531   @param  SenseCounts  The number of sense key
5532 
5533   @retval TRUE   Media is changed.
5534   @retval FALSE  Media is NOT changed.
5535 **/
5536 BOOLEAN
5537 ScsiDiskIsMediaChange (
5538   IN  EFI_SCSI_SENSE_DATA   *SenseData,
5539   IN  UINTN                 SenseCounts
5540   )
5541 {
5542   EFI_SCSI_SENSE_DATA *SensePtr;
5543   UINTN               Index;
5544   BOOLEAN             IsMediaChanged;
5545 
5546   IsMediaChanged  = FALSE;
5547   SensePtr        = SenseData;
5548 
5549   for (Index = 0; Index < SenseCounts; Index++) {
5550     //
5551     // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
5552     // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
5553     //
5554     if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
5555         (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
5556       IsMediaChanged = TRUE;
5557     }
5558 
5559     SensePtr++;
5560   }
5561 
5562   return IsMediaChanged;
5563 }
5564 
5565 /**
5566   Check sense key to find if reset happens.
5567 
5568   @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA
5569   @param  SenseCounts  The number of sense key
5570 
5571   @retval TRUE  It is reset before.
5572   @retval FALSE It is NOT reset before.
5573 
5574 **/
5575 BOOLEAN
5576 ScsiDiskIsResetBefore (
5577   IN  EFI_SCSI_SENSE_DATA   *SenseData,
5578   IN  UINTN                 SenseCounts
5579   )
5580 {
5581   EFI_SCSI_SENSE_DATA *SensePtr;
5582   UINTN               Index;
5583   BOOLEAN             IsResetBefore;
5584 
5585   IsResetBefore = FALSE;
5586   SensePtr      = SenseData;
5587 
5588   for (Index = 0; Index < SenseCounts; Index++) {
5589 
5590     //
5591     // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
5592     // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
5593     //
5594     if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
5595         (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
5596       IsResetBefore = TRUE;
5597     }
5598 
5599     SensePtr++;
5600   }
5601 
5602   return IsResetBefore;
5603 }
5604 
5605 /**
5606   Check sense key to find if the drive is ready.
5607 
5608   @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA
5609   @param  SenseCounts  The number of sense key
5610   @param  RetryLater   The flag means if need a retry
5611 
5612   @retval TRUE  Drive is ready.
5613   @retval FALSE Drive is NOT ready.
5614 
5615 **/
5616 BOOLEAN
5617 ScsiDiskIsDriveReady (
5618   IN  EFI_SCSI_SENSE_DATA   *SenseData,
5619   IN  UINTN                 SenseCounts,
5620   OUT BOOLEAN               *RetryLater
5621   )
5622 {
5623   EFI_SCSI_SENSE_DATA *SensePtr;
5624   UINTN               Index;
5625   BOOLEAN             IsReady;
5626 
5627   IsReady     = TRUE;
5628   *RetryLater = FALSE;
5629   SensePtr    = SenseData;
5630 
5631   for (Index = 0; Index < SenseCounts; Index++) {
5632 
5633     switch (SensePtr->Sense_Key) {
5634 
5635     case EFI_SCSI_SK_NOT_READY:
5636       //
5637       // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5638       //
5639       switch (SensePtr->Addnl_Sense_Code) {
5640       case EFI_SCSI_ASC_NOT_READY:
5641         //
5642         // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
5643         //
5644         switch (SensePtr->Addnl_Sense_Code_Qualifier) {
5645         case EFI_SCSI_ASCQ_IN_PROGRESS:
5646           //
5647           // Additional Sense Code Qualifier is
5648           // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
5649           //
5650           IsReady     = FALSE;
5651           *RetryLater = TRUE;
5652           break;
5653 
5654         default:
5655           IsReady     = FALSE;
5656           *RetryLater = FALSE;
5657           break;
5658         }
5659         break;
5660 
5661       default:
5662         break;
5663       }
5664       break;
5665 
5666     default:
5667       break;
5668     }
5669 
5670     SensePtr++;
5671   }
5672 
5673   return IsReady;
5674 }
5675 
5676 /**
5677   Check sense key to find if it has sense key.
5678 
5679   @param  SenseData   - The pointer of EFI_SCSI_SENSE_DATA
5680   @param  SenseCounts - The number of sense key
5681 
5682   @retval TRUE  It has sense key.
5683   @retval FALSE It has NOT any sense key.
5684 
5685 **/
5686 BOOLEAN
5687 ScsiDiskHaveSenseKey (
5688   IN  EFI_SCSI_SENSE_DATA   *SenseData,
5689   IN  UINTN                 SenseCounts
5690   )
5691 {
5692   EFI_SCSI_SENSE_DATA *SensePtr;
5693   UINTN               Index;
5694   BOOLEAN             HaveSenseKey;
5695 
5696   if (SenseCounts == 0) {
5697     HaveSenseKey = FALSE;
5698   } else {
5699     HaveSenseKey = TRUE;
5700   }
5701 
5702   SensePtr = SenseData;
5703 
5704   for (Index = 0; Index < SenseCounts; Index++) {
5705 
5706     //
5707     // Sense Key is SK_NO_SENSE (0x0)
5708     //
5709     if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
5710         (Index == 0)) {
5711       HaveSenseKey = FALSE;
5712     }
5713 
5714     SensePtr++;
5715   }
5716 
5717   return HaveSenseKey;
5718 }
5719 
5720 /**
5721   Release resource about disk device.
5722 
5723   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
5724 
5725 **/
5726 VOID
5727 ReleaseScsiDiskDeviceResources (
5728   IN  SCSI_DISK_DEV   *ScsiDiskDevice
5729   )
5730 {
5731   if (ScsiDiskDevice == NULL) {
5732     return ;
5733   }
5734 
5735   if (ScsiDiskDevice->SenseData != NULL) {
5736     FreePool (ScsiDiskDevice->SenseData);
5737     ScsiDiskDevice->SenseData = NULL;
5738   }
5739 
5740   if (ScsiDiskDevice->ControllerNameTable != NULL) {
5741     FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
5742     ScsiDiskDevice->ControllerNameTable = NULL;
5743   }
5744 
5745   FreePool (ScsiDiskDevice);
5746 
5747   ScsiDiskDevice = NULL;
5748 }
5749 
5750 /**
5751   Determine if Block Io & Block Io2 should be produced.
5752 
5753 
5754   @param  ChildHandle  Child Handle to retrieve Parent information.
5755 
5756   @retval  TRUE    Should produce Block Io & Block Io2.
5757   @retval  FALSE   Should not produce Block Io & Block Io2.
5758 
5759 **/
5760 BOOLEAN
5761 DetermineInstallBlockIo (
5762   IN  EFI_HANDLE      ChildHandle
5763   )
5764 {
5765   EFI_SCSI_PASS_THRU_PROTOCOL           *ScsiPassThru;
5766   EFI_EXT_SCSI_PASS_THRU_PROTOCOL       *ExtScsiPassThru;
5767 
5768   //
5769   // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
5770   // check its attribute, logic or physical.
5771   //
5772   ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);
5773   if (ExtScsiPassThru != NULL) {
5774     if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
5775       return TRUE;
5776     }
5777   }
5778 
5779   //
5780   // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
5781   // check its attribute, logic or physical.
5782   //
5783   ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);
5784   if (ScsiPassThru != NULL) {
5785     if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
5786       return TRUE;
5787     }
5788   }
5789 
5790   return FALSE;
5791 }
5792 
5793 /**
5794   Search protocol database and check to see if the protocol
5795   specified by ProtocolGuid is present on a ControllerHandle and opened by
5796   ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
5797   If the ControllerHandle is found, then the protocol specified by ProtocolGuid
5798   will be opened on it.
5799 
5800 
5801   @param  ProtocolGuid   ProtocolGuid pointer.
5802   @param  ChildHandle    Child Handle to retrieve Parent information.
5803 
5804 **/
5805 VOID *
5806 EFIAPI
5807 GetParentProtocol (
5808   IN  EFI_GUID                          *ProtocolGuid,
5809   IN  EFI_HANDLE                        ChildHandle
5810   )
5811 {
5812   UINTN                                 Index;
5813   UINTN                                 HandleCount;
5814   VOID                                  *Interface;
5815   EFI_STATUS                            Status;
5816   EFI_HANDLE                            *HandleBuffer;
5817 
5818   //
5819   // Retrieve the list of all handles from the handle database
5820   //
5821   Status = gBS->LocateHandleBuffer (
5822                   ByProtocol,
5823                   ProtocolGuid,
5824                   NULL,
5825                   &HandleCount,
5826                   &HandleBuffer
5827                   );
5828 
5829   if (EFI_ERROR (Status)) {
5830     return NULL;
5831   }
5832 
5833   //
5834   // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
5835   //
5836   for (Index = 0; Index < HandleCount; Index++) {
5837     Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);
5838     if (!EFI_ERROR (Status)) {
5839       Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);
5840       if (!EFI_ERROR (Status)) {
5841         gBS->FreePool (HandleBuffer);
5842         return Interface;
5843       }
5844     }
5845   }
5846 
5847   gBS->FreePool (HandleBuffer);
5848   return NULL;
5849 }
5850 
5851 /**
5852   Determine if EFI Erase Block Protocol should be produced.
5853 
5854   @param   ScsiDiskDevice    The pointer of SCSI_DISK_DEV.
5855   @param   ChildHandle       Handle of device.
5856 
5857   @retval  TRUE    Should produce EFI Erase Block Protocol.
5858   @retval  FALSE   Should not produce EFI Erase Block Protocol.
5859 
5860 **/
5861 BOOLEAN
5862 DetermineInstallEraseBlock (
5863   IN  SCSI_DISK_DEV          *ScsiDiskDevice,
5864   IN  EFI_HANDLE             ChildHandle
5865   )
5866 {
5867   UINT8                           HostAdapterStatus;
5868   UINT8                           TargetStatus;
5869   EFI_STATUS                      CommandStatus;
5870   EFI_STATUS                      Status;
5871   BOOLEAN                         UfsDevice;
5872   BOOLEAN                         RetVal;
5873   EFI_DEVICE_PATH_PROTOCOL        *DevicePathNode;
5874   UINT8                           SenseDataLength;
5875   UINT32                          DataLength16;
5876   EFI_SCSI_DISK_CAPACITY_DATA16   *CapacityData16;
5877 
5878   UfsDevice      = FALSE;
5879   RetVal         = TRUE;
5880   CapacityData16 = NULL;
5881 
5882   //
5883   // UNMAP command is not supported by any of the UFS WLUNs.
5884   //
5885   if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) {
5886     RetVal = FALSE;
5887     goto Done;
5888   }
5889 
5890   Status = gBS->HandleProtocol (
5891                   ChildHandle,
5892                   &gEfiDevicePathProtocolGuid,
5893                   (VOID **) &DevicePathNode
5894                   );
5895   //
5896   // Device Path protocol must be installed on the device handle.
5897   //
5898   ASSERT_EFI_ERROR (Status);
5899 
5900   while (!IsDevicePathEndType (DevicePathNode)) {
5901     //
5902     // For now, only support Erase Block Protocol on UFS devices.
5903     //
5904     if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&
5905         (DevicePathNode->SubType == MSG_UFS_DP)) {
5906       UfsDevice = TRUE;
5907       break;
5908     }
5909 
5910     DevicePathNode = NextDevicePathNode (DevicePathNode);
5911   }
5912   if (!UfsDevice) {
5913     RetVal = FALSE;
5914     goto Done;
5915   }
5916 
5917   //
5918   // Check whether the erase functionality is enabled on the UFS device.
5919   //
5920   CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
5921   if (CapacityData16 == NULL) {
5922     RetVal = FALSE;
5923     goto Done;
5924   }
5925 
5926   SenseDataLength = 0;
5927   DataLength16    = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
5928   ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
5929 
5930   CommandStatus = ScsiReadCapacity16Command (
5931                     ScsiDiskDevice->ScsiIo,
5932                     SCSI_DISK_TIMEOUT,
5933                     NULL,
5934                     &SenseDataLength,
5935                     &HostAdapterStatus,
5936                     &TargetStatus,
5937                     (VOID *) CapacityData16,
5938                     &DataLength16,
5939                     FALSE
5940                     );
5941 
5942   if (CommandStatus == EFI_SUCCESS) {
5943     //
5944     // Universal Flash Storage (UFS) Version 2.0
5945     // Section 11.3.9.2
5946     // Bits TPE and TPRZ should both be set to enable the erase feature on UFS.
5947     //
5948     if (((CapacityData16->LowestAlignLogic2 & BIT7) == 0) ||
5949         ((CapacityData16->LowestAlignLogic2 & BIT6) == 0)) {
5950       DEBUG ((
5951         EFI_D_VERBOSE,
5952         "ScsiDisk EraseBlock: Either TPE or TPRZ is not set: 0x%x.\n",
5953         CapacityData16->LowestAlignLogic2
5954         ));
5955 
5956       RetVal = FALSE;
5957       goto Done;
5958     }
5959   } else {
5960     DEBUG ((
5961       EFI_D_VERBOSE,
5962       "ScsiDisk EraseBlock: ReadCapacity16 failed with status %r.\n",
5963       CommandStatus
5964       ));
5965 
5966     RetVal = FALSE;
5967     goto Done;
5968   }
5969 
5970   //
5971   // Check whether the UFS device server implements the UNMAP command.
5972   //
5973   if ((ScsiDiskDevice->UnmapInfo.MaxLbaCnt == 0) ||
5974       (ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt == 0)) {
5975     DEBUG ((
5976       EFI_D_VERBOSE,
5977       "ScsiDisk EraseBlock: The device server does not implement the UNMAP command.\n"
5978       ));
5979 
5980     RetVal = FALSE;
5981     goto Done;
5982   }
5983 
5984 Done:
5985   if (CapacityData16 != NULL) {
5986     FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
5987   }
5988 
5989   return RetVal;
5990 }
5991 
5992 /**
5993   Determine if EFI Storage Security Command Protocol should be produced.
5994 
5995   @param   ScsiDiskDevice    The pointer of SCSI_DISK_DEV.
5996   @param   ChildHandle       Handle of device.
5997 
5998   @retval  TRUE    Should produce EFI Storage Security Command Protocol.
5999   @retval  FALSE   Should not produce EFI Storage Security Command Protocol.
6000 
6001 **/
6002 BOOLEAN
6003 DetermineInstallStorageSecurity (
6004   IN  SCSI_DISK_DEV          *ScsiDiskDevice,
6005   IN  EFI_HANDLE             ChildHandle
6006   )
6007 {
6008   EFI_STATUS                      Status;
6009   UFS_DEVICE_PATH                 *UfsDevice;
6010   BOOLEAN                         RetVal;
6011   EFI_DEVICE_PATH_PROTOCOL        *DevicePathNode;
6012 
6013   UfsDevice      = NULL;
6014   RetVal         = TRUE;
6015 
6016   Status = gBS->HandleProtocol (
6017                   ChildHandle,
6018                   &gEfiDevicePathProtocolGuid,
6019                   (VOID **) &DevicePathNode
6020                   );
6021   //
6022   // Device Path protocol must be installed on the device handle.
6023   //
6024   ASSERT_EFI_ERROR (Status);
6025 
6026   while (!IsDevicePathEndType (DevicePathNode)) {
6027     //
6028     // For now, only support Storage Security Command Protocol on UFS devices.
6029     //
6030     if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&
6031         (DevicePathNode->SubType == MSG_UFS_DP)) {
6032       UfsDevice = (UFS_DEVICE_PATH *) DevicePathNode;
6033       break;
6034     }
6035 
6036     DevicePathNode = NextDevicePathNode (DevicePathNode);
6037   }
6038   if (UfsDevice == NULL) {
6039     RetVal = FALSE;
6040     goto Done;
6041   }
6042 
6043   if (UfsDevice->Lun != UFS_WLUN_RPMB) {
6044     RetVal = FALSE;
6045   }
6046 
6047 Done:
6048   return RetVal;
6049 }
6050 
6051 /**
6052   Provides inquiry information for the controller type.
6053 
6054   This function is used by the IDE bus driver to get inquiry data.  Data format
6055   of Identify data is defined by the Interface GUID.
6056 
6057   @param[in]      This              Pointer to the EFI_DISK_INFO_PROTOCOL instance.
6058   @param[in, out] InquiryData       Pointer to a buffer for the inquiry data.
6059   @param[in, out] InquiryDataSize   Pointer to the value for the inquiry data size.
6060 
6061   @retval EFI_SUCCESS            The command was accepted without any errors.
6062   @retval EFI_NOT_FOUND          Device does not support this data class
6063   @retval EFI_DEVICE_ERROR       Error reading InquiryData from device
6064   @retval EFI_BUFFER_TOO_SMALL   InquiryDataSize not big enough
6065 
6066 **/
6067 EFI_STATUS
6068 EFIAPI
6069 ScsiDiskInfoInquiry (
6070   IN     EFI_DISK_INFO_PROTOCOL   *This,
6071   IN OUT VOID                     *InquiryData,
6072   IN OUT UINT32                   *InquiryDataSize
6073   )
6074 {
6075   EFI_STATUS      Status;
6076   SCSI_DISK_DEV   *ScsiDiskDevice;
6077 
6078   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_DISKINFO (This);
6079 
6080   Status = EFI_BUFFER_TOO_SMALL;
6081   if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {
6082     Status = EFI_SUCCESS;
6083     CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));
6084   }
6085   *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);
6086   return Status;
6087 }
6088 
6089 
6090 /**
6091   Provides identify information for the controller type.
6092 
6093   This function is used by the IDE bus driver to get identify data.  Data format
6094   of Identify data is defined by the Interface GUID.
6095 
6096   @param[in]      This              Pointer to the EFI_DISK_INFO_PROTOCOL
6097                                     instance.
6098   @param[in, out] IdentifyData      Pointer to a buffer for the identify data.
6099   @param[in, out] IdentifyDataSize  Pointer to the value for the identify data
6100                                     size.
6101 
6102   @retval EFI_SUCCESS            The command was accepted without any errors.
6103   @retval EFI_NOT_FOUND          Device does not support this data class
6104   @retval EFI_DEVICE_ERROR       Error reading IdentifyData from device
6105   @retval EFI_BUFFER_TOO_SMALL   IdentifyDataSize not big enough
6106 
6107 **/
6108 EFI_STATUS
6109 EFIAPI
6110 ScsiDiskInfoIdentify (
6111   IN     EFI_DISK_INFO_PROTOCOL   *This,
6112   IN OUT VOID                     *IdentifyData,
6113   IN OUT UINT32                   *IdentifyDataSize
6114   )
6115 {
6116   EFI_STATUS      Status;
6117   SCSI_DISK_DEV   *ScsiDiskDevice;
6118 
6119   if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
6120     //
6121     // Physical SCSI bus does not support this data class.
6122     //
6123     return EFI_NOT_FOUND;
6124   }
6125 
6126   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_DISKINFO (This);
6127 
6128   Status = EFI_BUFFER_TOO_SMALL;
6129   if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {
6130     Status = EFI_SUCCESS;
6131     CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));
6132   }
6133   *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);
6134   return Status;
6135 }
6136 
6137 /**
6138   Provides sense data information for the controller type.
6139 
6140   This function is used by the IDE bus driver to get sense data.
6141   Data format of Sense data is defined by the Interface GUID.
6142 
6143   @param[in]      This              Pointer to the EFI_DISK_INFO_PROTOCOL instance.
6144   @param[in, out] SenseData         Pointer to the SenseData.
6145   @param[in, out] SenseDataSize     Size of SenseData in bytes.
6146   @param[out]     SenseDataNumber   Pointer to the value for the sense data size.
6147 
6148   @retval EFI_SUCCESS            The command was accepted without any errors.
6149   @retval EFI_NOT_FOUND          Device does not support this data class.
6150   @retval EFI_DEVICE_ERROR       Error reading SenseData from device.
6151   @retval EFI_BUFFER_TOO_SMALL   SenseDataSize not big enough.
6152 
6153 **/
6154 EFI_STATUS
6155 EFIAPI
6156 ScsiDiskInfoSenseData (
6157   IN     EFI_DISK_INFO_PROTOCOL   *This,
6158   IN OUT VOID                     *SenseData,
6159   IN OUT UINT32                   *SenseDataSize,
6160   OUT    UINT8                    *SenseDataNumber
6161   )
6162 {
6163   return EFI_NOT_FOUND;
6164 }
6165 
6166 
6167 /**
6168   This function is used by the IDE bus driver to get controller information.
6169 
6170   @param[in]  This         Pointer to the EFI_DISK_INFO_PROTOCOL instance.
6171   @param[out] IdeChannel   Pointer to the Ide Channel number.  Primary or secondary.
6172   @param[out] IdeDevice    Pointer to the Ide Device number.  Master or slave.
6173 
6174   @retval EFI_SUCCESS       IdeChannel and IdeDevice are valid.
6175   @retval EFI_UNSUPPORTED   This is not an IDE device.
6176 
6177 **/
6178 EFI_STATUS
6179 EFIAPI
6180 ScsiDiskInfoWhichIde (
6181   IN  EFI_DISK_INFO_PROTOCOL   *This,
6182   OUT UINT32                   *IdeChannel,
6183   OUT UINT32                   *IdeDevice
6184   )
6185 {
6186   SCSI_DISK_DEV   *ScsiDiskDevice;
6187 
6188   if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
6189     //
6190     // This is not an IDE physical device.
6191     //
6192     return EFI_UNSUPPORTED;
6193   }
6194 
6195   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_DISKINFO (This);
6196   *IdeChannel     = ScsiDiskDevice->Channel;
6197   *IdeDevice      = ScsiDiskDevice->Device;
6198 
6199   return EFI_SUCCESS;
6200 }
6201 
6202 
6203 /**
6204   Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
6205 
6206   This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
6207   implement Identify() interface for DiskInfo protocol. The ATA command is sent
6208   via SCSI Request Packet.
6209 
6210   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
6211 
6212   @retval EFI_SUCCESS     The ATAPI device identify data were retrieved successfully.
6213   @retval others          Some error occurred during the identification that ATAPI device.
6214 
6215 **/
6216 EFI_STATUS
6217 AtapiIdentifyDevice (
6218   IN OUT SCSI_DISK_DEV   *ScsiDiskDevice
6219   )
6220 {
6221   EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
6222   UINT8                           Cdb[6];
6223 
6224   //
6225   // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
6226   //
6227   ZeroMem (&CommandPacket, sizeof (CommandPacket));
6228   ZeroMem (Cdb, sizeof (Cdb));
6229 
6230   Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;
6231   CommandPacket.Timeout = SCSI_DISK_TIMEOUT;
6232   CommandPacket.Cdb = Cdb;
6233   CommandPacket.CdbLength = (UINT8) sizeof (Cdb);
6234   CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;
6235   CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);
6236 
6237   return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);
6238 }
6239 
6240 
6241 /**
6242   Initialize the installation of DiskInfo protocol.
6243 
6244   This function prepares for the installation of DiskInfo protocol on the child handle.
6245   By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
6246   detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
6247   to be IDE/AHCI interface GUID.
6248 
6249   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV.
6250   @param  ChildHandle     Child handle to install DiskInfo protocol.
6251 
6252 **/
6253 VOID
6254 InitializeInstallDiskInfo (
6255   IN  SCSI_DISK_DEV   *ScsiDiskDevice,
6256   IN  EFI_HANDLE      ChildHandle
6257   )
6258 {
6259   EFI_STATUS                Status;
6260   EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode;
6261   EFI_DEVICE_PATH_PROTOCOL  *ChildDevicePathNode;
6262   ATAPI_DEVICE_PATH         *AtapiDevicePath;
6263   SATA_DEVICE_PATH          *SataDevicePath;
6264   UINTN                     IdentifyRetry;
6265 
6266   Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePathNode);
6267   //
6268   // Device Path protocol must be installed on the device handle.
6269   //
6270   ASSERT_EFI_ERROR (Status);
6271   //
6272   // Copy the DiskInfo protocol template.
6273   //
6274   CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));
6275 
6276   while (!IsDevicePathEnd (DevicePathNode)) {
6277     ChildDevicePathNode = NextDevicePathNode (DevicePathNode);
6278     if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
6279         (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
6280         (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
6281        ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||
6282         (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP))) {
6283 
6284       IdentifyRetry = 3;
6285       do {
6286         //
6287         // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
6288         // with IDE/AHCI interface GUID.
6289         //
6290         Status = AtapiIdentifyDevice (ScsiDiskDevice);
6291         if (!EFI_ERROR (Status)) {
6292           if (DevicePathSubType(ChildDevicePathNode) == MSG_ATAPI_DP) {
6293             //
6294             // We find the valid ATAPI device path
6295             //
6296             AtapiDevicePath = (ATAPI_DEVICE_PATH *) ChildDevicePathNode;
6297             ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;
6298             ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;
6299             //
6300             // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
6301             //
6302             CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);
6303           } else {
6304             //
6305             // We find the valid SATA device path
6306             //
6307             SataDevicePath = (SATA_DEVICE_PATH *) ChildDevicePathNode;
6308             ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;
6309             ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;
6310             //
6311             // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
6312             //
6313             CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);
6314           }
6315           return;
6316         }
6317       } while (--IdentifyRetry > 0);
6318     } else if ((DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
6319        (DevicePathSubType (ChildDevicePathNode) == MSG_UFS_DP)) {
6320       CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoUfsInterfaceGuid);
6321       break;
6322     }
6323     DevicePathNode = ChildDevicePathNode;
6324   }
6325 
6326   return;
6327 }
6328