]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
MdeModulePkg: ATA performance tuning.
[mirror_edk2.git] / MdeModulePkg / Bus / Scsi / ScsiDiskDxe / ScsiDisk.c
index 07e2f870c0e435620e8d4592230be5882537adba..0e8aa34ad63c61e6dc26d370db253d7b29c0cc9c 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
   SCSI disk driver that layers on every SCSI IO protocol in the system.\r
 \r
-Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
-All rights reserved. This program and the accompanying materials\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
 http://opensource.org/licenses/bsd-license.php\r
@@ -12,21 +12,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 **/\r
 \r
-#include <Uefi.h>\r
-\r
-\r
-#include <Protocol/ScsiIo.h>\r
-#include <Protocol/ComponentName.h>\r
-#include <Protocol/BlockIo.h>\r
-#include <Protocol/DriverBinding.h>\r
-#include <Protocol/ScsiPassThruExt.h>\r
-\r
-#include <Library/DebugLib.h>\r
-#include <Library/UefiDriverEntryPoint.h>\r
-#include <Library/UefiLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/ScsiLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
 \r
 #include "ScsiDisk.h"\r
 \r
@@ -39,11 +24,21 @@ EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {
   NULL\r
 };\r
 \r
+EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = {\r
+  EFI_DISK_INFO_SCSI_INTERFACE_GUID,\r
+  ScsiDiskInfoInquiry,\r
+  ScsiDiskInfoIdentify,\r
+  ScsiDiskInfoSenseData,\r
+  ScsiDiskInfoWhichIde\r
+};\r
+\r
 /**\r
-  The user Entry Point for module ScsiDisk. The user code starts with this function.\r
+  The user Entry Point for module ScsiDisk.\r
+\r
+  The user code starts with this function.\r
 \r
-  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
-  @param[in] SystemTable    A pointer to the EFI System Table.\r
+  @param  ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param  SystemTable    A pointer to the EFI System Table.\r
   \r
   @retval EFI_SUCCESS       The entry point is executed successfully.\r
   @retval other             Some error occurs when executing this entry point.\r
@@ -75,33 +70,32 @@ InitializeScsiDisk(
   return Status;\r
 }\r
 \r
+/**\r
+  Test to see if this driver supports ControllerHandle.\r
+\r
+  This service is called by the EFI boot service ConnectController(). In order\r
+  to make drivers as small as possible, there are a few calling restrictions for\r
+  this service. ConnectController() must follow these calling restrictions.\r
+  If any other agent wishes to call Supported() it must also follow these\r
+  calling restrictions.\r
+\r
+  @param  This                Protocol instance pointer.\r
+  @param  ControllerHandle    Handle of device to test\r
+  @param  RemainingDevicePath Optional parameter use to pick a specific child\r
+                              device to start.\r
+\r
+  @retval EFI_SUCCESS         This driver supports this device\r
+  @retval EFI_ALREADY_STARTED This driver is already running on this device\r
+  @retval other               This driver does not support this device\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ScsiDiskDriverBindingSupported (\r
   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN EFI_HANDLE                   Controller,\r
-  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
-  that has ScsiIoProtocol installed will be supported.\r
-\r
-Arguments:\r
-\r
-  This                - Protocol instance pointer.\r
-  Controller          - Handle of device to test\r
-  RemainingDevicePath - Not used\r
-\r
-Returns:\r
-\r
-  EFI_SUCCESS         - This driver supports this device.\r
-  EFI_UNSUPPORTED     - This driver does not support this device.\r
-  \r
-  \r
---*/\r
 {\r
   EFI_STATUS            Status;\r
   EFI_SCSI_IO_PROTOCOL  *ScsiIo;\r
@@ -137,32 +131,33 @@ Returns:
   return Status;\r
 }\r
 \r
+\r
+/**\r
+  Start this driver on ControllerHandle.\r
+\r
+  This service is called by the EFI boot service ConnectController(). In order\r
+  to make drivers as small as possible, there are a few calling restrictions for\r
+  this service. ConnectController() must follow these calling restrictions. If\r
+  any other agent wishes to call Start() it must also follow these calling\r
+  restrictions.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  ControllerHandle     Handle of device to bind driver to\r
+  @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
+                               device to start.\r
+\r
+  @retval EFI_SUCCESS          This driver is added to ControllerHandle\r
+  @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle\r
+  @retval other                This driver does not support this device\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ScsiDiskDriverBindingStart (\r
   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN EFI_HANDLE                   Controller,\r
-  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Start SCSI Disk Driver, and attach BlockIoProtocol to it.\r
-  \r
-Arguments:\r
-\r
-  This                - Protocol instance pointer.\r
-  Controller          - Handle of device to test\r
-  RemainingDevicePath - Not used\r
-\r
-Returns:\r
-\r
-  EFI_SUCCESS         - This driver supports this device.\r
-  EFI_UNSUPPORTED     - This driver does not support this device.\r
-  \r
-  \r
---*/\r
 {\r
   EFI_STATUS            Status;\r
   EFI_SCSI_IO_PROTOCOL  *ScsiIo;\r
@@ -171,17 +166,14 @@ Returns:
   UINT8                 Index;\r
   UINT8                 MaxRetry;\r
   BOOLEAN               NeedRetry;\r
+  BOOLEAN               MustReadCapacity;\r
 \r
-  Status = gBS->AllocatePool (\r
-                  EfiBootServicesData,\r
-                  sizeof (SCSI_DISK_DEV),\r
-                  (VOID **) &ScsiDiskDevice\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
+  MustReadCapacity = TRUE;\r
 \r
-  ZeroMem (ScsiDiskDevice, sizeof (SCSI_DISK_DEV));\r
+  ScsiDiskDevice = (SCSI_DISK_DEV *) AllocateZeroPool (sizeof (SCSI_DISK_DEV));\r
+  if (ScsiDiskDevice == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
 \r
   Status = gBS->OpenProtocol (\r
                   Controller,\r
@@ -192,12 +184,13 @@ Returns:
                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    gBS->FreePool (ScsiDiskDevice);\r
+    FreePool (ScsiDiskDevice);\r
     return Status;\r
   }\r
 \r
   ScsiDiskDevice->Signature         = SCSI_DISK_DEV_SIGNATURE;\r
   ScsiDiskDevice->ScsiIo            = ScsiIo;\r
+  ScsiDiskDevice->BlkIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION3;\r
   ScsiDiskDevice->BlkIo.Media       = &ScsiDiskDevice->BlkIoMedia;\r
   ScsiDiskDevice->BlkIo.Reset       = ScsiDiskReset;\r
   ScsiDiskDevice->BlkIo.ReadBlocks  = ScsiDiskReadBlocks;\r
@@ -209,39 +202,34 @@ Returns:
   switch (ScsiDiskDevice->DeviceType) {\r
   case EFI_SCSI_TYPE_DISK:\r
     ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;\r
+    MustReadCapacity = TRUE;\r
     break;\r
 \r
   case EFI_SCSI_TYPE_CDROM:\r
     ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;\r
+    MustReadCapacity = FALSE;\r
     break;\r
   }\r
   //\r
   // The Sense Data Array's initial size is 6\r
   //\r
   ScsiDiskDevice->SenseDataNumber = 6;\r
-  Status = gBS->AllocatePool (\r
-                  EfiBootServicesData,\r
-                  sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber,\r
-                  (VOID **) &(ScsiDiskDevice->SenseData)\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
+  ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *) AllocateZeroPool (\r
+                                 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber\r
+                                 );\r
+  if (ScsiDiskDevice->SenseData == NULL) {\r
     gBS->CloseProtocol (\r
           Controller,\r
           &gEfiScsiIoProtocolGuid,\r
           This->DriverBindingHandle,\r
           Controller\r
           );\r
-    gBS->FreePool (ScsiDiskDevice);\r
-    return Status;\r
+    FreePool (ScsiDiskDevice);\r
+    return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  ZeroMem (\r
-    ScsiDiskDevice->SenseData,\r
-    sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber\r
-    );\r
-\r
   //\r
-  // Retrive device information\r
+  // Retrieve device information\r
   //\r
   MaxRetry = 2;\r
   for (Index = 0; Index < MaxRetry; Index++) {\r
@@ -251,14 +239,14 @@ Returns:
     }\r
 \r
     if (!NeedRetry) {\r
-      gBS->FreePool (ScsiDiskDevice->SenseData);\r
+      FreePool (ScsiDiskDevice->SenseData);\r
       gBS->CloseProtocol (\r
              Controller,\r
              &gEfiScsiIoProtocolGuid,\r
              This->DriverBindingHandle,\r
              Controller\r
              );\r
-      gBS->FreePool (ScsiDiskDevice);\r
+      FreePool (ScsiDiskDevice);\r
       return EFI_DEVICE_ERROR;\r
     }\r
   }\r
@@ -266,78 +254,82 @@ Returns:
   // The second parameter "TRUE" means must\r
   // retrieve media capacity\r
   //\r
-  Status = ScsiDiskDetectMedia (ScsiDiskDevice, TRUE, &Temp);\r
+  Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);\r
   if (!EFI_ERROR (Status)) {\r
-    Status = gBS->InstallMultipleProtocolInterfaces (\r
-                    &Controller,\r
-                    &gEfiBlockIoProtocolGuid,\r
-                    &ScsiDiskDevice->BlkIo,\r
-                    NULL\r
-                    );\r
+    //\r
+    // Determine if Block IO should be produced on this controller handle\r
+    //\r
+    if (DetermineInstallBlockIo(Controller)) {\r
+      InitializeInstallDiskInfo(ScsiDiskDevice, Controller);\r
+      Status = gBS->InstallMultipleProtocolInterfaces (\r
+                      &Controller,\r
+                      &gEfiBlockIoProtocolGuid,\r
+                      &ScsiDiskDevice->BlkIo,\r
+                      &gEfiDiskInfoProtocolGuid,\r
+                      &ScsiDiskDevice->DiskInfo,\r
+                      NULL\r
+                      );\r
+      if (!EFI_ERROR(Status)) {\r
+        ScsiDiskDevice->ControllerNameTable = NULL;\r
+        AddUnicodeString2 (\r
+          "eng",\r
+          gScsiDiskComponentName.SupportedLanguages,\r
+          &ScsiDiskDevice->ControllerNameTable,\r
+          L"SCSI Disk Device",\r
+          TRUE\r
+          );\r
+        AddUnicodeString2 (\r
+          "en",\r
+          gScsiDiskComponentName2.SupportedLanguages,\r
+          &ScsiDiskDevice->ControllerNameTable,\r
+          L"SCSI Disk Device",\r
+          FALSE\r
+          );\r
+        return EFI_SUCCESS;\r
+      }\r
+    } \r
   }\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    gBS->FreePool (ScsiDiskDevice->SenseData);\r
-    gBS->CloseProtocol (\r
-           Controller,\r
-           &gEfiScsiIoProtocolGuid,\r
-           This->DriverBindingHandle,\r
-           Controller\r
-           );\r
-    gBS->FreePool (ScsiDiskDevice);\r
-    return Status;\r
-  }\r
+  gBS->FreePool (ScsiDiskDevice->SenseData);\r
+  gBS->FreePool (ScsiDiskDevice);\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiScsiIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+  return Status;\r
+  \r
+}\r
 \r
-  ScsiDiskDevice->ControllerNameTable = NULL;\r
-  AddUnicodeString2 (\r
-    "eng",\r
-    gScsiDiskComponentName.SupportedLanguages,\r
-    &ScsiDiskDevice->ControllerNameTable,\r
-    L"SCSI Disk Device",\r
-    TRUE\r
-    );\r
-  AddUnicodeString2 (\r
-    "en",\r
-    gScsiDiskComponentName2.SupportedLanguages,\r
-    &ScsiDiskDevice->ControllerNameTable,\r
-    L"SCSI Disk Device",\r
-    FALSE\r
-    );\r
 \r
