]> 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 e85f99ba94f7ccd92b5494198cdc1794b96f44bd..0e8aa34ad63c61e6dc26d370db253d7b29c0cc9c 100644 (file)
@@ -1,42 +1,17 @@
-/*++\r
-\r
-Copyright (c) 2006 - 2007, Intel Corporation                                                         \r
-All rights reserved. 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
-                                                                                          \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
-\r
-Module Name:\r
-\r
-  ScsiDisk.c\r
-\r
-Abstract:\r
-\r
---*/\r
-//\r
-// The package level header files this module uses\r
-//\r
-#include <PiDxe.h>\r
-\r
-//\r
-// The protocols, PPI and GUID defintions for this module\r
-//\r
-#include <Protocol/ScsiIo.h>\r
-#include <Protocol/ComponentName.h>\r
-#include <Protocol/BlockIo.h>\r
-#include <Protocol/DriverBinding.h>\r
-//\r
-// The Library classes this module consumes\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
+/** @file\r
+  SCSI disk driver that layers on every SCSI IO protocol in the system.\r
+\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
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
 \r
 #include "ScsiDisk.h"\r
 \r
@@ -49,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
@@ -71,14 +56,13 @@ InitializeScsiDisk(
   //\r
   // Install driver model protocol(s).\r
   //\r
-  Status = EfiLibInstallAllDriverProtocols (\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
              ImageHandle,\r
              SystemTable,\r
              &gScsiDiskDriverBinding,\r
              ImageHandle,\r
              &gScsiDiskComponentName,\r
-             NULL,\r
-             NULL\r
+             &gScsiDiskComponentName2\r
              );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
@@ -86,25 +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
-  Arguments:\r
-  \r
-  Returns:\r
-  \r
---*/\r
-// TODO:    This - add argument and description to function comment\r
-// TODO:    Controller - add argument and description to function comment\r
-// TODO:    RemainingDevicePath - add argument and description to function comment\r
 {\r
   EFI_STATUS            Status;\r
   EFI_SCSI_IO_PROTOCOL  *ScsiIo;\r
@@ -132,35 +123,41 @@ ScsiDiskDriverBindingSupported (
   }\r
 \r
   gBS->CloseProtocol (\r
-        Controller,\r
-        &gEfiScsiIoProtocolGuid,\r
-        This->DriverBindingHandle,\r
-        Controller\r
-        );\r
+         Controller,\r
+         &gEfiScsiIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
   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
-  Arguments:\r
-  \r
-  Returns:\r
-  \r
---*/\r
-// TODO:    This - add argument and description to function comment\r
-// TODO:    Controller - add argument and description to function comment\r
-// TODO:    RemainingDevicePath - add argument and description to function comment\r
-// TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-// TODO:    EFI_SUCCESS - add return value to function comment\r
 {\r
   EFI_STATUS            Status;\r
   EFI_SCSI_IO_PROTOCOL  *ScsiIo;\r
@@ -169,17 +166,14 @@ ScsiDiskDriverBindingStart (
   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
@@ -190,12 +184,13 @@ ScsiDiskDriverBindingStart (
                   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
@@ -207,39 +202,34 @@ ScsiDiskDriverBindingStart (
   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
@@ -249,14 +239,14 @@ ScsiDiskDriverBindingStart (
     }\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
+             Controller,\r
+             &gEfiScsiIoProtocolGuid,\r
+             This->DriverBindingHandle,\r
+             Controller\r
+             );\r
+      FreePool (ScsiDiskDevice);\r
       return EFI_DEVICE_ERROR;\r
     }\r
   }\r
@@ -264,62 +254,82 @@ ScsiDiskDriverBindingStart (
   // 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
-\r
-  if (EFI_ERROR (Status)) {\r
-    gBS->FreePool (ScsiDiskDevice->SenseData);\r
-    gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiScsiIoProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\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
-    gBS->FreePool (ScsiDiskDevice);\r
-    return Status;\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
-  ScsiDiskDevice->ControllerNameTable = NULL;\r
-  AddUnicodeString (\r
-    "eng",\r
-    gScsiDiskComponentName.SupportedLanguages,\r
-    &ScsiDiskDevice->ControllerNameTable,\r
-    (CHAR16 *) L"SCSI Disk Device"\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
-  return EFI_SUCCESS;\r
 \r
-}\r
+/**\r
+  Stop this driver on ControllerHandle.\r
 \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
+  @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
-  Arguments:\r
-  \r
-  Returns:\r
-  \r
---*/\r
-// TODO:    This - add argument and description to function comment\r
-// TODO:    Controller - add argument and description to function comment\r
-// TODO:    NumberOfChildren - add argument and description to function comment\r
-// TODO:    ChildHandleBuffer - add argument and description to function comment\r
-// TODO:    EFI_SUCCESS - add return value to function comment\r
 {\r
   EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
   SCSI_DISK_DEV         *ScsiDiskDevice;\r
@@ -338,18 +348,21 @@ ScsiDiskDriverBindingStop (
   }\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
-          Controller,\r
-          &gEfiScsiIoProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
+           Controller,\r
+           &gEfiScsiIoProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
 \r
     ReleaseScsiDiskDeviceResources (ScsiDiskDevice);\r
 \r
@@ -361,36 +374,29 @@ ScsiDiskDriverBindingStop (
   return Status;\r
 }\r
 \r
-//\r
-// Block I/O Protocol Interface\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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  This                  - TODO: add argument description\r
-  ExtendedVerification  - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
 {\r
+  EFI_TPL       OldTpl;\r
   SCSI_DISK_DEV *ScsiDiskDevice;\r
   EFI_STATUS    Status;\r
-  EFI_TPL       OldTpl;\r
 \r
   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
 \r
@@ -398,53 +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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  This        - TODO: add argument description\r
-  MediaId     - TODO: add argument description\r
-  LBA         - TODO: add argument description\r
-  BufferSize  - TODO: add argument description\r
-  Buffer      - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  EFI_INVALID_PARAMETER - TODO: Add description for return value\r
-  EFI_SUCCESS - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_NO_MEDIA - TODO: Add description for return value\r
-  EFI_MEDIA_CHANGED - TODO: Add description for return value\r
-  EFI_BAD_BUFFER_SIZE - TODO: Add description for return value\r
-  EFI_INVALID_PARAMETER - TODO: Add description for return value\r
-  EFI_INVALID_PARAMETER - TODO: Add description for return value\r
-  EFI_INVALID_PARAMETER - TODO: Add description for return value\r
-\r
---*/\r
 {\r
   SCSI_DISK_DEV       *ScsiDiskDevice;\r
   EFI_BLOCK_IO_MEDIA  *Media;\r
@@ -454,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
@@ -502,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
@@ -521,54 +528,45 @@ Returns:
     Status = EFI_INVALID_PARAMETER;\r
     goto Done;\r
   }\r
-  \r
+\r
   //\r
-  // if all the parameters are valid, then perform read sectors command\r
+  // 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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  This        - TODO: add argument description\r
-  MediaId     - TODO: add argument description\r
-  LBA         - TODO: add argument description\r
-  BufferSize  - TODO: add argument description\r
-  Buffer      - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  EFI_INVALID_PARAMETER - TODO: Add description for return value\r
-  EFI_SUCCESS - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_NO_MEDIA - TODO: Add description for return value\r
-  EFI_MEDIA_CHANGED - TODO: Add description for return value\r
-  EFI_BAD_BUFFER_SIZE - TODO: Add description for return value\r
-  EFI_INVALID_PARAMETER - TODO: Add description for return value\r
-  EFI_INVALID_PARAMETER - TODO: Add description for return value\r
-  EFI_INVALID_PARAMETER - TODO: Add description for return value\r
-\r
---*/\r
 {\r
   SCSI_DISK_DEV       *ScsiDiskDevice;\r
   EFI_BLOCK_IO_MEDIA  *Media;\r
@@ -578,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
@@ -626,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
@@ -649,34 +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
-  \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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  This  - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  EFI_SUCCESS - TODO: Add description for return value\r
-\r
---*/\r
 {\r
   //\r
   // return directly\r
@@ -684,56 +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
-  TODO: Add function description\r
-\r
-Arguments:\r
 \r
-  ScsiDiskDevice    - TODO: add argument description\r
-  MustReadCapacity  - TODO: add argument description\r
-  MediaChange       - TODO: add argument description\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 - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_SUCCESS - TODO: Add description for return value\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
+  *MediaChange        = FALSE;\r
+  TimeoutEvt          = NULL;\r
+\r
   CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));\r
-  // OldMedia            = *(ScsiDiskDevice->BlkIo.Media);\r
 \r
-  *MediaChange        = FALSE;\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
-  MaxRetry            = 3;\r
-  for (Index = 0; Index < MaxRetry; Index++) {\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
@@ -741,103 +748,86 @@ 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
+\r
   //\r
   // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,\r
   // retrieve capacity via Read Capacity command\r
   //\r
   if (NeedReadCapacity || MustReadCapacity) {\r
-    \r
     //\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
@@ -879,56 +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
-  TODO: Add function description\r
 \r
-Arguments:\r
-\r
-  ScsiDiskDevice  - TODO: add argument description\r
-  NeedRetry       - TODO: add argument description\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_SUCCESS - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\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 = SubmitInquiryCommand (\r
+  Status = ScsiInquiryCommand (\r
             ScsiDiskDevice->ScsiIo,\r
-            EfiScsiStallSeconds (1),\r
+            EFI_TIMER_PERIOD_SECONDS (1),\r
             NULL,\r
             &SenseDataLength,\r
             &HostAdapterStatus,\r
@@ -937,22 +920,77 @@ Returns:
             &InquiryDataLength,\r
             FALSE\r
             );\r
-  if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
     //\r
     // no need to check HostAdapterStatus and TargetStatus\r
     //\r
+  if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\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
-    //\r
-    // no need to check HostAdapterStatus and TargetStatus\r
-    //\r
     *NeedRetry = TRUE;\r
     return EFI_DEVICE_ERROR;\r
\r
   } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
-    //\r
-    // no need to check HostAdapterStatus and TargetStatus\r
-    //\r
     *NeedRetry = FALSE;\r
     return EFI_DEVICE_ERROR;\r
   }\r
@@ -960,14 +998,15 @@ Returns:
   // 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
+      //\r
+      // reset the scsi channel\r
+      //\r
     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
     *NeedRetry = FALSE;\r
     return EFI_DEVICE_ERROR;\r
@@ -981,19 +1020,19 @@ Returns:
     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
     *NeedRetry = TRUE;\r
     return EFI_DEVICE_ERROR;\r
+\r
   } else if (Status == EFI_DEVICE_ERROR) {\r
     *NeedRetry = FALSE;\r
     return EFI_DEVICE_ERROR;\r
   }\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
-\r
     Status = ScsiDiskRequestSenseKeys (\r
               ScsiDiskDevice,\r
               NeedRetry,\r
@@ -1018,37 +1057,29 @@ Returns:
   return EFI_DEVICE_ERROR;\r
 }\r
 \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
+  @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
+  @retval EFI_DEVICE_ERROR   Indicates that error occurs\r
+  @retval EFI_SUCCESS        Successfully to test unit\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
+  IN  SCSI_DISK_DEV         *ScsiDiskDevice,\r
+  OUT BOOLEAN               *NeedRetry,\r
+  OUT EFI_SCSI_SENSE_DATA   **SenseDataArray,\r
+  OUT UINTN                 *NumberOfSenseKeys\r
   )\r
-// TODO: function comment should start with '/*++'\r
-/*\r
-  When Test Unit Ready command succeeds,\r
-  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
-// TODO: function comment should end with '--*/'\r
-// TODO: function comment is missing 'Routine Description:'\r
-// TODO: function comment is missing 'Arguments:'\r
-// TODO: function comment is missing 'Returns:'\r
-// TODO:    ScsiDiskDevice - add argument and description to function comment\r
-// TODO:    NeedRetry - add argument and description to function comment\r
-// TODO:    SenseDataArray - add argument and description to function comment\r
-// TODO:    NumberOfSenseKeys - add argument and description to function comment\r
-// TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-// TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-// TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-// TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-// TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-// TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-// TODO:    EFI_SUCCESS - add return value to function comment\r
-// TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-// TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
 {\r
   EFI_STATUS  Status;\r
   UINT8       SenseDataLength;\r
@@ -1063,34 +1094,34 @@ ScsiDiskTestUnitReady (
   //\r
   // Parameter 3 and 4: do not require sense data, retrieve it when needed.\r
   //\r
-  Status = SubmitTestUnitReadyCommand (\r
+  Status = ScsiTestUnitReadyCommand (\r
             ScsiDiskDevice->ScsiIo,\r
-            EfiScsiStallSeconds (1),\r
+            EFI_TIMER_PERIOD_SECONDS (1),\r
             NULL,\r
             &SenseDataLength,\r
             &HostAdapterStatus,\r
             &TargetStatus\r
             );\r
+  //\r
+  // no need to check HostAdapterStatus and TargetStatus\r
+  //\r
   if (Status == EFI_NOT_READY) {\r
-    //\r
-    // no need to check HostAdapterStatus and TargetStatus\r
-    //\r
     *NeedRetry = TRUE;\r
     return EFI_DEVICE_ERROR;\r
+\r
   } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
-    //\r
-    // no need to check HostAdapterStatus and TargetStatus\r
-    //\r
     *NeedRetry = FALSE;\r
     return EFI_DEVICE_ERROR;\r
   }\r
   //\r
-  // go ahead to check HostAdapterStatus and TargetStatus\r
+  // go ahead to check HostAdapterStatus and TargetStatus(in case of 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
+\r
   } else if (Status == EFI_DEVICE_ERROR) {\r
     //\r
     // reset the scsi channel\r
@@ -1108,6 +1139,7 @@ ScsiDiskTestUnitReady (
     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
     *NeedRetry = TRUE;\r
     return EFI_DEVICE_ERROR;\r
+\r
   } else if (Status == EFI_DEVICE_ERROR) {\r
     *NeedRetry = FALSE;\r
     return EFI_DEVICE_ERROR;\r
@@ -1115,7 +1147,6 @@ ScsiDiskTestUnitReady (
 \r
   MaxRetry = 3;\r
   for (Index = 0; Index < MaxRetry; Index++) {\r
-\r
     Status = ScsiDiskRequestSenseKeys (\r
               ScsiDiskDevice,\r
               NeedRetry,\r
@@ -1139,39 +1170,25 @@ ScsiDiskTestUnitReady (
   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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice    - TODO: add argument description\r
-  SenseData         - TODO: add argument description\r
-  NumberOfSenseKeys - TODO: add argument description\r
-  Action            - TODO: add argument description\r
+/**\r
+  Parsing Sense Keys which got from request sense command.\r
 \r
-Returns:\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
-  EFI_SUCCESS - TODO: Add description for return value\r
-  EFI_SUCCESS - TODO: Add description for return value\r
-  EFI_SUCCESS - TODO: Add description for return value\r
-  EFI_SUCCESS - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_SUCCESS - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_SUCCESS - TODO: Add description for return value\r
+  @retval EFI_DEVICE_ERROR   Indicates that error occurs\r
+  @retval 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
@@ -1181,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
@@ -1189,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
@@ -1205,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
@@ -1220,107 +1248,122 @@ 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
-  TODO: Add function description\r
 \r
-Arguments:\r
-\r
-  ScsiDiskDevice    - TODO: add argument description\r
-  NeedRetry         - TODO: add argument description\r
-  SenseDataArray    - TODO: add argument description\r
-  NumberOfSenseKeys - TODO: add argument description\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_SUCCESS - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\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 = SubmitReadCapacityCommand (\r
+  CommandStatus = ScsiReadCapacityCommand (\r
                     ScsiDiskDevice->ScsiIo,\r
-                    EfiScsiStallSeconds (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
-  if (CommandStatus == EFI_SUCCESS) {\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
-    // no need to check HostAdapterStatus and TargetStatus\r
+    // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB\r
     //\r
-    GetMediaInfo (ScsiDiskDevice, &CapacityData);\r
-    return EFI_SUCCESS;\r
-  } else if (CommandStatus == EFI_NOT_READY) {\r
+    ScsiDiskDevice->Cdb16Byte = TRUE;\r
     //\r
-    // no need to check HostAdapterStatus and TargetStatus\r
+    // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock\r
+    // and LowestAlignedLba\r
     //\r
-    *NeedRetry = TRUE;\r
-    return EFI_DEVICE_ERROR;\r
-  } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {\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
-    *NeedRetry = FALSE;\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-  //\r
-  // go ahead to check HostAdapterStatus and TargetStatus\r
-  // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)\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
+   if (CommandStatus == EFI_SUCCESS) {\r
+     GetMediaInfo (ScsiDiskDevice, &CapacityData10,&CapacityData16);\r
+     return EFI_SUCCESS;\r
\r
+   } else if (CommandStatus == EFI_NOT_READY) {\r
+     *NeedRetry = TRUE;\r
+     return EFI_DEVICE_ERROR;\r
\r
+   } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == 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, EFI_WARN_BUFFER_TOO_SMALL)\r
+   //\r
\r
+   Status = CheckHostAdapterStatus (HostAdapterStatus);\r
+   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
+     *NeedRetry = TRUE;\r
+     return EFI_DEVICE_ERROR;\r
\r
+   } else if (Status == EFI_DEVICE_ERROR) {\r
     //\r
     // reset the scsi channel\r
     //\r
@@ -1337,15 +1380,16 @@ Returns:
     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
     *NeedRetry = TRUE;\r
     return EFI_DEVICE_ERROR;\r
+\r
   } else if (Status == EFI_DEVICE_ERROR) {\r
     *NeedRetry = FALSE;\r
     return EFI_DEVICE_ERROR;\r
   }\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
@@ -1358,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
@@ -1374,48 +1417,40 @@ Returns:
   return EFI_DEVICE_ERROR;\r
 }\r
 \r
-EFI_STATUS\r
-CheckHostAdapterStatus (\r
-  UINT8   HostAdapterStatus\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  HostAdapterStatus - TODO: add argument description\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 - TODO: Add description for return value\r
-  EFI_TIMEOUT - TODO: Add description for return value\r
-  EFI_NOT_READY - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_SUCCESS - TODO: Add description for return value\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_SCSI_IO_STATUS_HOST_ADAPTER_OK:\r
+  case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:\r
     return EFI_SUCCESS;\r
 \r
-  case EFI_SCSI_IO_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:\r
-  case EFI_SCSI_IO_STATUS_HOST_ADAPTER_TIMEOUT:\r
-  case EFI_SCSI_IO_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:\r
+  case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:\r
+  case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:\r
+  case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:\r
     return EFI_TIMEOUT;\r
 \r
-  case EFI_SCSI_IO_STATUS_HOST_ADAPTER_MESSAGE_REJECT:\r
-  case EFI_SCSI_IO_STATUS_HOST_ADAPTER_PARITY_ERROR:\r
-  case EFI_SCSI_IO_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:\r
-  case EFI_SCSI_IO_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:\r
-  case EFI_SCSI_IO_STATUS_HOST_ADAPTER_BUS_RESET:\r
+  case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:\r
+  case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:\r
+  case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:\r
+  case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:\r
+  case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:\r
     return EFI_NOT_READY;\r
 \r
-  case EFI_SCSI_IO_STATUS_HOST_ADAPTER_BUS_FREE:\r
-  case EFI_SCSI_IO_STATUS_HOST_ADAPTER_PHASE_ERROR:\r
+  case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:\r
+  case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:\r
     return EFI_DEVICE_ERROR;\r
 \r
   default:\r
@@ -1423,43 +1458,35 @@ Returns:
   }\r
 }\r
 \r
-EFI_STATUS\r
-CheckTargetStatus (\r
-  UINT8   TargetStatus\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  TODO: Add function description\r
 \r
-Arguments:\r
-\r
-  TargetStatus  - TODO: add argument description\r
+/**\r
+  Check the target status and re-interpret it in EFI_STATUS.\r
 \r
-Returns:\r
+  @param  TargetStatus  Target status\r
 \r
-  EFI_SUCCESS - TODO: Add description for return value\r
-  EFI_NOT_READY - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_SUCCESS - TODO: Add description for return value\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_SCSI_IO_STATUS_TARGET_GOOD:\r
-  case EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION:\r
-  case EFI_SCSI_IO_STATUS_TARGET_CONDITION_MET:\r
+  case EFI_EXT_SCSI_STATUS_TARGET_GOOD:\r
+  case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:\r
+  case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:\r
     return EFI_SUCCESS;\r
 \r
-  case EFI_SCSI_IO_STATUS_TARGET_INTERMEDIATE:\r
-  case EFI_SCSI_IO_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:\r
-  case EFI_SCSI_IO_STATUS_TARGET_BUSY:\r
-  case EFI_SCSI_IO_STATUS_TARGET_COMMOND_TERMINATED:\r
-  case EFI_SCSI_IO_STATUS_TARGET_QUEUE_FULL:\r
+  case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:\r
+  case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:\r
+  case EFI_EXT_SCSI_STATUS_TARGET_BUSY:\r
+  case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:\r
     return EFI_NOT_READY;\r
 \r
-  case EFI_SCSI_IO_STATUS_TARGET_RESERVATION_CONFLICT:\r
+  case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:\r
     return EFI_DEVICE_ERROR;\r
     break;\r
 \r
@@ -1468,35 +1495,32 @@ Returns:
   }\r
 }\r
 \r
+\r
+/**\r
+  Retrieve all sense keys from the device.\r
+\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
+  @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
-  SCSI_DISK_DEV           *ScsiDiskDevice,\r
-  BOOLEAN                 *NeedRetry,\r
-  EFI_SCSI_SENSE_DATA     **SenseDataArray,\r
-  UINTN                   *NumberOfSenseKeys,\r
-  BOOLEAN                 AskResetIfError\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
-// TODO: function comment should start with '/*++'\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
-// TODO: function comment should end with '--*/'\r
-// TODO: function comment is missing 'Routine Description:'\r
-// TODO: function comment is missing 'Arguments:'\r
-// TODO: function comment is missing 'Returns:'\r
-// TODO:    ScsiDiskDevice - add argument and description to function comment\r
-// TODO:    NeedRetry - add argument and description to function comment\r
-// TODO:    SenseDataArray - add argument and description to function comment\r
-// TODO:    NumberOfSenseKeys - add argument and description to function comment\r
-// TODO:    AskResetIfError - add argument and description to function comment\r
-// TODO:    EFI_SUCCESS - add return value to function comment\r
-// TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-// TODO:    EFI_SUCCESS - add return value to function comment\r
 {\r
   EFI_SCSI_SENSE_DATA *PtrSenseData;\r
   UINT8               SenseDataLength;\r
@@ -1507,7 +1531,7 @@ ScsiDiskRequestSenseKeys (
   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
@@ -1519,29 +1543,31 @@ ScsiDiskRequestSenseKeys (
   PtrSenseData        = ScsiDiskDevice->SenseData;\r
 \r
   for (SenseReq = TRUE; SenseReq;) {\r
-\r
-    Status = SubmitRequestSenseCommand (\r
+    Status = ScsiRequestSenseCommand (\r
               ScsiDiskDevice->ScsiIo,\r
-              EfiScsiStallSeconds (2),\r
+              EFI_TIMER_PERIOD_SECONDS (2),\r
               PtrSenseData,\r
               &SenseDataLength,\r
               &HostAdapterStatus,\r
               &TargetStatus\r
               );\r
-    if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
-      FallStatus = EFI_SUCCESS;\r
-    } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) { \r
-      *NeedRetry  = TRUE;\r
-      FallStatus  = EFI_DEVICE_ERROR;\r
-    } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
-      *NeedRetry  = FALSE;\r
-      FallStatus  = EFI_DEVICE_ERROR;\r
-    } else if (Status == EFI_DEVICE_ERROR) {\r
-      if (AskResetIfError) {\r
-        ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
-      }\r
-\r
-      FallStatus = EFI_DEVICE_ERROR;\r
+     if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
+        FallStatus = EFI_SUCCESS;\r
+  \r
+     } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
+       *NeedRetry  = TRUE;\r
+       FallStatus  = EFI_DEVICE_ERROR;\r
\r
+     } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
+       *NeedRetry  = FALSE;\r
+       FallStatus  = EFI_DEVICE_ERROR;\r
\r
+     } else if (Status == EFI_DEVICE_ERROR) {\r
+        if (AskResetIfError) {\r
+          ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
+        }\r
+  \r
+        FallStatus = EFI_DEVICE_ERROR;\r
     }\r
 \r
     if (EFI_ERROR (FallStatus)) {\r
@@ -1563,46 +1589,64 @@ ScsiDiskRequestSenseKeys (
         (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {\r
       SenseReq = FALSE;\r
     }\r
-\r
     PtrSenseData += 1;\r
-\r
   }\r
-\r
   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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice  - TODO: add argument description\r
-  Capacity        - TODO: add argument description\r
-\r
-Returns:\r
+/**\r
+  Get information from media read capacity command.\r
 \r
-  TODO: add return values\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
@@ -1612,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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice  - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\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
-ScsiDiskReadSectors (\r
-  SCSI_DISK_DEV     *ScsiDiskDevice,\r
-  VOID              *Buffer,\r
-  EFI_LBA           Lba,\r
-  UINTN             NumberOfBlocks\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice  - TODO: add argument description\r
-  Buffer          - TODO: add argument description\r
-  Lba             - TODO: add argument description\r
-  NumberOfBlocks  - TODO: add argument description\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 - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_SUCCESS - TODO: Add description for return value\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
@@ -1686,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   = EfiScsiStallSeconds (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
@@ -1740,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
@@ -1748,36 +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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice  - TODO: add argument description\r
-  Buffer          - TODO: add argument description\r
-  Lba             - TODO: add argument description\r
-  NumberOfBlocks  - TODO: add argument description\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 - TODO: Add description for return value\r
-  EFI_DEVICE_ERROR - TODO: Add description for return value\r
-  EFI_SUCCESS - TODO: Add description for return value\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
@@ -1798,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   = EfiScsiStallSeconds (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
@@ -1848,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
@@ -1856,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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice    - TODO: add argument description\r
-  NeedRetry         - TODO: add argument description\r
-  SenseDataArray    - TODO: add argument description\r
-  NumberOfSenseKeys - TODO: add argument description\r
-  Timeout           - TODO: add argument description\r
-  DataBuffer        - TODO: add argument description\r
-  DataLength        - TODO: add argument description\r
-  StartLba          - TODO: add argument description\r
-  SectorSize        - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
 {\r
   UINT8       SenseDataLength;\r
   EFI_STATUS  Status;\r
@@ -1900,7 +1949,7 @@ Returns:
   *NeedRetry          = FALSE;\r
   *NumberOfSenseKeys  = 0;\r
   SenseDataLength     = 0;\r
-  Status = SubmitRead10Command (\r
+  Status = ScsiRead10Command (\r
             ScsiDiskDevice->ScsiIo,\r
             Timeout,\r
             NULL,\r
@@ -1915,41 +1964,140 @@ Returns:
   return Status;\r
 }\r
 \r
+\r
+/**\r
+  Submit Write(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 ScsiWrite10Command().\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
+  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
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       SenseDataLength;\r
+  UINT8       HostAdapterStatus;\r
+  UINT8       TargetStatus;\r
 \r
-Routine Description:\r
+  *NeedRetry          = FALSE;\r
+  *NumberOfSenseKeys  = 0;\r
+  SenseDataLength     = 0;\r
+  Status = ScsiWrite10Command (\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
-  TODO: Add function description\r
 \r
-Arguments:\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
-  ScsiDiskDevice    - TODO: add argument description\r
-  NeedRetry         - TODO: add argument description\r
-  SenseDataArray    - TODO: add argument description\r
-  NumberOfSenseKeys - TODO: add argument description\r
-  Timeout           - TODO: add argument description\r
-  DataBuffer        - TODO: add argument description\r
-  DataLength        - TODO: add argument description\r
-  StartLba          - TODO: add argument description\r
-  SectorSize        - TODO: add argument description\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
-Returns:\r
 \r
-  TODO: add return values\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
---*/\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
@@ -1959,7 +2107,7 @@ Returns:
   *NeedRetry          = FALSE;\r
   *NumberOfSenseKeys  = 0;\r
   SenseDataLength     = 0;\r
-  Status = SubmitWrite10Command (\r
+  Status = ScsiWrite16Command (\r
             ScsiDiskDevice->ScsiIo,\r
             Timeout,\r
             NULL,\r
@@ -1974,27 +2122,21 @@ Returns:
   return Status;\r
 }\r
 \r
+\r
+/**\r
+  Check sense key to find if media presents.\r
+\r
+  @param  SenseData   The pointer of EFI_SCSI_SENSE_DATA\r
+  @param  SenseCounts The number of sense key\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
-\r
-Routine Description:\r
-\r
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  SenseData   - TODO: add argument description\r
-  SenseCounts - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2004,7 +2146,6 @@ Returns:
   SensePtr  = SenseData;\r
 \r
   for (Index = 0; Index < SenseCounts; Index++) {\r
-\r
     //\r
     // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),\r
     // Additional Sense Code is ASC_NO_MEDIA (0x3A)\r
@@ -2013,34 +2154,28 @@ Returns:
         (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {\r
       IsNoMedia = TRUE;\r
     }\r
-\r
     SensePtr++;\r
   }\r
 \r
   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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  SenseData   - TODO: add argument description\r
-  SenseCounts - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2110,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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  SenseData   - TODO: add argument description\r
-  SenseCounts - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2154,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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  SenseData   - TODO: add argument description\r
-  SenseCounts - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2199,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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  SenseData   - TODO: add argument description\r
-  SenseCounts - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2245,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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  SenseData   - TODO: add argument description\r
-  SenseCounts - TODO: add argument description\r
-  RetryLater  - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2322,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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  SenseData   - TODO: add argument description\r
-  SenseCounts - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
 {\r
   EFI_SCSI_SENSE_DATA *SensePtr;\r
   UINTN               Index;\r
@@ -2372,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
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  ScsiDiskDevice  - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\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
@@ -2406,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