]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/AtapiPassThruDxe/AtapiPassThru.c
Save original PCI attributes in start() function and restore it in Stop() for those...
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / AtapiPassThruDxe / AtapiPassThru.c
index f14d9e34820fe3a3eb3e04be88f25924b9ac6d3b..51aa51d3e937bc205186db0cf97ced01d2613f63 100644 (file)
@@ -1,24 +1,17 @@
 /** @file\r
-  Copyright (c) 2006, 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
+  Copyright (c) 2006, 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
+  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
 #include "AtapiPassThru.h"\r
 \r
-///\r
-/// IDE registers' fixed address\r
-///\r
-static IDE_BASE_REGISTERS   gAtapiIoPortRegisters[2] = {\r
-  { 0x1f0, { 0x1f1 }, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, { 0x1f7 }, { 0x3f6 }, 0x3f7, 0 },\r
-  { 0x170, { 0x171 }, 0x172, 0x173, 0x174, 0x175, 0x176, { 0x177 }, { 0x376 }, 0x377, 0 } \r
-};\r
 \r
 static SCSI_COMMAND_SET     gEndTable = { 0xff, (DATA_DIRECTION) 0xff };\r
 \r
@@ -58,7 +51,7 @@ static SCSI_COMMAND_SET     gSupportedATAPICommands[] = {
   { OP_WRITE_10,                    DataOut },\r
   { OP_WRITE_12,                    DataOut },\r
   { OP_WRITE_AND_VERIFY,            DataOut },\r
-  { 0xff,                           (DATA_DIRECTION) 0xff    } \r
+  { 0xff,                           (DATA_DIRECTION) 0xff    }\r
 };\r
 \r
 static CHAR16               *gControllerNameString  = (CHAR16 *) L"ATAPI Controller";\r
@@ -97,6 +90,7 @@ AtapiScsiPassThruDriverBindingSupported (
   EFI_PCI_IO_PROTOCOL *PciIo;\r
   PCI_TYPE00          Pci;\r
 \r
+\r
   //\r
   // Open the IO Abstraction(s) needed to perform the supported test\r
   //\r
@@ -125,11 +119,11 @@ AtapiScsiPassThruDriverBindingSupported (
                         );\r
   if (EFI_ERROR (Status)) {\r
     gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiPciIoProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
@@ -139,11 +133,11 @@ AtapiScsiPassThruDriverBindingSupported (
   }\r
 \r
   gBS->CloseProtocol (\r
-        Controller,\r
-        &gEfiPciIoProtocolGuid,\r
-        This->DriverBindingHandle,\r
-        Controller\r
-        );\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
 \r
   return Status;\r
 }\r
@@ -170,6 +164,8 @@ AtapiScsiPassThruDriverBindingStart (
 {\r
   EFI_STATUS          Status;\r
   EFI_PCI_IO_PROTOCOL *PciIo;\r
+  UINT64              Supports;\r
+  UINT64              OriginalPciAttributes;\r
 \r
   PciIo = NULL;\r
   Status = gBS->OpenProtocol (\r
@@ -184,12 +180,37 @@ AtapiScsiPassThruDriverBindingStart (
     return Status;\r
   }\r
 \r
+  //\r
+  // Save original PCI attributes\r
+  //\r
   Status = PciIo->Attributes (\r
                     PciIo,\r
-                    EfiPciIoAttributeOperationEnable,\r
-                    EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE,\r
-                    NULL\r
+                    EfiPciIoAttributeOperationGet,\r
+                    0,\r
+                    &OriginalPciAttributes\r
                     );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSupported,\r
+                    0,\r
+                    &Supports\r
+                    );\r
+  if (!EFI_ERROR (Status)) {\r
+    Supports &= (EFI_PCI_DEVICE_ENABLE               |\r
+                 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO |\r
+                 EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO);\r
+    Status = PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationEnable,\r
+                      Supports,\r
+                      NULL\r
+                      );\r
+  }\r
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
@@ -197,25 +218,26 @@ AtapiScsiPassThruDriverBindingStart (
   //\r
   // Create SCSI Pass Thru instance for the IDE channel.\r
   //\r
-  Status = RegisterAtapiScsiPassThru (This, Controller, PciIo);\r
+  Status = RegisterAtapiScsiPassThru (This, Controller, PciIo, OriginalPciAttributes);\r
 \r
 Done:\r
   if (EFI_ERROR (Status)) {\r
-    if (PciIo) {\r
-      PciIo->Attributes (\r
-              PciIo,\r
-              EfiPciIoAttributeOperationDisable,\r
-              EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE,\r
-              NULL\r
-              );\r
-    }\r
+    //\r
+    // Restore original PCI attributes\r
+    //\r
+    PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSet,\r
+                    OriginalPciAttributes,\r
+                    NULL\r
+                    );\r
 \r
     gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiPciIoProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
   }\r
 \r
   return Status;\r
@@ -269,22 +291,23 @@ AtapiScsiPassThruDriverBindingStop (
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+\r
   //\r
-  // Release Pci Io protocol on the controller handle.\r
+  // Restore original PCI attributes\r
   //\r
   AtapiScsiPrivate->PciIo->Attributes (\r
-                            AtapiScsiPrivate->PciIo,\r
-                            EfiPciIoAttributeOperationDisable,\r
-                            EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE,\r
-                            NULL\r
-                            );\r
+                  AtapiScsiPrivate->PciIo,\r
+                  EfiPciIoAttributeOperationSet,\r
+                  AtapiScsiPrivate->OriginalPciAttributes,\r
+                  NULL\r
+                  );\r
 \r
   gBS->CloseProtocol (\r
-        Controller,\r
-        &gEfiPciIoProtocolGuid,\r
-        This->DriverBindingHandle,\r
-        Controller\r
-        );\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
 \r
   gBS->FreePool (AtapiScsiPrivate);\r
 \r
@@ -294,8 +317,10 @@ AtapiScsiPassThruDriverBindingStop (
 /**\r
   Attaches SCSI Pass Thru Protocol for specified IDE channel.\r
 \r
-  @param Controller:       Parent device handle to the IDE channel.\r
-  @param PciIo:            PCI I/O protocol attached on the "Controller".\r
+  @param Controller:            Parent device handle to the IDE channel.\r
+  @param PciIo:                 PCI I/O protocol attached on the "Controller".\r
+  @param OriginalPciAttributes  Original PCI attributes\r
+\r
 \r
   @return EFI_SUCCESS Always returned unless installing SCSI Pass Thru Protocol failed.\r
 \r
@@ -308,36 +333,41 @@ EFI_STATUS
 RegisterAtapiScsiPassThru (\r
   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
   IN  EFI_HANDLE                  Controller,\r
-  IN  EFI_PCI_IO_PROTOCOL         *PciIo\r
+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,\r
+  IN  UINT64                      OriginalPciAttributes\r
   )\r
 {\r
   EFI_STATUS                Status;\r
   ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;\r
-  UINT64                    Attributes;\r
+  IDE_REGISTERS_BASE_ADDR   IdeRegsBaseAddr[ATAPI_MAX_CHANNEL];\r
 \r
   AtapiScsiPrivate = AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV));\r
   if (AtapiScsiPrivate == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  Attributes = EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE;\r
   CopyMem (AtapiScsiPrivate->ChannelName, gAtapiChannelString, sizeof (gAtapiChannelString));\r
 \r
-  //\r
-  // Enable channel\r
-  //\r
-  PciIo->Attributes (PciIo, EfiPciIoAttributeOperationSet, Attributes, NULL);\r
-\r
   AtapiScsiPrivate->Signature = ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE;\r
   AtapiScsiPrivate->Handle    = Controller;\r
 \r
   //\r
   // will reset the IoPort inside each API function.\r
   //\r
-  AtapiScsiPrivate->IoPort  = gAtapiIoPortRegisters;\r
-  AtapiScsiPrivate->PciIo   = PciIo;\r
+  AtapiScsiPrivate->IoPort                = NULL;\r
+  AtapiScsiPrivate->PciIo                 = PciIo;\r
+  AtapiScsiPrivate->OriginalPciAttributes = OriginalPciAttributes;\r
 \r
   //\r
+  // Obtain IDE IO port registers' base addresses\r
+  //\r
+  Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  InitAtapiIoPortRegisters(AtapiScsiPrivate, IdeRegsBaseAddr);\r
+\r
   // initialize SCSI Pass Thru Protocol interface\r
   //\r
   AtapiScsiPrivate->ScsiPassThru.Mode             = &AtapiScsiPrivate->ScsiPassThruMode;\r
@@ -359,14 +389,14 @@ RegisterAtapiScsiPassThru (
   //\r
   // non-RAID SCSI controllers should set both physical and logical attributes\r
   //\r
-  AtapiScsiPrivate->ScsiPassThruMode.Attributes = EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | \r
+  AtapiScsiPrivate->ScsiPassThruMode.Attributes = EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |\r
                                                   EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;\r
   AtapiScsiPrivate->ScsiPassThruMode.IoAlign = 0;\r
 \r
   //\r
-  // Initialize the LatestTargetId to 0xFFFFFFFF (for the GetNextDevice() call).\r
+  // Initialize the LatestTargetId.\r
   //\r
-  AtapiScsiPrivate->LatestTargetId  = 0xFFFFFFFF;\r
+  AtapiScsiPrivate->LatestTargetId  = 4;\r
   AtapiScsiPrivate->LatestLun       = 0;\r
 \r
   Status = gBS->InstallProtocolInterface (\r
@@ -411,18 +441,18 @@ AtapiScsiPassThruFunction (
   IN EFI_EVENT                                          Event OPTIONAL\r
   )\r
 {\r
-  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;\r
-  EFI_STATUS                Status;\r
+  ATAPI_SCSI_PASS_THRU_DEV               *AtapiScsiPrivate;\r
+  EFI_STATUS                             Status;\r
 \r
   AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
 \r
   //\r
   // Target is not allowed beyond MAX_TARGET_ID\r
   //\r
-  if (Target > MAX_TARGET_ID) {\r
+  if ((Target > MAX_TARGET_ID) || (Lun != 0)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   //\r
   // check the data fields in Packet parameter.\r
   //\r
@@ -439,18 +469,20 @@ AtapiScsiPassThruFunction (
     Packet->TransferLength = 0;\r
     return EFI_SUCCESS;\r
   }\r
-  \r
+\r
   //\r
   // According to Target ID, reset the Atapi I/O Register mapping\r
-  // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0],\r
-  //  Target Id in [2,3] area, using gAtapiIoPortRegisters[1]\r
+  // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],\r
+  //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]\r
   //\r
   if ((Target / 2) == 0) {\r
-    AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[0];\r
+    Target = Target % 2;\r
+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];\r
   } else {\r
-    AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[1];\r
+    Target = Target % 2;\r
+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];\r
   }\r
-  \r
+\r
   //\r
   // the ATAPI SCSI interface does not support non-blocking I/O\r
   // ignore the Event parameter\r
@@ -462,7 +494,7 @@ AtapiScsiPassThruFunction (
 }\r
 \r
 /**\r
-  Used to retrieve the list of legal Target IDs for SCSI devices \r
+  Used to retrieve the list of legal Target IDs for SCSI devices\r
   on a SCSI channel.\r
 \r
   @param  This Protocol instance pointer.\r
@@ -535,7 +567,7 @@ AtapiScsiPassThruGetNextDevice (
 }\r
 \r
 /**\r
-  Used to allocate and build a device path node for a SCSI device \r
+  Used to allocate and build a device path node for a SCSI device\r
   on a SCSI channel. Would not build device path for a SCSI Host Controller.\r
 \r
   @param  This Protocol instance pointer.\r
@@ -572,14 +604,15 @@ AtapiScsiPassThruBuildDevicePath (
 {\r
   EFI_DEV_PATH              *Node;\r
 \r
+\r
   //\r
   // Validate parameters passed in.\r
   //\r
-  \r
+\r
   if (DevicePath == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   //\r
   // can not build device path for the SCSI Host Controller.\r
   //\r
@@ -645,7 +678,7 @@ AtapiScsiPassThruGetTargetLun (
   if (DevicePath == NULL || Target == NULL || Lun == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   //\r
   // Check whether the DevicePath belongs to SCSI_DEVICE_PATH\r
   //\r
@@ -668,7 +701,7 @@ AtapiScsiPassThruGetTargetLun (
 }\r
 \r
 /**\r
-  Resets a SCSI channel.This operation resets all the \r
+  Resets a SCSI channel.This operation resets all the\r
   SCSI devices connected to the SCSI channel.\r
 \r
   @param  This Protocol instance pointer.\r
@@ -691,8 +724,10 @@ AtapiScsiPassThruResetChannel (
   UINT8                     DeviceControlValue;\r
   ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;\r
   UINT8                     Index;\r
+  BOOLEAN                   ResetFlag;\r
 \r
   AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
+  ResetFlag = FALSE;\r
 \r
   //\r
   // Reset both Primary channel and Secondary channel.\r
@@ -702,7 +737,7 @@ AtapiScsiPassThruResetChannel (
     //\r
     // Reset\r
     //\r
-    AtapiScsiPrivate->IoPort  = &gAtapiIoPortRegisters[Index];\r
+    AtapiScsiPrivate->IoPort  = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];\r
 \r
     DeviceControlValue        = 0;\r
     //\r
@@ -729,18 +764,22 @@ AtapiScsiPassThruResetChannel (
     // 0xfb:1111,1011\r
     //\r
     DeviceControlValue &= 0xfb;\r
-    \r
+\r
     WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);\r
 \r
     //\r
     // slave device needs at most 31s to clear BSY\r
     //\r
-    if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000) == EFI_TIMEOUT) {\r
-      return EFI_DEVICE_ERROR;\r
+    if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {\r
+      ResetFlag = TRUE;\r
     }\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  if (ResetFlag) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
 }\r
 \r
 /**\r
@@ -776,7 +815,7 @@ AtapiScsiPassThruResetTarget (
 \r
   AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
 \r
-  if (Target > MAX_TARGET_ID) {\r
+  if ((Target > MAX_TARGET_ID) || (Lun != 0)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
   //\r
@@ -785,18 +824,18 @@ AtapiScsiPassThruResetTarget (
   if (Target == This->Mode->AdapterId) {\r
     return EFI_SUCCESS;\r
   }\r
-  \r
+\r
   //\r
   // According to Target ID, reset the Atapi I/O Register mapping\r
-  // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0],\r
-  //  Target Id in [2,3] area, using gAtapiIoPortRegisters[1]\r
+  // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],\r
+  //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]\r
   //\r
   if ((Target / 2) == 0) {\r
-    AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[0];\r
+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];\r
   } else {\r
-    AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[1];\r
+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];\r
   }\r
-  \r
+\r
   //\r
   // for ATAPI device, no need to wait DRDY ready after device selecting.\r
   //\r
@@ -813,10 +852,10 @@ AtapiScsiPassThruResetTarget (
   // when reset is complete.\r
   // slave device needs at most 31s to clear BSY\r
   //\r
-  if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000))) {\r
-    return EFI_DEVICE_ERROR;\r
+  if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {\r
+    return EFI_TIMEOUT;\r
   }\r
-  \r
+\r
   //\r
   // stall 5 seconds to make the device status stable\r
   //\r
@@ -825,25 +864,159 @@ AtapiScsiPassThruResetTarget (
   return EFI_SUCCESS;\r
 }\r
 \r
-    \r
-/**\r
-  Checks the parameters in the SCSI Request Packet to make sure\r
-  they are valid for a SCSI Pass Thru request.\r
+EFI_STATUS\r
+GetIdeRegistersBaseAddr (\r
+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,\r
+  OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,\r
+  use fixed addresses. In Native-PCI mode, get base addresses from BARs in\r
+  the PCI IDE controller's Configuration Space.\r
+\r
+Arguments:\r
+  PciIo             - Pointer to the EFI_PCI_IO_PROTOCOL instance\r
+  IdeRegsBaseAddr   - Pointer to IDE_REGISTERS_BASE_ADDR to\r
+                      receive IDE IO port registers' base addresses\r
+\r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  PCI_TYPE00  PciData;\r
+\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        0,\r
+                        sizeof (PciData),\r
+                        &PciData\r
+                        );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
+    IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  = 0x1f0;\r
+    IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  = 0x3f6;\r
+  } else {\r
+    //\r
+    // The BARs should be of IO type\r
+    //\r
+    if ((PciData.Device.Bar[0] & BIT0) == 0 ||\r
+        (PciData.Device.Bar[1] & BIT0) == 0) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  =\r
+    (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
+    IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  =\r
+    (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
+  }\r
+\r
+  if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
+    IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  = 0x170;\r
+    IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  = 0x376;\r
+  } else {\r
+    //\r
+    // The BARs should be of IO type\r
+    //\r
+    if ((PciData.Device.Bar[2] & BIT0) == 0 ||\r
+        (PciData.Device.Bar[3] & BIT0) == 0) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  =\r
+    (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
+    IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  =\r
+    (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+InitAtapiIoPortRegisters (\r
+  IN  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,\r
+  IN  IDE_REGISTERS_BASE_ADDR      *IdeRegsBaseAddr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initialize each Channel's Base Address of CommandBlock and ControlBlock.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  IdeRegsBaseAddr             - The pointer of IDE_REGISTERS_BASE_ADDR\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+\r
+  UINT8               IdeChannel;\r
+  UINT16              CommandBlockBaseAddr;\r
+  UINT16              ControlBlockBaseAddr;\r
+  IDE_BASE_REGISTERS  *RegisterPointer;\r
+\r
+\r
+  for (IdeChannel = 0; IdeChannel < ATAPI_MAX_CHANNEL; IdeChannel++) {\r
+\r
+    RegisterPointer =  &AtapiScsiPrivate->AtapiIoPortRegisters[IdeChannel];\r
+\r
+    //\r
+    // Initialize IDE IO port addresses, including Command Block registers\r
+    // and Control Block registers\r
+    //\r
+    CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr;\r
+    ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr;\r
+\r
+    RegisterPointer->Data = CommandBlockBaseAddr;\r
+    (*(UINT16 *) &RegisterPointer->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);\r
+    RegisterPointer->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
+    RegisterPointer->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
+    RegisterPointer->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
+    RegisterPointer->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
+    RegisterPointer->Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
+    (*(UINT16 *) &RegisterPointer->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);\r
+\r
+    (*(UINT16 *) &RegisterPointer->Alt) = ControlBlockBaseAddr;\r
+    RegisterPointer->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);\r
+  }\r
+\r
+}\r
+\r
 \r
-  @todo function comment is missing 'Routine Description:'\r
-  @todo function comment is missing 'Arguments:'\r
-  @todo function comment is missing 'Returns:'\r
-  @todo    Packet - add argument and description to function comment\r
-  @todo    EFI_INVALID_PARAMETER - add return value to function comment\r
-  @todo    EFI_INVALID_PARAMETER - add return value to function comment\r
-  @todo    EFI_INVALID_PARAMETER - add return value to function comment\r
-  @todo    EFI_UNSUPPORTED - add return value to function comment\r
-  @todo    EFI_SUCCESS - add return value to function comment\r
-**/\r
 EFI_STATUS\r
 CheckSCSIRequestPacket (\r
   EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet\r
   )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Checks the parameters in the SCSI Request Packet to make sure\r