+/**\r
+  Stop this driver on ControllerHandle.\r
 \r
-  return EFI_SUCCESS;\r
+  This service is called by the EFI boot service DisconnectController().\r
+  In order to make drivers as small as possible, there are a few calling\r
+  restrictions for this service. DisconnectController() must follow these\r
+  calling restrictions. If any other agent wishes to call Stop() it must\r
+  also follow these calling restrictions.\r
+  \r
+  @param  This              Protocol instance pointer.\r
+  @param  ControllerHandle  Handle of device to stop driver on\r
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
+                            children is zero stop the entire bus driver.\r
+  @param  ChildHandleBuffer List of Child Handles to Stop.\r
 \r
-}\r
+  @retval EFI_SUCCESS       This driver is removed ControllerHandle\r
+  @retval other             This driver was not removed from this device\r
 \r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ScsiDiskDriverBindingStop (\r
   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
   IN  EFI_HANDLE                      Controller,\r
   IN  UINTN                           NumberOfChildren,\r
-  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer   OPTIONAL\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-    Stop this driver on ControllerHandle. Support stoping any child handles\r
-    created by this driver.\r
-\r
-Arguments:\r
-\r
-    This              - Protocol instance pointer.\r
-    Controller        - Handle of device to stop driver on\r
-    NumberOfChildren  - Number of Children in the ChildHandleBuffer\r
-    ChildHandleBuffer - List of handles for the children we need to stop.\r
-\r
-Returns:\r
-\r
-    EFI_SUCCESS\r
-    EFI_DEVICE_ERROR\r
-    others\r
-  \r
---*/\r
 {\r
   EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
   SCSI_DISK_DEV         *ScsiDiskDevice;\r
@@ -356,10 +348,13 @@ Returns:
   }\r
 \r
   ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (BlkIo);\r
-  Status = gBS->UninstallProtocolInterface (\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
                   Controller,\r
                   &gEfiBlockIoProtocolGuid,\r
-                  &ScsiDiskDevice->BlkIo\r
+                  &ScsiDiskDevice->BlkIo,\r
+                  &gEfiDiskInfoProtocolGuid,\r
+                  &ScsiDiskDevice->DiskInfo,\r
+                  NULL\r
                   );\r
   if (!EFI_ERROR (Status)) {\r
     gBS->CloseProtocol (\r
@@ -379,29 +374,25 @@ Returns:
   return Status;\r
 }\r
 \r
+/**\r
+  Reset SCSI Disk.\r
+\r
+\r
+  @param  This                 The pointer of EFI_BLOCK_IO_PROTOCOL\r
+  @param  ExtendedVerification The flag about if extend verificate\r
+\r
+  @retval EFI_SUCCESS          The device was reset.\r
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could\r
+                               not be reset.\r
+  @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().\r
 \r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ScsiDiskReset (\r
   IN  EFI_BLOCK_IO_PROTOCOL   *This,\r
   IN  BOOLEAN                 ExtendedVerification\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Reset SCSI Disk  \r
-\r
-Arguments:\r
-\r
-  This                  - The pointer of EFI_BLOCK_IO_PROTOCOL\r
-  ExtendedVerification  - The flag about if extend verificate\r
-\r
-Returns:\r
-\r
-  EFI_STATUS\r
-\r
---*/\r
 {\r
   EFI_TPL       OldTpl;\r
   SCSI_DISK_DEV *ScsiDiskDevice;\r
@@ -413,50 +404,53 @@ Returns:
 \r
   Status          = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
 \r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Done;\r
+  }\r
+\r
   if (!ExtendedVerification) {\r
     goto Done;\r
   }\r
 \r
   Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
 \r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Done;\r
+  }\r
+\r
 Done:\r
   gBS->RestoreTPL (OldTpl);\r
   return Status;\r
 }\r
 \r
+/**\r
+  The function is to Read Block from SCSI Disk.\r
+\r
+  @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL.\r
+  @param  MediaId    The Id of Media detected\r
+  @param  Lba        The logic block address\r
+  @param  BufferSize The size of Buffer\r
+  @param  Buffer     The buffer to fill the read out data\r
+\r
+  @retval EFI_SUCCESS           Successfully to read out block.\r
+  @retval EFI_DEVICE_ERROR      Fail to detect media.\r
+  @retval EFI_NO_MEDIA          Media is not present.\r
+  @retval EFI_MEDIA_CHANGED     Media has changed.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER Invalid parameter passed in.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ScsiDiskReadBlocks (\r
   IN  EFI_BLOCK_IO_PROTOCOL   *This,\r
   IN  UINT32                  MediaId,\r
-  IN  EFI_LBA                 LBA,\r
+  IN  EFI_LBA                 Lba,\r
   IN  UINTN                   BufferSize,\r
   OUT VOID                    *Buffer\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  The function is to Read Block from SCSI Disk\r
-\r
-Arguments:\r
-\r
-  This        - The pointer of EFI_BLOCK_IO_PROTOCOL\r
-  MediaId     - The Id of Media detected\r
-  LBA         - The logic block address\r
-  BufferSize  - The size of Buffer\r
-  Buffer      - The buffer to fill the read out data\r
-\r
-Returns:\r
-\r
-  EFI_INVALID_PARAMETER - Invalid parameter passed in.\r
-  EFI_SUCCESS           - Successfully to read out block.\r
-  EFI_DEVICE_ERROR      - Fail to detect media.\r
-  EFI_NO_MEDIA          - Media is not present.\r
-  EFI_MEDIA_CHANGED     - Media has changed.\r
-  EFI_BAD_BUFFER_SIZE   - The buffer size is not multiple of BlockSize.\r
-\r
---*/\r
 {\r
   SCSI_DISK_DEV       *ScsiDiskDevice;\r
   EFI_BLOCK_IO_MEDIA  *Media;\r
@@ -466,20 +460,11 @@ Returns:
   BOOLEAN             MediaChange;\r
   EFI_TPL             OldTpl;\r
 \r
-  MediaChange = FALSE;\r
-  if (!Buffer) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if (BufferSize == 0) {\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
-\r
+  MediaChange    = FALSE;\r
+  OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);\r
   ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
 \r
-  if (!IsDeviceFixed (ScsiDiskDevice)) {\r
+  if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
 \r
     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
     if (EFI_ERROR (Status)) {\r
@@ -514,17 +499,27 @@ Returns:
     goto Done;\r
   }\r
 \r
+  if (Buffer == NULL) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Done;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    Status = EFI_SUCCESS;\r
+    goto Done;\r
+  }\r
+\r
   if (BufferSize % BlockSize != 0) {\r
     Status = EFI_BAD_BUFFER_SIZE;\r
     goto Done;\r
   }\r
 \r
-  if (LBA > Media->LastBlock) {\r
+  if (Lba > Media->LastBlock) {\r
     Status = EFI_INVALID_PARAMETER;\r
     goto Done;\r
   }\r
 \r
-  if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+  if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
     Status = EFI_INVALID_PARAMETER;\r
     goto Done;\r
   }\r
@@ -538,46 +533,40 @@ Returns:
   // If all the parameters are valid, then perform read sectors command\r
   // to transfer data from device to host.\r
   //\r
-  Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, LBA, NumberOfBlocks);\r
+  Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);\r
 \r
 Done:\r
   gBS->RestoreTPL (OldTpl);\r
   return Status;\r
 }\r
 \r
+/**\r
+  The function is to Write Block to SCSI Disk.\r
+\r
+  @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL\r
+  @param  MediaId    The Id of Media detected\r
+  @param  Lba        The logic block address\r
+  @param  BufferSize The size of Buffer\r
+  @param  Buffer     The buffer to fill the read out data\r
+\r
+  @retval EFI_SUCCESS           Successfully to read out block.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      Fail to detect media.\r
+  @retval EFI_NO_MEDIA          Media is not present.\r
+  @retval EFI_MEDIA_CHNAGED     Media has changed.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER Invalid parameter passed in.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ScsiDiskWriteBlocks (\r
   IN  EFI_BLOCK_IO_PROTOCOL   *This,\r
   IN  UINT32                  MediaId,\r
-  IN  EFI_LBA                 LBA,\r
+  IN  EFI_LBA                 Lba,\r
   IN  UINTN                   BufferSize,\r
   IN  VOID                    *Buffer\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  The function is to Write Block to SCSI Disk\r
-\r
-Arguments:\r
-\r
-  This        - The pointer of EFI_BLOCK_IO_PROTOCOL\r
-  MediaId     - The Id of Media detected\r
-  LBA         - The logic block address\r
-  BufferSize  - The size of Buffer\r
-  Buffer      - The buffer to fill the read out data\r
-\r
-Returns:\r
-\r
-  EFI_INVALID_PARAMETER - Invalid parameter passed in.\r
-  EFI_SUCCESS           - Successfully to read out block.\r
-  EFI_DEVICE_ERROR      - Fail to detect media.\r
-  EFI_NO_MEDIA          - Media is not present.\r
-  EFI_MEDIA_CHANGED     - Media has changed.\r
-  EFI_BAD_BUFFER_SIZE   - The buffer size is not multiple of BlockSize.\r
-\r
---*/\r
 {\r
   SCSI_DISK_DEV       *ScsiDiskDevice;\r
   EFI_BLOCK_IO_MEDIA  *Media;\r
@@ -587,20 +576,11 @@ Returns:
   BOOLEAN             MediaChange;\r
   EFI_TPL             OldTpl;\r
 \r
-  MediaChange = FALSE;\r
-  if (!Buffer) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if (BufferSize == 0) {\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
-\r
+  MediaChange    = FALSE;\r
+  OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);\r
   ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
 \r
-  if (!IsDeviceFixed (ScsiDiskDevice)) {\r
+  if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
 \r
     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
     if (EFI_ERROR (Status)) {\r
@@ -635,17 +615,27 @@ Returns:
     goto Done;\r
   }\r
 \r
+  if (BufferSize == 0) {\r
+    Status = EFI_SUCCESS;\r
+    goto Done;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Done;\r
+  }\r
+\r
   if (BufferSize % BlockSize != 0) {\r
     Status = EFI_BAD_BUFFER_SIZE;\r
     goto Done;\r
   }\r
 \r
-  if (LBA > Media->LastBlock) {\r
+  if (Lba > Media->LastBlock) {\r
     Status = EFI_INVALID_PARAMETER;\r
     goto Done;\r
   }\r
 \r
-  if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+  if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
     Status = EFI_INVALID_PARAMETER;\r
     goto Done;\r
   }\r
@@ -658,33 +648,28 @@ Returns:
   // if all the parameters are valid, then perform read sectors command\r
   // to transfer data from device to host.\r
   //\r
-  Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, LBA, NumberOfBlocks);\r
+  Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);\r
 \r
 Done:\r
   gBS->RestoreTPL (OldTpl);\r
   return Status;\r
 }\r
 \r
