]> 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 3c81e994bf63bebce9527c18ccdd34a3b014760b..0e8aa34ad63c61e6dc26d370db253d7b29c0cc9c 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
   SCSI disk driver that layers on every SCSI IO protocol in the system.\r
 \r
-Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
-All rights reserved. This program and the accompanying materials\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
 http://opensource.org/licenses/bsd-license.php\r
@@ -15,7 +15,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include "ScsiDisk.h"\r
 \r
-\r
 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {\r
   ScsiDiskDriverBindingSupported,\r
   ScsiDiskDriverBindingStart,\r
@@ -25,6 +24,13 @@ 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.\r
@@ -160,6 +166,9 @@ ScsiDiskDriverBindingStart (
   UINT8                 Index;\r
   UINT8                 MaxRetry;\r
   BOOLEAN               NeedRetry;\r
+  BOOLEAN               MustReadCapacity;\r
+\r
+  MustReadCapacity = TRUE;\r
 \r
   ScsiDiskDevice = (SCSI_DISK_DEV *) AllocateZeroPool (sizeof (SCSI_DISK_DEV));\r
   if (ScsiDiskDevice == NULL) {\r
@@ -181,6 +190,7 @@ ScsiDiskDriverBindingStart (
 \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
@@ -192,10 +202,12 @@ 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
@@ -242,47 +254,52 @@ 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
-    FreePool (ScsiDiskDevice->SenseData);\r
-    gBS->CloseProtocol (\r
-           Controller,\r
-           &gEfiScsiIoProtocolGuid,\r
-           This->DriverBindingHandle,\r
-           Controller\r
-           );\r
-    FreePool (ScsiDiskDevice);\r
-    return Status;\r
+    //\r
+    // Determine if Block IO should be produced on this controller handle\r
+    //\r
+    if (DetermineInstallBlockIo(Controller)) {\r
+      InitializeInstallDiskInfo(ScsiDiskDevice, Controller);\r
+      Status = gBS->InstallMultipleProtocolInterfaces (\r
+                      &Controller,\r
+                      &gEfiBlockIoProtocolGuid,\r
+                      &ScsiDiskDevice->BlkIo,\r
+                      &gEfiDiskInfoProtocolGuid,\r
+                      &ScsiDiskDevice->DiskInfo,\r
+                      NULL\r
+                      );\r
+      if (!EFI_ERROR(Status)) {\r
+        ScsiDiskDevice->ControllerNameTable = NULL;\r
+        AddUnicodeString2 (\r
+          "eng",\r
+          gScsiDiskComponentName.SupportedLanguages,\r
+          &ScsiDiskDevice->ControllerNameTable,\r
+          L"SCSI Disk Device",\r
+          TRUE\r
+          );\r
+        AddUnicodeString2 (\r
+          "en",\r
+          gScsiDiskComponentName2.SupportedLanguages,\r
+          &ScsiDiskDevice->ControllerNameTable,\r
+          L"SCSI Disk Device",\r
+          FALSE\r
+          );\r
+        return EFI_SUCCESS;\r
+      }\r
+    } \r
   }\r
 \r
-  ScsiDiskDevice->ControllerNameTable = NULL;\r
-  AddUnicodeString2 (\r
-    "eng",\r
-    gScsiDiskComponentName.SupportedLanguages,\r
-    &ScsiDiskDevice->ControllerNameTable,\r
-    L"SCSI Disk Device",\r
-    TRUE\r
-    );\r
-  AddUnicodeString2 (\r
-    "en",\r
-    gScsiDiskComponentName2.SupportedLanguages,\r
-    &ScsiDiskDevice->ControllerNameTable,\r
-    L"SCSI Disk Device",\r
-    FALSE\r
-    );\r
-\r
-\r
-  return EFI_SUCCESS;\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
 \r
@@ -331,10 +348,13 @@ 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
@@ -364,7 +384,7 @@ ScsiDiskDriverBindingStop (
   @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 retured from EFI_SCSI_IO_PROTOCOL.ResetDevice().\r
+  @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().\r
 \r
 **/\r
 EFI_STATUS\r
@@ -384,12 +404,22 @@ ScsiDiskReset (
 \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
@@ -430,17 +460,8 @@ ScsiDiskReadBlocks (
   BOOLEAN             MediaChange;\r
   EFI_TPL             OldTpl;\r
 \r
-  MediaChange = FALSE;\r
-  if (Buffer == NULL) {\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 (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
@@ -478,6 +499,16 @@ ScsiDiskReadBlocks (
     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
@@ -545,17 +576,8 @@ ScsiDiskWriteBlocks (
   BOOLEAN             MediaChange;\r
   EFI_TPL             OldTpl;\r
 \r
-  MediaChange = FALSE;\r
-  if (Buffer == NULL) {\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 (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
@@ -593,6 +615,16 @@ ScsiDiskWriteBlocks (
     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
@@ -647,7 +679,7 @@ ScsiDiskFlushBlocks (
 \r
 \r
 /**\r
-  Dectect Device and read out capacity ,if error occurs, parse the sense key.\r
+  Detect Device and read out capacity ,if error occurs, parse the sense key.\r
 \r
   @param  ScsiDiskDevice    The pointer of SCSI_DISK_DEV\r
   @param  MustReadCapacity  The flag about reading device capacity\r
@@ -665,26 +697,50 @@ ScsiDiskDetectMedia (
   )\r
 {\r
   EFI_STATUS          Status;\r
-  EFI_STATUS          ReadCapacityStatus;\r
   EFI_SCSI_SENSE_DATA *SenseData;\r
   UINTN               NumberOfSenseKeys;\r
   BOOLEAN             NeedRetry;\r
   BOOLEAN             NeedReadCapacity;\r
-  UINT8               Index;\r
+  UINT8               Retry;\r
   UINT8               MaxRetry;\r
   EFI_BLOCK_IO_MEDIA  OldMedia;\r
   UINTN               Action;\r
+  EFI_EVENT           TimeoutEvt;\r
 \r
   Status              = EFI_SUCCESS;\r
-  ReadCapacityStatus  = EFI_SUCCESS;\r
   SenseData           = NULL;\r
   NumberOfSenseKeys   = 0;\r
+  Retry               = 0;\r
+  MaxRetry            = 3;\r
+  Action              = ACTION_NO_ACTION;\r
   NeedReadCapacity    = FALSE;\r
-  CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));\r
   *MediaChange        = FALSE;\r
-  MaxRetry            = 3;\r
+  TimeoutEvt          = NULL;\r
 \r
-  for (Index = 0; Index < MaxRetry; Index++) {\r
+  CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER,\r
+                  TPL_CALLBACK,\r
+                  NULL,\r
+                  NULL,\r
+                  &TimeoutEvt\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(120));\r
+  if (EFI_ERROR (Status)) {\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Sending Test_Unit cmd to poll device status.\r
+  // If the sense data shows the drive is not ready or reset before, we need poll the device status again.\r
+  // We limit the upper boundary to 120 seconds.\r
+  //\r
+  while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {\r
     Status = ScsiDiskTestUnitReady (\r
               ScsiDiskDevice,\r
               &NeedRetry,\r
@@ -692,34 +748,36 @@ ScsiDiskDetectMedia (
               &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
@@ -731,63 +789,45 @@ ScsiDiskDetectMedia (
     //\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
@@ -829,7 +869,11 @@ ScsiDiskDetectMedia (
     *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
 \r
@@ -849,15 +893,18 @@ ScsiDiskInquiryDevice (
      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
@@ -877,27 +924,86 @@ ScsiDiskInquiryDevice (
     // no need to check HostAdapterStatus and TargetStatus\r
     //\r
   if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
-     ParseInquiryData (ScsiDiskDevice);\r
-     return EFI_SUCCESS;\r
\r
-   } else if (Status == EFI_NOT_READY) {\r
-     *NeedRetry = TRUE;\r
-     return EFI_DEVICE_ERROR;\r
\r
-   } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
-     *NeedRetry = FALSE;\r
-     return EFI_DEVICE_ERROR;\r
-   }\r
-   //\r
-   // go ahead to check HostAdapterStatus and TargetStatus\r
-   // (EFI_TIMEOUT, EFI_DEVICE_ERROR)\r
-   //\r
+    ParseInquiryData (ScsiDiskDevice);\r
+\r
+    if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {\r
+      //\r
+      // Check whether the device supports Block Limits VPD page (0xB0)\r
+      //\r
+      ZeroMem (&SupportedVpdPages, sizeof (SupportedVpdPages));\r
+      InquiryDataLength = sizeof (SupportedVpdPages);\r
+      SenseDataLength   = 0;\r
+      Status = ScsiInquiryCommandEx (\r
+                 ScsiDiskDevice->ScsiIo,\r
+                 EFI_TIMER_PERIOD_SECONDS (1),\r
+                 NULL,\r
+                 &SenseDataLength,\r
+                 &HostAdapterStatus,\r
+                 &TargetStatus,\r
+                 (VOID *) &SupportedVpdPages,\r
+                 &InquiryDataLength,\r
+                 TRUE,\r
+                 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD\r
+                 );\r
+      if (!EFI_ERROR (Status)) {\r
+        PageLength = (SupportedVpdPages.PageLength2 << 8)\r
+                   |  SupportedVpdPages.PageLength1;\r
+        for (Index = 0; Index < PageLength; Index++) {\r
+          if (SupportedVpdPages.SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {\r
+            break;\r
+          }\r
+        }\r
+\r
+        //\r
+        // Query the Block Limits VPD page\r
+        //\r
+        if (Index < PageLength) {\r
+          ZeroMem (&BlockLimits, sizeof (BlockLimits));\r
+          InquiryDataLength = sizeof (BlockLimits);\r
+          SenseDataLength   = 0;\r
+          Status = ScsiInquiryCommandEx (\r
+                     ScsiDiskDevice->ScsiIo,\r
+                     EFI_TIMER_PERIOD_SECONDS (1),\r
+                     NULL,\r
+                     &SenseDataLength,\r
+                     &HostAdapterStatus,\r
+                     &TargetStatus,\r
+                     (VOID *) &BlockLimits,\r
+                     &InquiryDataLength,\r
+                     TRUE,\r
+                     EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD\r
+                     );\r
+          if (!EFI_ERROR (Status)) {\r
+            ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity = \r
+              (BlockLimits.OptimalTransferLengthGranularity2 << 8) |\r
+               BlockLimits.OptimalTransferLengthGranularity1;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    return EFI_SUCCESS;\r
+\r
+  } else if (Status == EFI_NOT_READY) {\r
+    *NeedRetry = TRUE;\r
+    return EFI_DEVICE_ERROR;\r
  \r
-   Status = CheckHostAdapterStatus (HostAdapterStatus);\r
-   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
-     *NeedRetry = TRUE;\r
-     return EFI_DEVICE_ERROR;\r
-   } else if (Status == EFI_DEVICE_ERROR) {\r
+  } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
+    *NeedRetry = FALSE;\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // go ahead to check HostAdapterStatus and TargetStatus\r
+  // (EFI_TIMEOUT, EFI_DEVICE_ERROR)\r
+  //\r
+\r
+  Status = CheckHostAdapterStatus (HostAdapterStatus);\r
+  if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
+    *NeedRetry = TRUE;\r
+    return EFI_DEVICE_ERROR;\r
+  } else if (Status == EFI_DEVICE_ERROR) {\r
       //\r
       // reset the scsi channel\r
       //\r
@@ -921,9 +1027,9 @@ ScsiDiskInquiryDevice (
   }\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
@@ -952,7 +1058,7 @@ ScsiDiskInquiryDevice (
 }\r
 \r
 /**\r
-  To test deivice.\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
@@ -1092,7 +1198,9 @@ DetectMediaParsingSenseKeys (
   *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
@@ -1100,7 +1208,9 @@ DetectMediaParsingSenseKeys (
     //\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
@@ -1116,13 +1226,20 @@ DetectMediaParsingSenseKeys (
     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
@@ -1131,7 +1248,7 @@ DetectMediaParsingSenseKeys (
       *Action = ACTION_RETRY_COMMAND_LATER;\r
       return EFI_SUCCESS;\r
     }\r
-\r
+    *Action = ACTION_NO_ACTION;\r
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
@@ -1148,7 +1265,7 @@ DetectMediaParsingSenseKeys (
   @param  NumberOfSenseKeys  The number of sense key\r
 \r
   @retval EFI_DEVICE_ERROR   Indicates that error occurs\r
-  @retval EFI_SUCCESS        Successfully to read capacity\r
+  @retval EFI_SUCCESS        Successfully to read capacity or sense data is received.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1159,41 +1276,73 @@ ScsiDiskReadCapacity (
       OUT  UINTN                   *NumberOfSenseKeys\r
   )\r
 {\r
-  EFI_SCSI_DISK_CAPACITY_DATA CapacityData;\r
-  UINT32                      DataLength;\r
-  UINT8                       HostAdapterStatus;\r
-  UINT8                       TargetStatus;\r
-  EFI_STATUS                  CommandStatus;\r
-  EFI_STATUS                  Status;\r
-  UINT8                       Index;\r
-  UINT8                       MaxRetry;\r
-  UINT8                       SenseDataLength;\r
-\r
-  SenseDataLength = 0;\r
-  ZeroMem (&CapacityData, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
-  DataLength          = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);\r
+  UINT8                         HostAdapterStatus;\r
+  UINT8                         TargetStatus;\r
+  EFI_STATUS                    CommandStatus;\r
+  EFI_STATUS                    Status;\r
+  UINT8                         Index;\r
+  UINT8                         MaxRetry;\r
+  UINT8                         SenseDataLength;\r
+  UINT32                        DataLength10;\r
+  UINT32                        DataLength16;\r
+  EFI_SCSI_DISK_CAPACITY_DATA   CapacityData10;\r
+  EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16;\r
+\r
+\r
+  SenseDataLength       = 0;\r
+  DataLength10          = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);\r
+  DataLength16          = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);\r
+  ZeroMem (&CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
+  ZeroMem (&CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));\r
 \r
   *NumberOfSenseKeys  = 0;\r
   *NeedRetry          = FALSE;\r
+\r
   //\r
-  // submit Read Capacity Command. in this call,not request sense data\r
+  // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh, \r
+  // 16 byte command should be used to access large hard disk >2TB\r
   //\r
   CommandStatus = ScsiReadCapacityCommand (\r
                     ScsiDiskDevice->ScsiIo,\r
-                    EFI_TIMER_PERIOD_SECONDS (1),\r
+                    EFI_TIMER_PERIOD_SECONDS(1),\r
                     NULL,\r
                     &SenseDataLength,\r
                     &HostAdapterStatus,\r
                     &TargetStatus,\r
-                    (VOID *) &CapacityData,\r
-                    &DataLength,\r
+                    (VOID *) &CapacityData10,\r
+                    &DataLength10,\r
                     FALSE\r
                     );\r
-  //\r
+\r
+  ScsiDiskDevice->Cdb16Byte = FALSE;\r
+  if ((!EFI_ERROR (CommandStatus)) && (CapacityData10.LastLba3 == 0xff) && (CapacityData10.LastLba2 == 0xff) &&\r
+      (CapacityData10.LastLba1 == 0xff) && (CapacityData10.LastLba0 == 0xff)) {\r
+    //\r
+    // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB\r
+    //\r
+    ScsiDiskDevice->Cdb16Byte = TRUE;\r
+    //\r
+    // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock\r
+    // and LowestAlignedLba\r
+    //\r
+    CommandStatus = ScsiReadCapacity16Command (\r
+                      ScsiDiskDevice->ScsiIo,\r
+                      EFI_TIMER_PERIOD_SECONDS (1),\r
+                      NULL,\r
+                      &SenseDataLength,\r
+                      &HostAdapterStatus,\r
+                      &TargetStatus,\r
+                      (VOID *) &CapacityData16,\r
+                      &DataLength16,\r
+                      FALSE\r
+                      );\r
+  }\r
+\r
+    //\r
     // no need to check HostAdapterStatus and TargetStatus\r
     //\r
    if (CommandStatus == EFI_SUCCESS) {\r
-     GetMediaInfo (ScsiDiskDevice, &CapacityData);\r
+     GetMediaInfo (ScsiDiskDevice, &CapacityData10,&CapacityData16);\r
      return EFI_SUCCESS;\r
  \r
    } else if (CommandStatus == EFI_NOT_READY) {\r
@@ -1238,9 +1387,9 @@ ScsiDiskReadCapacity (
   }\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
@@ -1253,8 +1402,7 @@ ScsiDiskReadCapacity (
               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
@@ -1352,7 +1500,7 @@ CheckTargetStatus (
   Retrieve all sense keys from the device.\r
 \r
   When encountering error during the process, if retrieve sense keys before\r
-  error encounterred, it returns the sense keys with return status set to EFI_SUCCESS,\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
@@ -1383,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
@@ -1451,25 +1599,54 @@ ScsiDiskRequestSenseKeys (
   Get information from media read capacity command.\r
 \r
   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV\r
-  @param  Capacity        The pointer of EFI_SCSI_DISK_CAPACITY_DATA\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
 VOID\r
 GetMediaInfo (\r
-  IN  OUT  SCSI_DISK_DEV                 *ScsiDiskDevice,\r
-  IN       EFI_SCSI_DISK_CAPACITY_DATA   *Capacity\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
@@ -1490,14 +1667,14 @@ ParseInquiryData (
   IN OUT SCSI_DISK_DEV   *ScsiDiskDevice\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
 /**\r
   Read sector from SCSI Disk.\r
 \r
-  @param  ScsiDiskDevice  The poiniter of SCSI_DISK_DEV\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
@@ -1515,7 +1692,6 @@ ScsiDiskReadSectors (
   )\r
 {\r
   UINTN               BlocksRemaining;\r
-  UINT32              Lba32;\r
   UINT8               *PtrBuffer;\r
   UINT32              BlockSize;\r
   UINT32              ByteCount;\r
@@ -1536,21 +1712,27 @@ ScsiDiskReadSectors (
 \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
@@ -1559,18 +1741,31 @@ ScsiDiskReadSectors (
 \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
@@ -1590,7 +1785,7 @@ ScsiDiskReadSectors (
     //\r
     SectorCount = ByteCount / BlockSize;\r
 \r
-    Lba32 += SectorCount;\r
+    Lba += SectorCount;\r
     PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
     BlocksRemaining -= SectorCount;\r
   }\r
@@ -1601,7 +1796,7 @@ ScsiDiskReadSectors (
 /**\r
   Write sector to SCSI Disk.\r
 \r
-  @param  ScsiDiskDevice  The poiniter of SCSI_DISK_DEV\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
@@ -1619,7 +1814,6 @@ ScsiDiskWriteSectors (
   )\r
 {\r
   UINTN               BlocksRemaining;\r
-  UINT32              Lba32;\r
   UINT8               *PtrBuffer;\r
   UINT32              BlockSize;\r
   UINT32              ByteCount;\r
@@ -1640,21 +1834,27 @@ ScsiDiskWriteSectors (
 \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
@@ -1662,17 +1862,31 @@ ScsiDiskWriteSectors (
     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
@@ -1690,7 +1904,7 @@ ScsiDiskWriteSectors (
     //\r
     SectorCount = ByteCount / BlockSize;\r
 \r
-    Lba32 += SectorCount;\r
+    Lba += SectorCount;\r
     PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
     BlocksRemaining -= SectorCount;\r
   }\r
@@ -1700,7 +1914,7 @@ ScsiDiskWriteSectors (
 \r
 \r
 /**\r
-  Sumbmit Read command.\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
@@ -1752,7 +1966,7 @@ ScsiDiskRead10 (
 \r
 \r
 /**\r
-  Submit Write Command.\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
@@ -1804,6 +2018,111 @@ ScsiDiskWrite10 (
 }\r
 \r
 \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
+  *NeedRetry          = FALSE;\r
+  *NumberOfSenseKeys  = 0;\r
+  SenseDataLength     = 0;\r
+  Status = ScsiRead16Command (\r
+            ScsiDiskDevice->ScsiIo,\r
+            Timeout,\r
+            NULL,\r
+            &SenseDataLength,\r
+            &HostAdapterStatus,\r
+            &TargetStatus,\r
+            DataBuffer,\r
+            DataLength,\r
+            StartLba,\r
+            SectorSize\r
+            );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Submit Write(16) Command.\r
+\r
+  @param  ScsiDiskDevice     The pointer of ScsiDiskDevice\r
+  @param  NeedRetry          The pointer of flag indicates if needs retry if error happens\r
+  @param  SenseDataArray     NOT used yet in this function\r
+  @param  NumberOfSenseKeys  The number of sense key\r
+  @param  Timeout            The time to complete the command\r
+  @param  DataBuffer         The buffer to fill with the read out data\r
+  @param  DataLength         The length of buffer\r
+  @param  StartLba           The start logic block address\r
+  @param  SectorSize         The size of sector\r
+\r
+  @return  EFI_STATUS is returned by calling ScsiWrite10Command().\r
+\r
+**/\r
+EFI_STATUS\r
+ScsiDiskWrite16 (\r
+  IN     SCSI_DISK_DEV         *ScsiDiskDevice,\r
+     OUT BOOLEAN               *NeedRetry,\r
+     OUT EFI_SCSI_SENSE_DATA   **SenseDataArray,   OPTIONAL\r
+     OUT UINTN                 *NumberOfSenseKeys,\r
+  IN     UINT64                Timeout,\r
+  IN     UINT8                 *DataBuffer,\r
+  IN OUT UINT32                *DataLength,\r
+  IN     UINT64                StartLba,\r
+  IN     UINT32                SectorSize\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       SenseDataLength;\r
+  UINT8       HostAdapterStatus;\r
+  UINT8       TargetStatus;\r
+\r
+  *NeedRetry          = FALSE;\r
+  *NumberOfSenseKeys  = 0;\r
+  SenseDataLength     = 0;\r
+  Status = ScsiWrite16Command (\r
+            ScsiDiskDevice->ScsiIo,\r
+            Timeout,\r
+            NULL,\r
+            &SenseDataLength,\r
+            &HostAdapterStatus,\r
+            &TargetStatus,\r
+            DataBuffer,\r
+            DataLength,\r
+            StartLba,\r
+            SectorSize\r
+            );\r
+  return Status;\r
+}\r
+\r
+\r
 /**\r
   Check sense key to find if media presents.\r
 \r
@@ -1973,7 +2292,7 @@ ScsiDiskIsHardwareError (
   @param  SenseCounts  The number of sense key\r
 \r
   @retval TRUE   Media is changed.\r
-  @retval FALSE  Medit is NOT changed.\r
+  @retval FALSE  Media is NOT changed.\r
 **/\r
 BOOLEAN\r
 ScsiDiskIsMediaChange (\r
@@ -2188,3 +2507,378 @@ ReleaseScsiDiskDeviceResources (
 \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