+  they are valid for a SCSI Pass Thru request.\r
+\r
+Arguments:\r
+\r
+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
+\r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
 {\r
   if (Packet == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -856,7 +1029,7 @@ CheckSCSIRequestPacket (
   if (Packet->Cdb == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   //\r
   // Checks whether the request command is supported.\r
   //\r
@@ -868,7 +1041,7 @@ CheckSCSIRequestPacket (
 }\r
 \r
 /**\r
-  Checks the requested SCSI command: \r
+  Checks the requested SCSI command:\r
   Is it supported by this driver?\r
   Is the Data transfer direction reasonable?\r
 \r
@@ -971,14 +1144,26 @@ SubmitBlockingIoCommand (
     Packet->SenseDataLength = 0;\r
     return PacketCommandStatus;\r
   }\r
+\r
+  //\r
+  // Check if SenseData meets the alignment requirement.\r
+  //\r
+  if ((AtapiScsiPrivate->ScsiPassThru.Mode->IoAlign != 0)     \\r
+    && (AtapiScsiPrivate->ScsiPassThru.Mode->IoAlign != 1)) {\r
+    if (((UINTN)Packet->SenseData % AtapiScsiPrivate->ScsiPassThru.Mode->IoAlign) != 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+\r
   //\r
   // Return SenseData if PacketCommandStatus matches\r
   // the following return codes.\r
   //\r
-  if ((PacketCommandStatus == EFI_WARN_BUFFER_TOO_SMALL) ||\r
+  if ((PacketCommandStatus ==  EFI_BAD_BUFFER_SIZE) ||\r
       (PacketCommandStatus == EFI_DEVICE_ERROR) ||\r
       (PacketCommandStatus == EFI_TIMEOUT)) {\r
-    \r
+\r
     //\r
     // avoid submit request sense command continuously.\r
     //\r
@@ -1096,18 +1281,25 @@ AtapiPacketCommand (
   EFI_STATUS  Status;\r
 \r
   //\r
-  // Set all the command parameters by fill related registers.\r
-  // Before write to all the following registers, BSY and DRQ must be 0.\r
+  // Check if the buffer meets the alignment requirement.\r
   //\r
-  Status = StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
-  if (EFI_ERROR (Status)) {\r
-    if (Status == EFI_ABORTED) {\r
-      Status = EFI_DEVICE_ERROR;\r
+  if ((AtapiScsiPrivate->ScsiPassThru.Mode->IoAlign != 0)     \\r
+    && (AtapiScsiPrivate->ScsiPassThru.Mode->IoAlign != 1)) {\r
+    if (((UINTN)Buffer % AtapiScsiPrivate->ScsiPassThru.Mode->IoAlign) != 0) {\r
+      return EFI_INVALID_PARAMETER;\r
     }\r
+  }\r
 \r
-    *ByteCount = 0;\r
-    return Status;\r
+  //\r
+  // Set all the command parameters by fill related registers.\r
+  // Before write to all the following registers, BSY must be 0.\r
+  //\r
+  Status = StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
   }\r
+\r
+\r
   //\r
   // Select device via Device/Head Register.\r
   // "Target = 0" indicates device 0; "Target = 1" indicates device 1\r
@@ -1118,6 +1310,20 @@ AtapiPacketCommand (
     (UINT8) ((Target << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)\r
     );\r
 \r
+  //\r
+  // Set all the command parameters by fill related registers.\r
+  // Before write to all the following registers, BSY DRQ must be 0.\r
+  //\r
+   Status =  StatusDRQClear(AtapiScsiPrivate,  TimeoutInMicroSeconds);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    if (Status == EFI_ABORTED) {\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
+    *ByteCount = 0;\r
+    return Status;\r
+  }\r
+\r
   //\r
   // No OVL; No DMA (by setting feature register)\r
   //\r
@@ -1282,7 +1488,7 @@ AtapiPassThruPioReadWriteData (
       // ActualWordCount > 0\r
       //\r
       if (ActualWordCount < RequiredWordCount) {\r
-        return EFI_WARN_BUFFER_TOO_SMALL;\r
+        return EFI_BAD_BUFFER_SIZE;\r
       }\r
     }\r
     //\r
@@ -1447,7 +1653,7 @@ WritePortW (
 /**\r
   Check whether DRQ is clear in the Status Register. (BSY must also be cleared)\r
   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
-  DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is \r
+  DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is\r
   elapsed.\r
 \r
   @todo function comment is missing 'Routine Description:'\r
@@ -1525,10 +1731,10 @@ StatusDRQClear (
 }\r
 \r
 /**\r
-  Check whether DRQ is clear in the Alternate Status Register. \r
+  Check whether DRQ is clear in the Alternate Status Register.\r
   (BSY must also be cleared).\r
   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
-  DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is \r
+  DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is\r
   elapsed.\r
 \r
   @todo function comment is missing 'Routine Description:'\r
@@ -1606,7 +1812,7 @@ AltStatusDRQClear (
 /**\r
   Check whether DRQ is ready in the Status Register. (BSY must also be cleared)\r
   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
-  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is \r
+  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is\r
   elapsed.\r
 \r
   @todo function comment is missing 'Routine Description:'\r
@@ -1684,10 +1890,10 @@ StatusDRQReady (
 }\r
 \r
 /**\r
-  Check whether DRQ is ready in the Alternate Status Register. \r
+  Check whether DRQ is ready in the Alternate Status Register.\r
   (BSY must also be cleared)\r
   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
-  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is \r
+  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is\r
   elapsed.\r
 \r
   @todo function comment is missing 'Routine Description:'\r
@@ -1766,7 +1972,7 @@ AltStatusDRQReady (
 /**\r
   Check whether BSY is clear in the Status Register.\r
   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
-  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is \r
+  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is\r
   elapsed.\r
 \r
   @todo function comment is missing 'Routine Description:'\r
@@ -1827,7 +2033,7 @@ StatusWaitForBSYClear (
 /**\r
   Check whether BSY is clear in the Alternate Status Register.\r
   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
-  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is \r
+  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is\r
   elapsed.\r
 \r
   @todo function comment is missing 'Routine Description:'\r
@@ -1885,10 +2091,10 @@ AltStatusWaitForBSYClear (
 }\r
 \r
 /**\r
-  Check whether DRDY is ready in the Status Register. \r
+  Check whether DRDY is ready in the Status Register.\r
   (BSY must also be cleared)\r
   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
-  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is \r
+  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is\r
   elapsed.\r
 \r
   @todo function comment is missing 'Routine Description:'\r
@@ -1938,7 +2144,7 @@ StatusDRDYReady (
         return EFI_ABORTED;\r
       }\r
     }\r
-    \r
+\r
     //\r
     // Stall for 30 us\r
     //\r
@@ -1961,10 +2167,10 @@ StatusDRDYReady (
 }\r
 \r
 /**\r
-  Check whether DRDY is ready in the Alternate Status Register. \r
+  Check whether DRDY is ready in the Alternate Status Register.\r
   (BSY must also be cleared)\r
   If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
-  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is \r
+  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is\r
   elapsed.\r
 \r
   @todo function comment is missing 'Routine Description:'\r
@@ -2037,7 +2243,7 @@ AltStatusDRDYReady (
 }\r
 \r
 /**\r
-  Check Error Register for Error Information. \r
+  Check Error Register for Error Information.\r
 \r
   @todo function comment is missing 'Routine Description:'\r
   @todo function comment is missing 'Arguments:'\r
@@ -2058,7 +2264,7 @@ AtapiPassThruCheckErrorStatus (
                     AtapiScsiPrivate->PciIo,\r
                     AtapiScsiPrivate->IoPort->Reg.Status\r
                     );\r
-  \r
+\r
   DEBUG_CODE_BEGIN ();\r
 \r
     if (StatusRegister & DWF) {\r
@@ -2079,7 +2285,7 @@ AtapiPassThruCheckErrorStatus (
 \r
     if (StatusRegister & ERR) {\r
       ErrorRegister = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg1.Error);\r
-      \r
+\r
 \r
       if (ErrorRegister & BBK_ERR) {\r
         DEBUG (\r
@@ -2136,16 +2342,16 @@ AtapiPassThruCheckErrorStatus (
     return EFI_SUCCESS;\r
   }\r
 \r
\r
+\r
   return EFI_DEVICE_ERROR;\r
 }\r
 \r
 /**\r
   The user Entry Point for module AtapiPassThru. The user code starts with this function.\r
 \r
-  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
   @param[in] SystemTable    A pointer to the EFI System Table.\r
-  \r
+\r
   @retval EFI_SUCCESS       The entry point is executed successfully.\r
   @retval other             Some error occurs when executing this entry point.\r
 \r
@@ -2162,14 +2368,13 @@ InitializeAtapiPassThru(
   //\r
   // Install driver model protocol(s).\r
   //\r
-  Status = EfiLibInstallAllDriverProtocols (\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
              ImageHandle,\r
              SystemTable,\r
              &gAtapiScsiPassThruDriverBinding,\r
              ImageHandle,\r
              &gAtapiScsiPassThruComponentName,\r
-             NULL,\r
-             NULL\r
+             &gAtapiScsiPassThruComponentName2\r
              );\r
   ASSERT_EFI_ERROR (Status);\r
 \r