+/**\r
+  Flush Block to Disk.\r
+\r
+  EFI_SUCCESS is returned directly.\r
+\r
+  @param  This              The pointer of EFI_BLOCK_IO_PROTOCOL\r
+\r
+  @retval EFI_SUCCESS       All outstanding data was written to the device\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 ScsiDiskFlushBlocks (\r
   IN  EFI_BLOCK_IO_PROTOCOL   *This\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Flush Block to Disk\r
-\r
-Arguments:\r
-\r
-  This  - The pointer of EFI_BLOCK_IO_PROTOCOL\r
-\r
-Returns:\r
-\r
-  EFI_SUCCESS \r
-\r
---*/\r
 {\r
   //\r
   // return directly\r
@@ -692,52 +677,70 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
-EFI_STATUS\r
-ScsiDiskDetectMedia (\r
-  SCSI_DISK_DEV   *ScsiDiskDevice,\r
-  BOOLEAN         MustReadCapacity,\r
-  BOOLEAN         *MediaChange\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Dectect Device and read out capacity ,if error occurs, parse the sense key.\r
 \r
-Arguments:\r
-\r
-  ScsiDiskDevice     - The pointer of SCSI_DISK_DEV\r
-  MustReadCapacity   - The flag about reading device capacity\r
-  MediaChange        - The pointer of flag indicates if media has changed \r
+/**\r
+  Detect Device and read out capacity ,if error occurs, parse the sense key.\r
 \r
-Returns:\r
+  @param  ScsiDiskDevice    The pointer of SCSI_DISK_DEV\r
+  @param  MustReadCapacity  The flag about reading device capacity\r
+  @param  MediaChange       The pointer of flag indicates if media has changed \r
 \r
-  EFI_DEVICE_ERROR   - Indicates that error occurs\r
-  EFI_SUCCESS        - Successfully to detect media\r
+  @retval EFI_DEVICE_ERROR  Indicates that error occurs\r
+  @retval EFI_SUCCESS       Successfully to detect media\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ScsiDiskDetectMedia (\r
+  IN   SCSI_DISK_DEV   *ScsiDiskDevice,\r
+  IN   BOOLEAN         MustReadCapacity,\r
+  OUT  BOOLEAN         *MediaChange\r
+  )\r
 {\r
   EFI_STATUS          Status;\r
-  EFI_STATUS          ReadCapacityStatus;\r
   EFI_SCSI_SENSE_DATA *SenseData;\r
   UINTN               NumberOfSenseKeys;\r
   BOOLEAN             NeedRetry;\r
   BOOLEAN             NeedReadCapacity;\r
-  UINT8               Index;\r
+  UINT8               Retry;\r
   UINT8               MaxRetry;\r
   EFI_BLOCK_IO_MEDIA  OldMedia;\r
   UINTN               Action;\r
+  EFI_EVENT           TimeoutEvt;\r
 \r
   Status              = EFI_SUCCESS;\r
-  ReadCapacityStatus  = EFI_SUCCESS;\r
   SenseData           = NULL;\r
   NumberOfSenseKeys   = 0;\r
+  Retry               = 0;\r
+  MaxRetry            = 3;\r
+  Action              = ACTION_NO_ACTION;\r
   NeedReadCapacity    = FALSE;\r
-  CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));\r
   *MediaChange        = FALSE;\r
-  MaxRetry            = 3;\r
+  TimeoutEvt          = NULL;\r
 \r
-  for (Index = 0; Index < MaxRetry; Index++) {\r
+  CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER,\r
+                  TPL_CALLBACK,\r
+                  NULL,\r
+                  NULL,\r
+                  &TimeoutEvt\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(120));\r
+  if (EFI_ERROR (Status)) {\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Sending Test_Unit cmd to poll device status.\r
+  // If the sense data shows the drive is not ready or reset before, we need poll the device status again.\r
+  // We limit the upper boundary to 120 seconds.\r
+  //\r
+  while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {\r
     Status = ScsiDiskTestUnitReady (\r
               ScsiDiskDevice,\r
               &NeedRetry,\r
@@ -745,34 +748,36 @@ Returns:
               &NumberOfSenseKeys\r
               );\r
     if (!EFI_ERROR (Status)) {\r
-      break;\r
-    }\r
-\r
-    if (!NeedRetry) {\r
-      return Status;\r
+      Status = DetectMediaParsingSenseKeys (\r
+                 ScsiDiskDevice,\r
+                 SenseData,\r
+                 NumberOfSenseKeys,\r
+                 &Action\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        goto EXIT;\r
+      } else if (Action == ACTION_RETRY_COMMAND_LATER) {\r
+        continue;\r
+      } else {\r
+        break;\r
+      }\r
+    } else {\r
+      Retry++;\r
+      if (!NeedRetry || (Retry >= MaxRetry)) {\r
+        goto EXIT;\r
+      }\r
     }\r
   }\r
 \r
-  if ((Index == MaxRetry) && EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-\r
-  Status = DetectMediaParsingSenseKeys (\r
-            ScsiDiskDevice,\r
-            SenseData,\r
-            NumberOfSenseKeys,\r
-            &Action\r
-            );\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    goto EXIT;\r
   }\r
+\r
   //\r
   // ACTION_NO_ACTION: need not read capacity\r
   // other action code: need read capacity\r
   //\r
-  if (Action == ACTION_NO_ACTION) {\r
-    NeedReadCapacity = FALSE;\r
-  } else {\r
+  if (Action == ACTION_READ_CAPACITY) {\r
     NeedReadCapacity = TRUE;\r
   }\r
 \r
@@ -784,63 +789,45 @@ Returns:
     //\r
     // retrieve media information\r
     //\r
-    MaxRetry = 3;\r
-    for (Index = 0; Index < MaxRetry; Index++) {\r
-\r
-      ReadCapacityStatus = ScsiDiskReadCapacity (\r
-                            ScsiDiskDevice,\r
-                            &NeedRetry,\r
-                            &SenseData,\r
-                            &NumberOfSenseKeys\r
-                            );\r
-      if (EFI_ERROR (ReadCapacityStatus) && !NeedRetry) {\r
-        return EFI_DEVICE_ERROR;\r
-      }\r
-      //\r
-      // analyze sense key to action\r
-      //\r
-      Status = DetectMediaParsingSenseKeys (\r
-                ScsiDiskDevice,\r
-                SenseData,\r
-                NumberOfSenseKeys,\r
-                &Action\r
-                );\r
-      //\r
-      // if Status is error, it may indicate crisis error,\r
-      // so return without retry.\r
-      //\r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
-\r
-      switch (Action) {\r
-      case ACTION_NO_ACTION:\r
-        //\r
-        // no retry\r
-        //\r
-        Index = MaxRetry;\r
-        break;\r
-\r
-      case ACTION_RETRY_COMMAND_LATER:\r
-        //\r
-        // retry the ReadCapacity later and continuously, until the condition\r
-        // no longer emerges.\r
-        // stall time is 100000us, or say 0.1 second.\r
-        //\r
-        gBS->Stall (100000);\r
-        Index = 0;\r
-        break;\r
-\r
-      default:\r
+    for (Retry = 0; Retry < MaxRetry; Retry++) {\r
+      Status = ScsiDiskReadCapacity (\r
+                 ScsiDiskDevice,\r
+                 &NeedRetry,\r
+                 &SenseData,\r
+                 &NumberOfSenseKeys\r
+                 );\r
+      if (!EFI_ERROR (Status)) {\r
         //\r
-        // other cases, just retry the command\r
+        // analyze sense key to action\r
         //\r
-        break;\r
+        Status = DetectMediaParsingSenseKeys (\r
+                   ScsiDiskDevice,\r
+                   SenseData,\r
+                   NumberOfSenseKeys,\r
+                   &Action\r
+                   );\r
+        if (EFI_ERROR (Status)) {\r
+          //\r
+          // if Status is error, it may indicate crisis error,\r
+          // so return without retry.\r
+          //\r
+          goto EXIT;\r
+        } else if (Action == ACTION_RETRY_COMMAND_LATER) {\r
+          Retry = 0;\r
+          continue;\r
+        } else {\r
+          break;\r
+        }\r
+      } else {   \r
+        Retry++;\r
+        if (!NeedRetry || (Retry >= MaxRetry)) {\r
+          goto EXIT;\r
+        }\r
       }\r
     }\r
 \r
-    if ((Index == MaxRetry) && EFI_ERROR (ReadCapacityStatus)) {\r
-      return EFI_DEVICE_ERROR;\r
+    if (EFI_ERROR (Status)) {\r
+      goto EXIT;\r
     }\r
   }\r
 \r
@@ -882,48 +869,49 @@ Returns:
     *MediaChange = TRUE;\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+EXIT:\r
+  if (TimeoutEvt != NULL) {\r
+    gBS->CloseEvent (TimeoutEvt);\r
+  }\r
+  return Status;\r
 }\r
 \r
-EFI_STATUS\r
-ScsiDiskInquiryDevice (\r
-  SCSI_DISK_DEV   *ScsiDiskDevice,\r
-  BOOLEAN         *NeedRetry\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Send out Inquiry command to Device\r
-\r
-Arguments:\r
 \r
-  ScsiDiskDevice  - The pointer of SCSI_DISK_DEV\r
-  NeedRetry       - Indicates if needs try again when error happens\r
+/**\r
+  Send out Inquiry command to Device.\r
 \r
-Returns:\r
+  @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV\r
+  @param  NeedRetry       Indicates if needs try again when error happens\r
 \r
-  EFI_DEVICE_ERROR   - Indicates that error occurs\r
-  EFI_SUCCESS        - Successfully to detect media\r
+  @retval  EFI_DEVICE_ERROR  Indicates that error occurs\r
+  @retval  EFI_SUCCESS       Successfully to detect media\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ScsiDiskInquiryDevice (\r
+  IN OUT  SCSI_DISK_DEV   *ScsiDiskDevice,\r
+     OUT  BOOLEAN         *NeedRetry\r
+  )\r
 {\r
-  UINT32              InquiryDataLength;\r
-  UINT8               SenseDataLength;\r
-  UINT8               HostAdapterStatus;\r
-  UINT8               TargetStatus;\r
-  EFI_SCSI_SENSE_DATA *SenseDataArray;\r
-  UINTN               NumberOfSenseKeys;\r
-  EFI_STATUS          Status;\r
-  UINT8               MaxRetry;\r
-  UINT8               Index;\r
+  UINT32                                InquiryDataLength;\r
+  UINT8                                 SenseDataLength;\r
+  UINT8                                 HostAdapterStatus;\r
+  UINT8                                 TargetStatus;\r
+  EFI_SCSI_SENSE_DATA                   *SenseDataArray;\r
+  UINTN                                 NumberOfSenseKeys;\r
+  EFI_STATUS                            Status;\r
+  UINT8                                 MaxRetry;\r
+  UINT8                                 Index;\r
+  EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE SupportedVpdPages;\r
+  EFI_SCSI_BLOCK_LIMITS_VPD_PAGE        BlockLimits;\r
+  UINTN                                 PageLength;\r
 \r
   InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
   SenseDataLength   = 0;\r
 \r
   Status = ScsiInquiryCommand (\r
             ScsiDiskDevice->ScsiIo,\r
-            EFI_SCSI_STALL_SECONDS (1),\r
+            EFI_TIMER_PERIOD_SECONDS (1),\r
             NULL,\r
             &SenseDataLength,\r
             &HostAdapterStatus,\r
@@ -936,27 +924,86 @@ Returns:
     // no need to check HostAdapterStatus and TargetStatus\r
     //\r
   if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
-     ParseInquiryData (ScsiDiskDevice);\r
-     return EFI_SUCCESS;\r
\r
-   } else if (Status == EFI_NOT_READY) {\r
-     *NeedRetry = TRUE;\r
-     return EFI_DEVICE_ERROR;\r
\r
-   } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
-     *NeedRetry = FALSE;\r
-     return EFI_DEVICE_ERROR;\r
-   }\r
-   //\r
-   // go ahead to check HostAdapterStatus and TargetStatus\r
-   // (EFI_TIMEOUT, EFI_DEVICE_ERROR)\r
-   //\r
+    ParseInquiryData (ScsiDiskDevice);\r
+\r
+    if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {\r
+      //\r
+      // Check whether the device supports Block Limits VPD page (0xB0)\r
+      //\r
+      ZeroMem (&SupportedVpdPages, sizeof (SupportedVpdPages));\r
+      InquiryDataLength = sizeof (SupportedVpdPages);\r
+      SenseDataLength   = 0;\r
+      Status = ScsiInquiryCommandEx (\r
+                 ScsiDiskDevice->ScsiIo,\r
+                 EFI_TIMER_PERIOD_SECONDS (1),\r
+                 NULL,\r
+                 &SenseDataLength,\r
+                 &HostAdapterStatus,\r
+                 &TargetStatus,\r
+                 (VOID *) &SupportedVpdPages,\r
+                 &InquiryDataLength,\r
+                 TRUE,\r
+                 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD\r
+                 );\r
+      if (!EFI_ERROR (Status)) {\r
+        PageLength = (SupportedVpdPages.PageLength2 << 8)\r
+                   |  SupportedVpdPages.PageLength1;\r
+        for (Index = 0; Index < PageLength; Index++) {\r
+          if (SupportedVpdPages.SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {\r
+            break;\r
+          }\r
+        }\r
+\r
+        //\r
+        // Query the Block Limits VPD page\r
+        //\r
+        if (Index < PageLength) {\r
+          ZeroMem (&BlockLimits, sizeof (BlockLimits));\r
+          InquiryDataLength = sizeof (BlockLimits);\r
+          SenseDataLength   = 0;\r
+          Status = ScsiInquiryCommandEx (\r
+                     ScsiDiskDevice->ScsiIo,\r
+                     EFI_TIMER_PERIOD_SECONDS (1),\r
+                     NULL,\r
+                     &SenseDataLength,\r
+                     &HostAdapterStatus,\r
+                     &TargetStatus,\r
+                     (VOID *) &BlockLimits,\r
+                     &InquiryDataLength,\r
+                     TRUE,\r
+                     EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD\r
+                     );\r
+          if (!EFI_ERROR (Status)) {\r
+            ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity = \r
+              (BlockLimits.OptimalTransferLengthGranularity2 << 8) |\r
+               BlockLimits.OptimalTransferLengthGranularity1;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    return EFI_SUCCESS;\r
+\r
+  } else if (Status == EFI_NOT_READY) {\r
+    *NeedRetry = TRUE;\r
+    return EFI_DEVICE_ERROR;\r
  \r
-   Status = CheckHostAdapterStatus (HostAdapterStatus);\r
-   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
-     *NeedRetry = TRUE;\r
-     return EFI_DEVICE_ERROR;\r
-   } else if (Status == EFI_DEVICE_ERROR) {\r
+  } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
+    *NeedRetry = FALSE;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // go ahead to check HostAdapterStatus and TargetStatus\r
+  // (EFI_TIMEOUT, EFI_DEVICE_ERROR)\r
+  //\r
+\r
+  Status = CheckHostAdapterStatus (HostAdapterStatus);\r
+  if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
+    *NeedRetry = TRUE;\r
+    return EFI_DEVICE_ERROR;\r
+  } else if (Status == EFI_DEVICE_ERROR) {\r
       //\r
       // reset the scsi channel\r
       //\r
@@ -980,9 +1027,9 @@ Returns:
   }\r
   \r
   //\r
-  // if goes here, meant SubmitInquiryCommand() failed.\r
+  // if goes here, meant ScsiInquiryCommand() failed.\r
   // if ScsiDiskRequestSenseKeys() succeeds at last,\r
-  // better retry SubmitInquiryCommand(). (by setting *NeedRetry = TRUE)\r
+  // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)\r
   //\r
   MaxRetry = 3;\r
   for (Index = 0; Index < MaxRetry; Index++) {\r
@@ -1010,34 +1057,29 @@ Returns:
   return EFI_DEVICE_ERROR;\r
 }\r
 \r
-EFI_STATUS\r
-ScsiDiskTestUnitReady (\r
-  SCSI_DISK_DEV         *ScsiDiskDevice,\r
-  BOOLEAN               *NeedRetry,\r
-  EFI_SCSI_SENSE_DATA   **SenseDataArray,\r
-  UINTN                 *NumberOfSenseKeys\r
-  )\r
- /*++\r
-\r
-Routine Description:\r
+/**\r
+  To test device.\r
 \r
   When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;\r
   When Test Unit Ready command encounters any error caused by host adapter or\r
   target, return error without retrieving Sense Keys.\r
-  \r
-Arguments:\r
 \r
-  ScsiDiskDevice  - The pointer of SCSI_DISK_DEV\r
-  NeedRetry       - The pointer of flag indicates try again\r
-  SenseDataArray  - The pointer of an array of sense data\r
-  NumberOfSenseKeys - The pointer of the number of sense data array\r
-  \r
-Returns:\r
+  @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV\r
+  @param  NeedRetry          The pointer of flag indicates try again\r
+  @param  SenseDataArray     The pointer of an array of sense data\r
+  @param  NumberOfSenseKeys  The pointer of the number of sense data array\r
 \r
-  EFI_DEVICE_ERROR   - Indicates that error occurs\r
-  EFI_SUCCESS        - Successfully to test unit\r
+  @retval EFI_DEVICE_ERROR   Indicates that error occurs\r
+  @retval EFI_SUCCESS        Successfully to test unit\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ScsiDiskTestUnitReady (\r
+  IN  SCSI_DISK_DEV         *ScsiDiskDevice,\r
+  OUT BOOLEAN               *NeedRetry,\r
+  OUT EFI_SCSI_SENSE_DATA   **SenseDataArray,\r
+  OUT UINTN                 *NumberOfSenseKeys\r
+  )\r
 {\r
   EFI_STATUS  Status;\r
   UINT8       SenseDataLength;\r
@@ -1054,7 +1096,7 @@ Returns:
   //\r
   Status = ScsiTestUnitReadyCommand (\r
             ScsiDiskDevice->ScsiIo,\r
-            EFI_SCSI_STALL_SECONDS (1),\r
+            EFI_TIMER_PERIOD_SECONDS (1),\r
             NULL,\r
             &SenseDataLength,\r
             &HostAdapterStatus,\r
@@ -1128,32 +1170,25 @@ Returns:
   return EFI_DEVICE_ERROR;\r
 }\r
 \r
-EFI_STATUS\r
-DetectMediaParsingSenseKeys (\r
-  SCSI_DISK_DEV           *ScsiDiskDevice,\r
-  EFI_SCSI_SENSE_DATA     *SenseData,\r
-  UINTN                   NumberOfSenseKeys,\r
-  UINTN                   *Action\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
+/**\r
   Parsing Sense Keys which got from request sense command.\r
-  \r
-Arguments:\r
 \r
-  ScsiDiskDevice    - The pointer of SCSI_DISK_DEV\r
-  SenseData         - The pointer of EFI_SCSI_SENSE_DATA\r
-  NumberOfSenseKeys - The number of sense key  \r
-  Action            - The pointer of action which indicates what is need to do next\r
+  @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV\r
+  @param  SenseData          The pointer of EFI_SCSI_SENSE_DATA\r
+  @param  NumberOfSenseKeys  The number of sense key  \r
+  @param  Action             The pointer of action which indicates what is need to do next\r
 \r
-Returns:\r
+  @retval EFI_DEVICE_ERROR   Indicates that error occurs\r
+  @retval EFI_SUCCESS        Successfully to complete the parsing\r
 \r
-  EFI_DEVICE_ERROR   - Indicates that error occurs\r
-  EFI_SUCCESS        - Successfully to complete the parsing\r
-\r
---*/\r
+**/\r
+EFI_STATUS\r
+DetectMediaParsingSenseKeys (\r
+  OUT  SCSI_DISK_DEV           *ScsiDiskDevice,\r
+  IN   EFI_SCSI_SENSE_DATA     *SenseData,\r
+  IN   UINTN                   NumberOfSenseKeys,\r
+  OUT  UINTN                   *Action\r
+  )\r
 {\r
   BOOLEAN RetryLater;\r
 \r
@@ -1163,7 +1198,9 @@ Returns:
   *Action = ACTION_READ_CAPACITY;\r
 \r
   if (NumberOfSenseKeys == 0) {\r
-    *Action = ACTION_NO_ACTION;\r
+    if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {\r
+      *Action = ACTION_NO_ACTION;\r
+    }\r
     return EFI_SUCCESS;\r
   }\r
 \r
@@ -1171,7 +1208,9 @@ Returns:
     //\r
     // No Sense Key returned from last submitted command\r
     //\r
-    *Action = ACTION_NO_ACTION;\r
+    if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {\r
+      *Action = ACTION_NO_ACTION;\r
+    }\r
     return EFI_SUCCESS;\r
   }\r
 \r
@@ -1187,13 +1226,20 @@ Returns:
     return EFI_SUCCESS;\r
   }\r
 \r
+  if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {\r
+    *Action = ACTION_RETRY_COMMAND_LATER;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
   if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {\r
     ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;\r
     ScsiDiskDevice->BlkIo.Media->LastBlock    = 0;\r
+    *Action = ACTION_NO_ACTION;\r
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
   if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {\r
+    *Action = ACTION_NO_ACTION;\r
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
@@ -1202,75 +1248,101 @@ Returns:
       *Action = ACTION_RETRY_COMMAND_LATER;\r
       return EFI_SUCCESS;\r
     }\r
-\r
+    *Action = ACTION_NO_ACTION;\r
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
-EFI_STATUS\r
-ScsiDiskReadCapacity (\r
-  SCSI_DISK_DEV           *ScsiDiskDevice,\r
-  BOOLEAN                 *NeedRetry,\r
-  EFI_SCSI_SENSE_DATA     **SenseDataArray,\r
-  UINTN                   *NumberOfSenseKeys\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
 \r
-  Send read capacity command to device and get the device parameter\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice     -  The pointer of SCSI_DISK_DEV\r
-  NeedRetry          -  The pointer of flag indicates if need a retry\r
-  SenseDataArray     -  The pointer of an array of sense data\r
-  NumberOfSenseKeys  -  The number of sense key\r
+/**\r
+  Send read capacity command to device and get the device parameter.\r
 \r
-Returns:\r
+  @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV\r
+  @param  NeedRetry          The pointer of flag indicates if need a retry\r
+  @param  SenseDataArray     The pointer of an array of sense data\r
+  @param  NumberOfSenseKeys  The number of sense key\r
 \r
-  EFI_DEVICE_ERROR   - Indicates that error occurs\r
-  EFI_SUCCESS        - Successfully to read capacity\r
+  @retval EFI_DEVICE_ERROR   Indicates that error occurs\r
+  @retval EFI_SUCCESS        Successfully to read capacity or sense data is received.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ScsiDiskReadCapacity (\r
+  IN  OUT  SCSI_DISK_DEV           *ScsiDiskDevice,\r
+      OUT  BOOLEAN                 *NeedRetry,\r
+      OUT  EFI_SCSI_SENSE_DATA     **SenseDataArray,\r
+      OUT  UINTN                   *NumberOfSenseKeys\r
+  )\r
 {\r
-  EFI_SCSI_DISK_CAPACITY_DATA CapacityData;\r
-  UINT32                      DataLength;\r
-  UINT8                       HostAdapterStatus;\r
-  UINT8                       TargetStatus;\r
-  EFI_STATUS                  CommandStatus;\r
-  EFI_STATUS                  Status;\r
-  UINT8                       Index;\r
-  UINT8                       MaxRetry;\r
-  UINT8                       SenseDataLength;\r
-\r
-  SenseDataLength = 0;\r
-  ZeroMem (&CapacityData, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
-  DataLength          = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);\r
+  UINT8                         HostAdapterStatus;\r
+  UINT8                         TargetStatus;\r
+  EFI_STATUS                    CommandStatus;\r
+  EFI_STATUS                    Status;\r
+  UINT8                         Index;\r
+  UINT8                         MaxRetry;\r
+  UINT8                         SenseDataLength;\r
+  UINT32                        DataLength10;\r
+  UINT32                        DataLength16;\r
+  EFI_SCSI_DISK_CAPACITY_DATA   CapacityData10;\r
+  EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16;\r
+\r
+\r
+  SenseDataLength       = 0;\r
+  DataLength10          = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);\r
+  DataLength16          = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);\r
+  ZeroMem (&CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
+  ZeroMem (&CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));\r
 \r
   *NumberOfSenseKeys  = 0;\r
   *NeedRetry          = FALSE;\r
+\r
   //\r
-  // submit Read Capacity Command. in this call,not request sense data\r
+  // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh, \r
+  // 16 byte command should be used to access large hard disk >2TB\r
   //\r
   CommandStatus = ScsiReadCapacityCommand (\r
                     ScsiDiskDevice->ScsiIo,\r
-                    EFI_SCSI_STALL_SECONDS (1),\r
+                    EFI_TIMER_PERIOD_SECONDS(1),\r
                     NULL,\r
                     &SenseDataLength,\r
                     &HostAdapterStatus,\r
                     &TargetStatus,\r
-                    (VOID *) &CapacityData,\r
-                    &DataLength,\r
+                    (VOID *) &CapacityData10,\r
+                    &DataLength10,\r
                     FALSE\r
                     );\r
-  //\r
+\r
+  ScsiDiskDevice->Cdb16Byte = FALSE;\r
+  if ((!EFI_ERROR (CommandStatus)) && (CapacityData10.LastLba3 == 0xff) && (CapacityData10.LastLba2 == 0xff) &&\r
+      (CapacityData10.LastLba1 == 0xff) && (CapacityData10.LastLba0 == 0xff)) {\r
+    //\r
+    // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB\r
+    //\r
+    ScsiDiskDevice->Cdb16Byte = TRUE;\r
+    //\r
+    // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock\r
+    // and LowestAlignedLba\r
+    //\r
+    CommandStatus = ScsiReadCapacity16Command (\r
+                      ScsiDiskDevice->ScsiIo,\r
+                      EFI_TIMER_PERIOD_SECONDS (1),\r
+                      NULL,\r
+                      &SenseDataLength,\r
+                      &HostAdapterStatus,\r
+                      &TargetStatus,\r
+                      (VOID *) &CapacityData16,\r
+                      &DataLength16,\r
+                      FALSE\r
+                      );\r
+  }\r
+\r
+    //\r
     // no need to check HostAdapterStatus and TargetStatus\r
     //\r
    if (CommandStatus == EFI_SUCCESS) {\r
-     GetMediaInfo (ScsiDiskDevice, &CapacityData);\r
+     GetMediaInfo (ScsiDiskDevice, &CapacityData10,&CapacityData16);\r
      return EFI_SUCCESS;\r
  \r
    } else if (CommandStatus == EFI_NOT_READY) {\r
@@ -1315,9 +1387,9 @@ Returns:
   }\r
   \r
   //\r
-  // if goes here, meant SubmitReadCapacityCommand() failed.\r
+  // if goes here, meant ScsiReadCapacityCommand() failed.\r
   // if ScsiDiskRequestSenseKeys() succeeds at last,\r
-  // better retry SubmitReadCapacityCommand(). (by setting *NeedRetry = TRUE)\r
+  // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)\r
   //\r
   MaxRetry = 3;\r
   for (Index = 0; Index < MaxRetry; Index++) {\r
@@ -1330,8 +1402,7 @@ Returns:
               TRUE\r
               );\r
     if (!EFI_ERROR (Status)) {\r
-      *NeedRetry = TRUE;\r
-      return EFI_DEVICE_ERROR;\r
+      return EFI_SUCCESS;\r
     }\r
 \r
     if (!*NeedRetry) {\r
@@ -1346,28 +1417,21 @@ Returns:
   return EFI_DEVICE_ERROR;\r
 }\r
 \r
-EFI_STATUS\r
-CheckHostAdapterStatus (\r
-  UINT8   HostAdapterStatus\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Check the HostAdapter status\r
-  \r
-Arguments:\r
-\r
-  HostAdapterStatus - Host Adapter status\r
+/**\r
+  Check the HostAdapter status and re-interpret it in EFI_STATUS.\r
 \r
-Returns:\r
+  @param  HostAdapterStatus  Host Adapter status\r
 \r
-  EFI_SUCCESS       \r
-  EFI_TIMEOUT       \r
-  EFI_NOT_READY     \r
-  EFI_DEVICE_ERROR  \r
+  @retval  EFI_SUCCESS       Host adapter is OK.\r
+  @retval  EFI_TIMEOUT       Timeout.\r
+  @retval  EFI_NOT_READY     Adapter NOT ready.\r
+  @retval  EFI_DEVICE_ERROR  Adapter device error.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+CheckHostAdapterStatus (\r
+  IN UINT8   HostAdapterStatus\r
+  )\r
 {\r
   switch (HostAdapterStatus) {\r
   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:\r
@@ -1394,27 +1458,21 @@ Returns:
   }\r
 }\r
 \r
-EFI_STATUS\r
-CheckTargetStatus (\r
-  UINT8   TargetStatus\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
 \r
-  Check the target status\r
-  \r
-Arguments:\r
-\r
-  TargetStatus  - Target status\r
+/**\r
+  Check the target status and re-interpret it in EFI_STATUS.\r
 \r
-Returns:\r
+  @param  TargetStatus  Target status\r
 \r
-  EFI_NOT_READY  \r
-  EFI_DEVICE_ERROR \r
-  EFI_SUCCESS\r
+  @retval EFI_NOT_READY       Device is NOT ready.\r
+  @retval EFI_DEVICE_ERROR \r
+  @retval EFI_SUCCESS\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+CheckTargetStatus (\r
+  IN  UINT8   TargetStatus\r
+  )\r
 {\r
   switch (TargetStatus) {\r
   case EFI_EXT_SCSI_STATUS_TARGET_GOOD:\r
@@ -1437,39 +1495,32 @@ Returns:
   }\r
 }\r
 \r
-EFI_STATUS\r
-ScsiDiskRequestSenseKeys (\r
-  SCSI_DISK_DEV           *ScsiDiskDevice,\r
-  BOOLEAN                 *NeedRetry,\r
-  EFI_SCSI_SENSE_DATA     **SenseDataArray,\r
-  UINTN                   *NumberOfSenseKeys,\r
-  BOOLEAN                 AskResetIfError\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
 \r
+/**\r
   Retrieve all sense keys from the device.\r
-  When encountering error during the process,\r
-  if retrieve sense keys before error encounterred,\r
-  return the sense keys with return status set to EFI_SUCCESS,\r
-  and NeedRetry set to FALSE; otherwize, return the proper return\r
-  status.\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice     -  The pointer of SCSI_DISK_DEV\r
-  NeedRetry          -  The pointer of flag indicates if need a retry\r
-  SenseDataArray     -  The pointer of an array of sense data\r
-  NumberOfSenseKeys  -  The number of sense key\r
-  AskResetIfError    -  The flag indicates if need reset when error occurs\r
-  \r
-Returns:\r
 \r
-  EFI_DEVICE_ERROR   - Indicates that error occurs\r
-  EFI_SUCCESS        - Successfully to request sense key\r
+  When encountering error during the process, if retrieve sense keys before\r
+  error encountered, it returns the sense keys with return status set to EFI_SUCCESS,\r
+  and NeedRetry set to FALSE; otherwize, return the proper return status.\r
+\r
+  @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV\r
+  @param  NeedRetry          The pointer of flag indicates if need a retry\r
+  @param  SenseDataArray     The pointer of an array of sense data\r
+  @param  NumberOfSenseKeys  The number of sense key\r
+  @param  AskResetIfError    The flag indicates if need reset when error occurs\r
 \r
---*/\r
+  @retval EFI_DEVICE_ERROR   Indicates that error occurs\r
+  @retval EFI_SUCCESS        Successfully to request sense key\r
+\r
+**/\r
+EFI_STATUS\r
+ScsiDiskRequestSenseKeys (\r
+  IN  OUT  SCSI_DISK_DEV           *ScsiDiskDevice,\r
+      OUT  BOOLEAN                 *NeedRetry,\r
+      OUT  EFI_SCSI_SENSE_DATA     **SenseDataArray,\r
+      OUT  UINTN                   *NumberOfSenseKeys,\r
+  IN       BOOLEAN                 AskResetIfError\r
+  )\r
 {\r
   EFI_SCSI_SENSE_DATA *PtrSenseData;\r
   UINT8               SenseDataLength;\r
@@ -1480,7 +1531,7 @@ Returns:
   UINT8               TargetStatus;\r
 \r
   FallStatus      = EFI_SUCCESS;\r
-  SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);\r
+  SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA);\r
 \r
   ZeroMem (\r
     ScsiDiskDevice->SenseData,\r
@@ -1494,7 +1545,7 @@ Returns:
   for (SenseReq = TRUE; SenseReq;) {\r
     Status = ScsiRequestSenseCommand (\r
               ScsiDiskDevice->ScsiIo,\r
-              EFI_SCSI_STALL_SECONDS (2),\r
+              EFI_TIMER_PERIOD_SECONDS (2),\r
               PtrSenseData,\r
               &SenseDataLength,\r
               &HostAdapterStatus,\r
@@ -1543,38 +1594,59 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
-VOID\r
-GetMediaInfo (\r
-  SCSI_DISK_DEV                 *ScsiDiskDevice,\r
-  EFI_SCSI_DISK_CAPACITY_DATA   *Capacity\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Get information from media read capacity command\r
 \r
-Arguments:\r
-\r
-  ScsiDiskDevice  - The pointer of SCSI_DISK_DEV\r
-  Capacity        - The pointer of EFI_SCSI_DISK_CAPACITY_DATA\r
-\r
-Returns:\r
+/**\r
+  Get information from media read capacity command.\r
 \r
-  NONE\r
+  @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV\r
+  @param  Capacity10      The pointer of EFI_SCSI_DISK_CAPACITY_DATA\r
+  @param  Capacity16      The pointer of EFI_SCSI_DISK_CAPACITY_DATA16\r
 \r
---*/\r
+**/\r
+VOID\r
+GetMediaInfo (\r
+  IN OUT SCSI_DISK_DEV                  *ScsiDiskDevice,\r
+  IN     EFI_SCSI_DISK_CAPACITY_DATA    *Capacity10,\r
+  IN     EFI_SCSI_DISK_CAPACITY_DATA16  *Capacity16\r
+  )\r
 {\r
-  ScsiDiskDevice->BlkIo.Media->LastBlock =  (Capacity->LastLba3 << 24) |\r
-                                            (Capacity->LastLba2 << 16) |\r
-                                            (Capacity->LastLba1 << 8)  |\r
-                                             Capacity->LastLba0;\r
+  UINT8       *Ptr;\r
+\r
+  if (!ScsiDiskDevice->Cdb16Byte) {\r
+    ScsiDiskDevice->BlkIo.Media->LastBlock =  (Capacity10->LastLba3 << 24) |\r
+                                              (Capacity10->LastLba2 << 16) |\r
+                                              (Capacity10->LastLba1 << 8)  |\r
+                                               Capacity10->LastLba0;\r
+  \r
+    ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |\r
+                                             (Capacity10->BlockSize2 << 16) | \r
+                                             (Capacity10->BlockSize1 << 8)  |\r
+                                              Capacity10->BlockSize0;\r
+    ScsiDiskDevice->BlkIo.Media->LowestAlignedLba               = 0;\r
+    ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock  = 0;\r
+  } else {\r
+    Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;\r
+    *Ptr++ = Capacity16->LastLba0;\r
+    *Ptr++ = Capacity16->LastLba1;\r
+    *Ptr++ = Capacity16->LastLba2;\r
+    *Ptr++ = Capacity16->LastLba3;\r
+    *Ptr++ = Capacity16->LastLba4;\r
+    *Ptr++ = Capacity16->LastLba5;\r
+    *Ptr++ = Capacity16->LastLba6;\r
+    *Ptr   = Capacity16->LastLba7;\r
+\r
+    ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |\r
+                                             (Capacity16->BlockSize2 << 16) | \r
+                                             (Capacity16->BlockSize1 << 8)  |\r
+                                              Capacity16->BlockSize0;\r
+\r
+    ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) |\r
+                                                     Capacity16->LowestAlignLogic1;\r
+    ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock  = (1 << Capacity16->LogicPerPhysical);\r
+  }\r
 \r
   ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;\r
-  ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity->BlockSize3 << 24) |\r
-                                           (Capacity->BlockSize2 << 16) | \r
-                                           (Capacity->BlockSize1 << 8)  |\r
-                                            Capacity->BlockSize0;\r
+  \r
   if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {\r
     ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;\r
   }\r
@@ -1584,60 +1656,42 @@ Returns:
   }\r
 }\r
 \r
+/**\r
+  Parse Inquiry data.\r
+\r
+  @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV\r
+\r
+**/\r
 VOID\r
 ParseInquiryData (\r
-  SCSI_DISK_DEV   *ScsiDiskDevice\r
+  IN OUT SCSI_DISK_DEV   *ScsiDiskDevice\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Parse Inquiry data\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice  - The pointer of SCSI_DISK_DEV\r
-\r
-Returns:\r
-\r
-  NONE\r
-\r
---*/\r
 {\r
-  ScsiDiskDevice->FixedDevice               = (BOOLEAN) (ScsiDiskDevice->InquiryData.RMB ? 0 : 1);\r
+  ScsiDiskDevice->FixedDevice               = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);\r
   ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);\r
 }\r
 \r
-EFI_STATUS\r
-EFIAPI\r
-ScsiDiskReadSectors (\r
-  SCSI_DISK_DEV     *ScsiDiskDevice,\r
-  VOID              *Buffer,\r
-  EFI_LBA           Lba,\r
-  UINTN             NumberOfBlocks\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Read sector from SCSI Disk\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice  - The poiniter of SCSI_DISK_DEV\r
-  Buffer          - The buffer to fill in the read out data\r
-  Lba             - Logic block address\r
-  NumberOfBlocks  - The number of blocks to read\r
+/**\r
+  Read sector from SCSI Disk.\r
 \r
-Returns:\r
+  @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV\r
+  @param  Buffer          The buffer to fill in the read out data\r
+  @param  Lba             Logic block address\r
+  @param  NumberOfBlocks  The number of blocks to read\r
 \r
-  EFI_DEVICE_ERROR\r
-  EFI_SUCCESS\r
+  @retval EFI_DEVICE_ERROR  Indicates a device error.\r
+  @retval EFI_SUCCESS       Operation is successful.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ScsiDiskReadSectors (\r
+  IN   SCSI_DISK_DEV     *ScsiDiskDevice,\r
+  OUT  VOID              *Buffer,\r
+  IN   EFI_LBA           Lba,\r
+  IN   UINTN             NumberOfBlocks\r
+  )\r
 {\r
   UINTN               BlocksRemaining;\r
-  UINT32              Lba32;\r
   UINT8               *PtrBuffer;\r
   UINT32              BlockSize;\r
   UINT32              ByteCount;\r
@@ -1658,41 +1712,60 @@ Returns:
 \r
   BlocksRemaining   = NumberOfBlocks;\r
   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
+  \r
   //\r
-  // limit the data bytes that can be transferred by one Read(10) Command\r
+  // limit the data bytes that can be transferred by one Read(10) or Read(16) Command\r
   //\r
-  MaxBlock  = 65536;\r
+  if (!ScsiDiskDevice->Cdb16Byte) {\r
+    MaxBlock         = 0xFFFF;\r
+  } else {\r
+    MaxBlock         = 0xFFFFFFFF;\r
+  }\r
 \r
   PtrBuffer = Buffer;\r
-  Lba32     = (UINT32) Lba;\r
 \r
   while (BlocksRemaining > 0) {\r
 \r
     if (BlocksRemaining <= MaxBlock) {\r
-\r
-      SectorCount = (UINT16) BlocksRemaining;\r
+      if (!ScsiDiskDevice->Cdb16Byte) {\r
+        SectorCount = (UINT16) BlocksRemaining;\r
+      } else {\r
+        SectorCount = (UINT32) BlocksRemaining;\r
+      }\r
     } else {\r
-\r
       SectorCount = MaxBlock;\r
     }\r
 \r
     ByteCount = SectorCount * BlockSize;\r
-    Timeout   = EFI_SCSI_STALL_SECONDS (2);\r
+    Timeout   = EFI_TIMER_PERIOD_SECONDS (2);\r
 \r
     MaxRetry  = 2;\r
     for (Index = 0; Index < MaxRetry; Index++) {\r
-\r
-      Status = ScsiDiskRead10 (\r
-                ScsiDiskDevice,\r
-                &NeedRetry,\r
-                &SenseData,\r
-                &NumberOfSenseKeys,\r
-                Timeout,\r
-                PtrBuffer,\r
-                &ByteCount,\r
-                Lba32,\r
-                SectorCount\r
-                );\r
+      if (!ScsiDiskDevice->Cdb16Byte) {\r
+        Status = ScsiDiskRead10 (\r
+                  ScsiDiskDevice,\r
+                  &NeedRetry,\r
+                  &SenseData,\r
+                  &NumberOfSenseKeys,\r
+                  Timeout,\r
+                  PtrBuffer,\r
+                  &ByteCount,\r
+                  (UINT32) Lba,\r
+                  SectorCount\r
+                  );\r
+      } else {\r
+        Status = ScsiDiskRead16 (\r
+                  ScsiDiskDevice,\r
+                  &NeedRetry,\r
+                  &SenseData,\r
+                  &NumberOfSenseKeys,\r
+                  Timeout,\r
+                  PtrBuffer,\r
+                  &ByteCount,\r
+                  Lba,\r
+                  SectorCount\r
+                  );\r
+      }\r
       if (!EFI_ERROR (Status)) {\r
         break;\r
       }\r
@@ -1712,7 +1785,7 @@ Returns:
     //\r
     SectorCount = ByteCount / BlockSize;\r
 \r
-    Lba32 += SectorCount;\r
+    Lba += SectorCount;\r
     PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
     BlocksRemaining -= SectorCount;\r
   }\r
@@ -1720,35 +1793,27 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
-EFI_STATUS\r
-ScsiDiskWriteSectors (\r
-  SCSI_DISK_DEV     *ScsiDiskDevice,\r
-  VOID              *Buffer,\r
-  EFI_LBA           Lba,\r
-  UINTN             NumberOfBlocks\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Write SCSI Disk sectors\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice  - The pointer of SCSI_DISK_DEV\r
-  Buffer          - The data buffer to write sector\r
-  Lba             - Logic block address\r
-  NumberOfBlocks  - The number of blocks to write\r
+/**\r
+  Write sector to SCSI Disk.\r
 \r
-Returns:\r
+  @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV\r
+  @param  Buffer          The buffer of data to be written into SCSI Disk\r
+  @param  Lba             Logic block address\r
+  @param  NumberOfBlocks  The number of blocks to read\r
 \r
-  EFI_DEVICE_ERROR \r
-  EFI_SUCCESS\r
+  @retval EFI_DEVICE_ERROR  Indicates a device error.\r
+  @retval EFI_SUCCESS       Operation is successful.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ScsiDiskWriteSectors (\r
+  IN  SCSI_DISK_DEV     *ScsiDiskDevice,\r
+  IN  VOID              *Buffer,\r
+  IN  EFI_LBA           Lba,\r
+  IN  UINTN             NumberOfBlocks\r
+  )\r
 {\r
   UINTN               BlocksRemaining;\r
-  UINT32              Lba32;\r
   UINT8               *PtrBuffer;\r
   UINT32              BlockSize;\r
   UINT32              ByteCount;\r
@@ -1769,39 +1834,59 @@ Returns:
 \r
   BlocksRemaining   = NumberOfBlocks;\r
   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
+\r
   //\r
-  // limit the data bytes that can be transferred by one Write(10) Command\r
+  // limit the data bytes that can be transferred by one Read(10) or Read(16) Command\r
   //\r
-  MaxBlock  = 65536;\r
+  if (!ScsiDiskDevice->Cdb16Byte) {\r
+    MaxBlock         = 0xFFFF;\r
+  } else {\r
+    MaxBlock         = 0xFFFFFFFF;\r
+  }\r
 \r
   PtrBuffer = Buffer;\r
-  Lba32     = (UINT32) Lba;\r
 \r
   while (BlocksRemaining > 0) {\r
 \r
     if (BlocksRemaining <= MaxBlock) {\r
-\r
-      SectorCount = (UINT16) BlocksRemaining;\r
+      if (!ScsiDiskDevice->Cdb16Byte) {\r
+        SectorCount = (UINT16) BlocksRemaining;\r
+      } else {\r
+        SectorCount = (UINT32) BlocksRemaining;\r
+      }\r
     } else {\r
-\r
       SectorCount = MaxBlock;\r
     }\r
 \r
     ByteCount = SectorCount * BlockSize;\r
-    Timeout   = EFI_SCSI_STALL_SECONDS (2);\r
+    Timeout   = EFI_TIMER_PERIOD_SECONDS (2);\r
     MaxRetry  = 2;\r
     for (Index = 0; Index < MaxRetry; Index++) {\r
-      Status = ScsiDiskWrite10 (\r
-                ScsiDiskDevice,\r
-                &NeedRetry,\r
-                &SenseData,\r
-                &NumberOfSenseKeys,\r
-                Timeout,\r
-                PtrBuffer,\r
-                &ByteCount,\r
-                Lba32,\r
-                SectorCount\r
-                );\r
+      if (!ScsiDiskDevice->Cdb16Byte) {\r
+        Status = ScsiDiskWrite10 (\r
+                  ScsiDiskDevice,\r
+                  &NeedRetry,\r
+                  &SenseData,\r
+                  &NumberOfSenseKeys,\r
+                  Timeout,\r
+                  PtrBuffer,\r
+                  &ByteCount,\r
+                  (UINT32) Lba,\r
+                  SectorCount\r
+                  );\r
+      } else {\r
+        Status = ScsiDiskWrite16 (\r
+                  ScsiDiskDevice,\r
+                  &NeedRetry,\r
+                  &SenseData,\r
+                  &NumberOfSenseKeys,\r
+                  Timeout,\r
+                  PtrBuffer,\r
+                  &ByteCount,\r
+                  Lba,\r
+                  SectorCount\r
+                  );         \r
+        }\r
       if (!EFI_ERROR (Status)) {\r
         break;\r
       }\r
@@ -1819,7 +1904,7 @@ Returns:
     //\r
     SectorCount = ByteCount / BlockSize;\r
 \r
-    Lba32 += SectorCount;\r
+    Lba += SectorCount;\r
     PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
     BlocksRemaining -= SectorCount;\r
   }\r
@@ -1827,41 +1912,34 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
+\r
+/**\r
+  Submit Read(10) command.\r
+\r
+  @param  ScsiDiskDevice     The pointer of ScsiDiskDevice\r
+  @param  NeedRetry          The pointer of flag indicates if needs retry if error happens\r
+  @param  SenseDataArray     NOT used yet in this function\r
+  @param  NumberOfSenseKeys  The number of sense key\r
+  @param  Timeout            The time to complete the command\r
+  @param  DataBuffer         The buffer to fill with the read out data\r
+  @param  DataLength         The length of buffer\r
+  @param  StartLba           The start logic block address\r
+  @param  SectorSize         The size of sector\r
+\r
+  @return  EFI_STATUS is returned by calling ScsiRead10Command().\r
+**/\r
 EFI_STATUS\r
 ScsiDiskRead10 (\r
-  SCSI_DISK_DEV         *ScsiDiskDevice,\r
-  BOOLEAN               *NeedRetry,\r
-  EFI_SCSI_SENSE_DATA   **SenseDataArray,\r
-  UINTN                 *NumberOfSenseKeys,\r
-  UINT64                Timeout,\r
-  UINT8                 *DataBuffer,\r
-  UINT32                *DataLength,\r
-  UINT32                StartLba,\r
-  UINT32                SectorSize\r
+  IN     SCSI_DISK_DEV         *ScsiDiskDevice,\r
+     OUT BOOLEAN               *NeedRetry,\r
+     OUT EFI_SCSI_SENSE_DATA   **SenseDataArray,   OPTIONAL\r
+     OUT UINTN                 *NumberOfSenseKeys,\r
+  IN     UINT64                Timeout,\r
+     OUT UINT8                 *DataBuffer,\r
+  IN OUT UINT32                *DataLength,\r
+  IN     UINT32                StartLba,\r
+  IN     UINT32                SectorSize\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Sumbmit Read command \r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice    - The pointer of ScsiDiskDevice\r
-  NeedRetry         - The pointer of flag indicates if needs retry if error happens\r
-  SenseDataArray    - The pointer of an array of sense data\r
-  NumberOfSenseKeys - The number of sense key\r
-  Timeout           - The time to complete the command\r
-  DataBuffer        - The buffer to fill with the read out data\r
-  DataLength        - The length of buffer\r
-  StartLba          - The start logic block address\r
-  SectorSize        - The size of sector\r
-\r
-Returns:\r
-\r
-  EFI_STATUS\r
-  \r
---*/\r
 {\r
   UINT8       SenseDataLength;\r
   EFI_STATUS  Status;\r
@@ -1886,41 +1964,35 @@ Returns:
   return Status;\r
 }\r
 \r
-EFI_STATUS\r
-ScsiDiskWrite10 (\r
-  SCSI_DISK_DEV         *ScsiDiskDevice,\r
-  BOOLEAN               *NeedRetry,\r
-  EFI_SCSI_SENSE_DATA   **SenseDataArray,\r
-  UINTN                 *NumberOfSenseKeys,\r
-  UINT64                Timeout,\r
-  UINT8                 *DataBuffer,\r
-  UINT32                *DataLength,\r
-  UINT32                StartLba,\r
-  UINT32                SectorSize\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
 \r
-  Submit Write Command\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice    - The pointer of ScsiDiskDevice\r
-  NeedRetry         - The pointer of flag indicates if needs retry if error happens\r
-  SenseDataArray    - The pointer of an array of sense data\r
-  NumberOfSenseKeys - The number of sense key\r
-  Timeout           - The time to complete the command\r
-  DataBuffer        - The buffer to fill with the read out data\r
-  DataLength        - The length of buffer\r
-  StartLba          - The start logic block address\r
-  SectorSize        - The size of sector\r
+/**\r
+  Submit Write(10) Command.\r
 \r
-Returns:\r
+  @param  ScsiDiskDevice     The pointer of ScsiDiskDevice\r
+  @param  NeedRetry          The pointer of flag indicates if needs retry if error happens\r
+  @param  SenseDataArray     NOT used yet in this function\r
+  @param  NumberOfSenseKeys  The number of sense key\r
+  @param  Timeout            The time to complete the command\r
+  @param  DataBuffer         The buffer to fill with the read out data\r
+  @param  DataLength         The length of buffer\r
+  @param  StartLba           The start logic block address\r
+  @param  SectorSize         The size of sector\r
 \r
-  EFI_STATUS\r
+  @return  EFI_STATUS is returned by calling ScsiWrite10Command().\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+ScsiDiskWrite10 (\r
+  IN     SCSI_DISK_DEV         *ScsiDiskDevice,\r
+     OUT BOOLEAN               *NeedRetry,\r
+     OUT EFI_SCSI_SENSE_DATA   **SenseDataArray,   OPTIONAL\r
+     OUT UINTN                 *NumberOfSenseKeys,\r
+  IN     UINT64                Timeout,\r
+  IN     UINT8                 *DataBuffer,\r
+  IN OUT UINT32                *DataLength,\r
+  IN     UINT32                StartLba,\r
+  IN     UINT32                SectorSize\r
+  )\r
 {\r
   EFI_STATUS  Status;\r
   UINT8       SenseDataLength;\r
@@ -1945,27 +2017,126 @@ Returns:
   return Status;\r
 }\r
 \r
-BOOLEAN\r
-ScsiDiskIsNoMedia (\r
-  IN  EFI_SCSI_SENSE_DATA   *SenseData,\r
-  IN  UINTN                 SenseCounts\r
-  )\r
-/*++\r
 \r
-Routine Description:\r
+/**\r
+  Submit Read(16) command.\r
+\r
+  @param  ScsiDiskDevice     The pointer of ScsiDiskDevice\r
+  @param  NeedRetry          The pointer of flag indicates if needs retry if error happens\r
+  @param  SenseDataArray     NOT used yet in this function\r
+  @param  NumberOfSenseKeys  The number of sense key\r
+  @param  Timeout            The time to complete the command\r
+  @param  DataBuffer         The buffer to fill with the read out data\r
+  @param  DataLength         The length of buffer\r
+  @param  StartLba           The start logic block address\r
+  @param  SectorSize         The size of sector\r
+\r
+  @return  EFI_STATUS is returned by calling ScsiRead10Command().\r
+**/\r
+EFI_STATUS\r
+ScsiDiskRead16 (\r
+  IN     SCSI_DISK_DEV         *ScsiDiskDevice,\r
+     OUT BOOLEAN               *NeedRetry,\r
+     OUT EFI_SCSI_SENSE_DATA   **SenseDataArray,   OPTIONAL\r
+     OUT UINTN                 *NumberOfSenseKeys,\r
+  IN     UINT64                Timeout,\r
+     OUT UINT8                 *DataBuffer,\r
+  IN OUT UINT32                *DataLength,\r
+  IN     UINT64                StartLba,\r
+  IN     UINT32                SectorSize\r
+  )\r
+{\r
+  UINT8       SenseDataLength;\r
+  EFI_STATUS  Status;\r
+  UINT8       HostAdapterStatus;\r
+  UINT8       TargetStatus;\r
 \r
-  Check sense key to find if media presents\r
+  *NeedRetry          = FALSE;\r
+  *NumberOfSenseKeys  = 0;\r
+  SenseDataLength     = 0;\r
+  Status = ScsiRead16Command (\r
+            ScsiDiskDevice->ScsiIo,\r
+            Timeout,\r
+            NULL,\r
+            &SenseDataLength,\r
+            &HostAdapterStatus,\r
+            &TargetStatus,\r
+            DataBuffer,\r
+            DataLength,\r
+            StartLba,\r
+            SectorSize\r
+            );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Submit Write(16) Command.\r
+\r
+  @param  ScsiDiskDevice     The pointer of ScsiDiskDevice\r
+  @param  NeedRetry          The pointer of flag indicates if needs retry if error happens\r
+  @param  SenseDataArray     NOT used yet in this function\r
+  @param  NumberOfSenseKeys  The number of sense key\r
+  @param  Timeout            The time to complete the command\r
+  @param  DataBuffer         The buffer to fill with the read out data\r
+  @param  DataLength         The length of buffer\r
+  @param  StartLba           The start logic block address\r
+  @param  SectorSize         The size of sector\r
+\r
+  @return  EFI_STATUS is returned by calling ScsiWrite10Command().\r
+\r
+**/\r
+EFI_STATUS\r
+ScsiDiskWrite16 (\r
+  IN     SCSI_DISK_DEV         *ScsiDiskDevice,\r
+     OUT BOOLEAN               *NeedRetry,\r
+     OUT EFI_SCSI_SENSE_DATA   **SenseDataArray,   OPTIONAL\r
+     OUT UINTN                 *NumberOfSenseKeys,\r
+  IN     UINT64                Timeout,\r
+  IN     UINT8                 *DataBuffer,\r
+  IN OUT UINT32                *DataLength,\r
+  IN     UINT64                StartLba,\r
+  IN     UINT32                SectorSize\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       SenseDataLength;\r
+  UINT8       HostAdapterStatus;\r
+  UINT8       TargetStatus;\r
 \r
-Arguments:\r
+  *NeedRetry          = FALSE;\r
+  *NumberOfSenseKeys  = 0;\r
+  SenseDataLength     = 0;\r
+  Status = ScsiWrite16Command (\r
+            ScsiDiskDevice->ScsiIo,\r
+            Timeout,\r
+            NULL,\r
+            &SenseDataLength,\r
+            &HostAdapterStatus,\r
+            &TargetStatus,\r
+            DataBuffer,\r
+            DataLength,\r
+            StartLba,\r
+            SectorSize\r
+            );\r
+  return Status;\r
+}\r
 \r
-  SenseData   - The pointer of EFI_SCSI_SENSE_DATA\r
-  SenseCounts - The number of sense key\r
 \r
-Returns:\r
+/**\r
+  Check sense key to find if media presents.\r
 \r
-  BOOLEAN\r
+  @param  SenseData   The pointer of EFI_SCSI_SENSE_DATA\r
+  @param  SenseCounts The number of sense key\r
 \r
---*/\r
+  @retval TRUE    NOT any media\r
+  @retval FALSE   Media presents\r
+**/\r
+BOOLEAN\r
+ScsiDiskIsNoMedia (\r
+  IN  EFI_SCSI_SENSE_DATA   *SenseData,\r
+  IN  UINTN                 SenseCounts\r
+  )\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -1989,27 +2160,22 @@ Returns:
   return IsNoMedia;\r
 }\r
 \r
+\r
+/**\r
+  Parse sense key.\r
+\r
+  @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA\r
+  @param  SenseCounts  The number of sense key\r
+\r
+  @retval TRUE   Error\r
+  @retval FALSE  NOT error\r
+\r
+**/\r
 BOOLEAN\r
 ScsiDiskIsMediaError (\r
   IN  EFI_SCSI_SENSE_DATA   *SenseData,\r
   IN  UINTN                 SenseCounts\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Parse sense key\r
-\r
-Arguments:\r
-\r
-  SenseData   - The pointer of EFI_SCSI_SENSE_DATA\r
-  SenseCounts - The number of sense key\r
-\r
-Returns:\r
-\r
-  BOOLEAN\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2079,27 +2245,22 @@ Returns:
   return IsError;\r
 }\r
 \r
+\r
+/**\r
+  Check sense key to find if hardware error happens.\r
+\r
+  @param  SenseData     The pointer of EFI_SCSI_SENSE_DATA\r
+  @param  SenseCounts   The number of sense key\r
+\r
+  @retval TRUE  Hardware error exits.\r
+  @retval FALSE NO error.\r
+\r
+**/\r
 BOOLEAN\r
 ScsiDiskIsHardwareError (\r
   IN  EFI_SCSI_SENSE_DATA   *SenseData,\r
   IN  UINTN                 SenseCounts\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Check sense key to find if hardware error happens\r
-\r
-Arguments:\r
-\r
-  SenseData   - The pointer of EFI_SCSI_SENSE_DATA\r
-  SenseCounts - The number of sense key\r
-\r
-Returns:\r
-\r
-  BOOLEAN\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2123,27 +2284,21 @@ Returns:
   return IsError;\r
 }\r
 \r
+\r
+/**\r
+  Check sense key to find if media has changed.\r
+\r
+  @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA\r
+  @param  SenseCounts  The number of sense key\r
+\r
+  @retval TRUE   Media is changed.\r
+  @retval FALSE  Media is NOT changed.\r
+**/\r
 BOOLEAN\r
 ScsiDiskIsMediaChange (\r
   IN  EFI_SCSI_SENSE_DATA   *SenseData,\r
   IN  UINTN                 SenseCounts\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Check sense key to find if media has changed\r
-\r
-Arguments:\r
-\r
-  SenseData   - The pointer of EFI_SCSI_SENSE_DATA\r
-  SenseCounts - The number of sense key\r
-\r
-Returns:\r
-\r
-  BOOLEAN\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2168,27 +2323,21 @@ Returns:
   return IsMediaChanged;\r
 }\r
 \r
+/**\r
+  Check sense key to find if reset happens.\r
+\r
+  @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA\r
+  @param  SenseCounts  The number of sense key\r
+\r
+  @retval TRUE  It is reset before.\r
+  @retval FALSE It is NOT reset before.\r
+\r
+**/\r
 BOOLEAN\r
 ScsiDiskIsResetBefore (\r
   IN  EFI_SCSI_SENSE_DATA   *SenseData,\r
   IN  UINTN                 SenseCounts\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Check sense key to find if reset happens\r
-\r
-Arguments:\r
-\r
-  SenseData   - The pointer of EFI_SCSI_SENSE_DATA\r
-  SenseCounts - The number of sense key\r
-\r
-Returns:\r
-\r
-  BOOLEAN\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2214,29 +2363,23 @@ Returns:
   return IsResetBefore;\r
 }\r
 \r
+/**\r
+  Check sense key to find if the drive is ready.\r
+\r
+  @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA\r
+  @param  SenseCounts  The number of sense key\r
+  @param  RetryLater   The flag means if need a retry \r
+\r
+  @retval TRUE  Drive is ready.\r
+  @retval FALSE Drive is NOT ready.\r
+\r
+**/\r
 BOOLEAN\r
 ScsiDiskIsDriveReady (\r
   IN  EFI_SCSI_SENSE_DATA   *SenseData,\r
   IN  UINTN                 SenseCounts,\r
   OUT BOOLEAN               *RetryLater\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Check sense key to find if the drive is ready\r
-\r
-Arguments:\r
-\r
-  SenseData   - The pointer of EFI_SCSI_SENSE_DATA\r
-  SenseCounts - The number of sense key\r
-  RetryLater  - The flag means if need a retry \r
-\r
-Returns:\r
-\r
-  BOOLEAN\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2291,27 +2434,21 @@ Returns:
   return IsReady;\r
 }\r
 \r
+/**\r
+  Check sense key to find if it has sense key.\r
+\r
+  @param  SenseData   - The pointer of EFI_SCSI_SENSE_DATA\r
+  @param  SenseCounts - The number of sense key\r
+\r
+  @retval TRUE  It has sense key.\r
+  @retval FALSE It has NOT any sense key.\r
+\r
+**/\r
 BOOLEAN\r
 ScsiDiskHaveSenseKey (\r
   IN  EFI_SCSI_SENSE_DATA   *SenseData,\r
   IN  UINTN                 SenseCounts\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Check sense key to find if it has sense key\r
-\r
-Arguments:\r
-\r
-  SenseData   - The pointer of EFI_SCSI_SENSE_DATA\r
-  SenseCounts - The number of sense key\r
-\r
-Returns:\r
-\r
-  BOOLEAN\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2341,32 +2478,23 @@ Returns:
   return HaveSenseKey;\r
 }\r
 \r
+/**\r
+  Release resource about disk device.\r
+\r
+  @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV\r
+\r
+**/\r
 VOID\r
 ReleaseScsiDiskDeviceResources (\r
   IN  SCSI_DISK_DEV   *ScsiDiskDevice\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Release resource about disk device\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice  - The pointer of SCSI_DISK_DEV\r
-\r
-Returns:\r
-\r
-  NONE\r
-\r
---*/\r
 {\r
   if (ScsiDiskDevice == NULL) {\r
     return ;\r
   }\r
 \r
   if (ScsiDiskDevice->SenseData != NULL) {\r
-    gBS->FreePool (ScsiDiskDevice->SenseData);\r
+    FreePool (ScsiDiskDevice->SenseData);\r
     ScsiDiskDevice->SenseData = NULL;\r
   }\r
 \r
@@ -2375,7 +2503,382 @@ Returns:
     ScsiDiskDevice->ControllerNameTable = NULL;\r
   }\r
 \r
-  gBS->FreePool (ScsiDiskDevice);\r
+  FreePool (ScsiDiskDevice);\r
 \r
   ScsiDiskDevice = NULL;\r
 }\r
+\r
+/**\r
+  Determine if Block Io should be produced.\r
+  \r
+\r
+  @param  ChildHandle  Child Handle to retrieve Parent information.\r
+  \r
+  @retval  TRUE    Should produce Block Io.\r
+  @retval  FALSE   Should not produce Block Io.\r
+\r
+**/  \r
+BOOLEAN\r
+DetermineInstallBlockIo (\r
+  IN  EFI_HANDLE      ChildHandle\r
+  )  \r
+{\r
+  EFI_SCSI_PASS_THRU_PROTOCOL           *ScsiPassThru;\r
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL       *ExtScsiPassThru;\r
+\r
+  //\r
+  // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,\r
+  // check its attribute, logic or physical.\r
+  //\r
+  ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);\r
+  if (ExtScsiPassThru != NULL) {\r
+    if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,\r
+  // check its attribute, logic or physical.\r
+  //\r
+  ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);\r
+  if (ScsiPassThru != NULL) {\r
+    if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {\r
+      return TRUE;\r
+    }\r
+  }\r
+  \r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Search protocol database and check to see if the protocol\r
+  specified by ProtocolGuid is present on a ControllerHandle and opened by\r
+  ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+  If the ControllerHandle is found, then the protocol specified by ProtocolGuid\r
+  will be opened on it.  \r
+  \r
+\r
+  @param  ProtocolGuid   ProtocolGuid pointer.\r
+  @param  ChildHandle    Child Handle to retrieve Parent information.\r
+  \r
+**/ \r
+VOID *\r
+EFIAPI\r
+GetParentProtocol (\r
+  IN  EFI_GUID                          *ProtocolGuid,\r
+  IN  EFI_HANDLE                        ChildHandle\r
+  ) \r
+{\r
+  UINTN                                 Index;\r
+  UINTN                                 HandleCount;\r
+  VOID                                  *Interface;  \r
+  EFI_STATUS                            Status;\r
+  EFI_HANDLE                            *HandleBuffer;\r
+\r
+  //\r
+  // Retrieve the list of all handles from the handle database\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  ProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle \r
+  //\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);\r
+      if (!EFI_ERROR (Status)) {\r
+        gBS->FreePool (HandleBuffer);\r
+        return Interface;\r
+      }\r
+    }\r
+  }\r
+\r
+  gBS->FreePool (HandleBuffer);\r
+  return NULL;\r
+} \r
+\r
+/**\r
+  Provides inquiry information for the controller type.\r
+  \r
+  This function is used by the IDE bus driver to get inquiry data.  Data format\r
+  of Identify data is defined by the Interface GUID.\r
+\r
+  @param[in]      This              Pointer to the EFI_DISK_INFO_PROTOCOL instance.\r
+  @param[in, out] InquiryData       Pointer to a buffer for the inquiry data.\r
+  @param[in, out] InquiryDataSize   Pointer to the value for the inquiry data size.\r
+\r
+  @retval EFI_SUCCESS            The command was accepted without any errors.\r
+  @retval EFI_NOT_FOUND          Device does not support this data class \r
+  @retval EFI_DEVICE_ERROR       Error reading InquiryData from device \r
+  @retval EFI_BUFFER_TOO_SMALL   InquiryDataSize not big enough \r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiDiskInfoInquiry (\r
+  IN     EFI_DISK_INFO_PROTOCOL   *This,\r
+  IN OUT VOID                     *InquiryData,\r
+  IN OUT UINT32                   *InquiryDataSize\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  SCSI_DISK_DEV   *ScsiDiskDevice;\r
+\r
+  ScsiDiskDevice  = SCSI_DISK_DEV_FROM_DISKINFO (This);\r
+\r
+  Status = EFI_BUFFER_TOO_SMALL;\r
+  if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {\r
+    Status = EFI_SUCCESS;\r
+    CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));\r
+  }\r
+  *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Provides identify information for the controller type.\r
+\r
+  This function is used by the IDE bus driver to get identify data.  Data format\r
+  of Identify data is defined by the Interface GUID.\r
+\r
+  @param[in]      This              Pointer to the EFI_DISK_INFO_PROTOCOL \r
+                                    instance.\r
+  @param[in, out] IdentifyData      Pointer to a buffer for the identify data.\r
+  @param[in, out] IdentifyDataSize  Pointer to the value for the identify data\r
+                                    size.\r
+\r
+  @retval EFI_SUCCESS            The command was accepted without any errors.\r
+  @retval EFI_NOT_FOUND          Device does not support this data class \r
+  @retval EFI_DEVICE_ERROR       Error reading IdentifyData from device \r
+  @retval EFI_BUFFER_TOO_SMALL   IdentifyDataSize not big enough \r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiDiskInfoIdentify (\r
+  IN     EFI_DISK_INFO_PROTOCOL   *This,\r
+  IN OUT VOID                     *IdentifyData,\r
+  IN OUT UINT32                   *IdentifyDataSize\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  SCSI_DISK_DEV   *ScsiDiskDevice;\r
+\r
+  if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {\r
+    //\r
+    // Physical SCSI bus does not support this data class. \r
+    //\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  ScsiDiskDevice  = SCSI_DISK_DEV_FROM_DISKINFO (This);\r
+\r
+  Status = EFI_BUFFER_TOO_SMALL;\r
+  if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {\r
+    Status = EFI_SUCCESS;\r
+    CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));\r
+  }\r
+  *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Provides sense data information for the controller type.\r
+  \r
+  This function is used by the IDE bus driver to get sense data. \r
+  Data format of Sense data is defined by the Interface GUID.\r
+\r
+  @param[in]      This              Pointer to the EFI_DISK_INFO_PROTOCOL instance.\r
+  @param[in, out] SenseData         Pointer to the SenseData.\r
+  @param[in, out] SenseDataSize     Size of SenseData in bytes.\r
+  @param[out]     SenseDataNumber   Pointer to the value for the sense data size.\r
+\r
+  @retval EFI_SUCCESS            The command was accepted without any errors.\r
+  @retval EFI_NOT_FOUND          Device does not support this data class.\r
+  @retval EFI_DEVICE_ERROR       Error reading SenseData from device.\r
+  @retval EFI_BUFFER_TOO_SMALL   SenseDataSize not big enough.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiDiskInfoSenseData (\r
+  IN     EFI_DISK_INFO_PROTOCOL   *This,\r
+  IN OUT VOID                     *SenseData,\r
+  IN OUT UINT32                   *SenseDataSize,\r
+  OUT    UINT8                    *SenseDataNumber\r
+  )\r
+{\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  This function is used by the IDE bus driver to get controller information.\r
+\r
+  @param[in]  This         Pointer to the EFI_DISK_INFO_PROTOCOL instance. \r
+  @param[out] IdeChannel   Pointer to the Ide Channel number.  Primary or secondary.\r
+  @param[out] IdeDevice    Pointer to the Ide Device number.  Master or slave.\r
+\r
+  @retval EFI_SUCCESS       IdeChannel and IdeDevice are valid.\r
+  @retval EFI_UNSUPPORTED   This is not an IDE device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiDiskInfoWhichIde (\r
+  IN  EFI_DISK_INFO_PROTOCOL   *This,\r
+  OUT UINT32                   *IdeChannel,\r
+  OUT UINT32                   *IdeDevice\r
+  )\r
+{\r
+  SCSI_DISK_DEV   *ScsiDiskDevice;\r
+\r
+  if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {\r
+    //\r
+    // This is not an IDE physical device.\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  ScsiDiskDevice  = SCSI_DISK_DEV_FROM_DISKINFO (This);\r
+  *IdeChannel     = ScsiDiskDevice->Channel;\r
+  *IdeDevice      = ScsiDiskDevice->Device;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Issues ATA IDENTIFY DEVICE command to identify ATAPI device.\r
+\r
+  This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to\r
+  implement Identify() interface for DiskInfo protocol. The ATA command is sent\r
+  via SCSI Request Packet.\r
+\r
+  @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV\r
+  \r
+  @retval EFI_SUCCESS     The ATAPI device identify data were retrieved successfully.\r
+  @retval others          Some error occurred during the identification that ATAPI device.\r
+\r
+**/  \r
+EFI_STATUS\r
+AtapiIdentifyDevice (\r
+  IN OUT SCSI_DISK_DEV   *ScsiDiskDevice\r
+  )\r
+{\r
+  EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;\r
+  UINT8                           Cdb[6];\r
+\r
+  //\r
+  // Initialize SCSI REQUEST_PACKET and 6-byte Cdb\r
+  //\r
+  ZeroMem (&CommandPacket, sizeof (CommandPacket));\r
+  ZeroMem (Cdb, sizeof (Cdb));\r
+\r
+  Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;\r
+  CommandPacket.Timeout = EFI_TIMER_PERIOD_SECONDS (1);\r
+  CommandPacket.Cdb = Cdb;\r
+  CommandPacket.CdbLength = (UINT8) sizeof (Cdb);\r
+  CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;\r
+  CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);\r
+\r
+  return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);\r
+}\r
+\r
+\r
+/**\r
+  Initialize the installation of DiskInfo protocol.\r
+\r
+  This function prepares for the installation of DiskInfo protocol on the child handle.\r
+  By default, it installs DiskInfo protocol with SCSI interface GUID. If it further\r
+  detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID\r
+  to be IDE/AHCI interface GUID.\r
+\r
+  @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV.\r
+  @param  ChildHandle     Child handle to install DiskInfo protocol.\r
+  \r
+**/  \r
+VOID\r
+InitializeInstallDiskInfo (\r
+  IN  SCSI_DISK_DEV   *ScsiDiskDevice,\r
+  IN  EFI_HANDLE      ChildHandle\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode;\r
+  EFI_DEVICE_PATH_PROTOCOL  *ChildDevicePathNode;\r
+  ATAPI_DEVICE_PATH         *AtapiDevicePath;\r
+  SATA_DEVICE_PATH          *SataDevicePath;\r
+  UINTN                     IdentifyRetry;\r
+\r
+  Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePathNode);\r
+  //\r
+  // Device Path protocol must be installed on the device handle. \r
+  //\r
+  ASSERT_EFI_ERROR (Status);\r
+  //\r
+  // Copy the DiskInfo protocol template.\r
+  //\r
+  CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));\r
+\r
+  while (!IsDevicePathEnd (DevicePathNode)) {\r
+    ChildDevicePathNode = NextDevicePathNode (DevicePathNode);\r
+    if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&\r
+        (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&\r
+        (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&\r
+       ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||\r
+        (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP))) {\r
+\r
+      IdentifyRetry = 3;\r
+      do {\r
+        //\r
+        // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol\r
+        // with IDE/AHCI interface GUID.\r
+        //\r
+        Status = AtapiIdentifyDevice (ScsiDiskDevice);\r
+        if (!EFI_ERROR (Status)) {\r
+          if (DevicePathSubType(ChildDevicePathNode) == MSG_ATAPI_DP) {\r
+            //\r
+            // We find the valid ATAPI device path\r
+            //\r
+            AtapiDevicePath = (ATAPI_DEVICE_PATH *) ChildDevicePathNode;\r
+            ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;\r
+            ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;\r
+            //\r
+            // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device. \r
+            //\r
+            CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);\r
+          } else {\r
+            //\r
+            // We find the valid SATA device path\r
+            //\r
+            SataDevicePath = (SATA_DEVICE_PATH *) ChildDevicePathNode;\r
+            ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;\r
+            ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;\r
+            //\r
+            // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device. \r
+            //\r
+            CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);\r
+          }\r
+          return;\r
+        }\r
+      } while (--IdentifyRetry > 0);\r
+    }\r
+    DevicePathNode = ChildDevicePathNode;\r
+  }\r
+\r
+  return;\r
+}\r