]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Add OptionRomPkg, it contains AtapiPassThru driver for the test purpose of Scsi Bus...
authorqhuang8 <qhuang8@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 20 Nov 2007 07:05:44 +0000 (07:05 +0000)
committerqhuang8 <qhuang8@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 20 Nov 2007 07:05:44 +0000 (07:05 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4309 6f19259b-4bc3-4df7-8a09-765794883524

OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c [new file with mode: 0644]
OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h [new file with mode: 0644]
OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf [new file with mode: 0644]
OptionRomPkg/AtapiPassThruDxe/ComponentName.c [new file with mode: 0644]
OptionRomPkg/OptionRomPkg.dec [new file with mode: 0644]
OptionRomPkg/OptionRomPkg.dsc [new file with mode: 0644]
OptionRomPkg/ReadMe.txt [new file with mode: 0644]

diff --git a/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c b/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c
new file mode 100644 (file)
index 0000000..b15f292
--- /dev/null
@@ -0,0 +1,3394 @@
+/** @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
+\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
+static SCSI_COMMAND_SET     gEndTable = { 0xff, (DATA_DIRECTION) 0xff };\r
+\r
+///\r
+/// This table contains all the supported ATAPI commands.\r
+///\r
+static SCSI_COMMAND_SET     gSupportedATAPICommands[] = {\r
+  { OP_INQUIRY,                     DataIn  },\r
+  { OP_LOAD_UNLOAD_CD,              NoData  },\r
+  { OP_MECHANISM_STATUS,            DataIn  },\r
+  { OP_MODE_SELECT_10,              DataOut },\r
+  { OP_MODE_SENSE_10,               DataIn  },\r
+  { OP_PAUSE_RESUME,                NoData  },\r
+  { OP_PLAY_AUDIO_10,               DataIn  },\r
+  { OP_PLAY_AUDIO_MSF,              DataIn  },\r
+  { OP_PLAY_CD,                     DataIn  },\r
+  { OP_PLAY_CD_MSF,                 DataIn  },\r
+  { OP_PREVENT_ALLOW_MEDIUM_REMOVAL,NoData  },\r
+  { OP_READ_10,                     DataIn  },\r
+  { OP_READ_12,                     DataIn  },\r
+  { OP_READ_CAPACITY,               DataIn  },\r
+  { OP_READ_CD,                     DataIn  },\r
+  { OP_READ_CD_MSF,                 DataIn  },\r
+  { OP_READ_HEADER,                 DataIn  },\r
+  { OP_READ_SUB_CHANNEL,            DataIn  },\r
+  { OP_READ_TOC,                    DataIn  },\r
+  { OP_REQUEST_SENSE,               DataIn  },\r
+  { OP_SCAN,                        NoData  },\r
+  { OP_SEEK_10,                     NoData  },\r
+  { OP_SET_CD_SPEED,                DataOut },\r
+  { OP_STOPPLAY_SCAN,               NoData  },\r
+  { OP_START_STOP_UNIT,             NoData  },\r
+  { OP_TEST_UNIT_READY,             NoData  },\r
+  { OP_FORMAT_UNIT,                 DataOut },\r
+  { OP_READ_FORMAT_CAPACITIES,      DataIn  },\r
+  { OP_VERIFY,                      DataOut },\r
+  { OP_WRITE_10,                    DataOut },\r
+  { OP_WRITE_12,                    DataOut },\r
+  { OP_WRITE_AND_VERIFY,            DataOut },\r
+  { 0xff,                           (DATA_DIRECTION) 0xff    }\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_MODE gScsiPassThruMode = {\r
+  L"ATAPI Controller",\r
+  L"ATAPI Channel",\r
+  4,\r
+  EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,\r
+  0\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_PROTOCOL gScsiPassThruProtocolTemplate = {\r
+  &gScsiPassThruMode,\r
+  AtapiScsiPassThruFunction,\r
+  AtapiScsiPassThruGetNextDevice,\r
+  AtapiScsiPassThruBuildDevicePath,\r
+  AtapiScsiPassThruGetTargetLun,\r
+  AtapiScsiPassThruResetChannel,\r
+  AtapiScsiPassThruResetTarget\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_MODE gExtScsiPassThruMode = {\r
+  4,      \r
+  EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,\r
+  0\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_PROTOCOL gExtScsiPassThruProtocolTemplate = {\r
+  &gExtScsiPassThruMode,\r
+  AtapiExtScsiPassThruFunction,\r
+  AtapiExtScsiPassThruGetNextTargetLun,\r
+  AtapiExtScsiPassThruBuildDevicePath,\r
+  AtapiExtScsiPassThruGetTargetLun,\r
+  AtapiExtScsiPassThruResetChannel,\r
+  AtapiExtScsiPassThruResetTarget,\r
+  AtapiExtScsiPassThruGetNextTarget\r
+};\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding = {\r
+  AtapiScsiPassThruDriverBindingSupported,\r
+  AtapiScsiPassThruDriverBindingStart,\r
+  AtapiScsiPassThruDriverBindingStop,\r
+  0x10,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+/*++\r
+  \r
+Routine Description:\r
+  Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
+  that has gEfiPciIoProtocolGuid installed and is IDE Controller it will be supported.\r
+    \r
+Arguments:\r
+\r
+  This                - Protocol instance pointer.\r
+  Controller          - Handle of device to test\r
+  RemainingDevicePath - Not used\r
+    \r
+Returns:\r
+    EFI_STATUS\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS          Status;\r
+  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
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Use the PCI I/O Protocol to see if Controller is a IDE Controller that\r
+  // can be managed by this driver.  Read the PCI Configuration Header\r
+  // for this device.\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint32,\r
+                        0,\r
+                        sizeof (Pci) / sizeof (UINT32),\r
+                        &Pci\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (Pci.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE || Pci.Hdr.ClassCode[1] != PCI_CLASS_IDE) {\r
+\r
+    Status = EFI_UNSUPPORTED;\r
+  }\r
+\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+/*++\r
+  \r
+Routine Description:\r
+  Create handles for IDE channels specified by RemainingDevicePath.\r
+  Install SCSI Pass Thru Protocol onto each created handle.\r
+  \r
+Arguments:\r
+\r
+  This                - Protocol instance pointer.\r
+  Controller          - Handle of device to test\r
+  RemainingDevicePath - Not used\r
+    \r
+Returns:\r
+    EFI_STATUS\r
+    \r
+--*/\r
+{\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
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Save original PCI attributes\r
+  //\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\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
+\r
+  //\r
+  // Create SCSI Pass Thru instance for the IDE channel.\r
+  //\r
+  Status = RegisterAtapiScsiPassThru (This, Controller, PciIo, OriginalPciAttributes);\r
+\r
+Done:\r
+  if (EFI_ERROR (Status)) {\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
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+/*++\r
+  \r
+Routine Description:\r
+\r
+  Stop this driver on ControllerHandle. Support stoping any child handles\r
+  created by this driver.\r
+\r
+Arguments:\r
+\r
+  This              - Protocol instance pointer.\r
+  Controller        - Handle of device to stop driver on\r
+  NumberOfChildren  - Number of Children in the ChildHandleBuffer\r
+  ChildHandleBuffer - List of handles for the children we need to stop.\r
+  \r
+Returns:\r
+\r
+    EFI_STATUS\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_SCSI_PASS_THRU_PROTOCOL     *ScsiPassThru;\r
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;\r
+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate;\r
+\r
+  if (FeaturePcdGet (PcdSupportScsiPassThru)) {\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiScsiPassThruProtocolGuid,\r
+                    (VOID **) &ScsiPassThru,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru);\r
+    if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {\r
+      Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                      Controller,\r
+                      &gEfiScsiPassThruProtocolGuid,\r
+                      &AtapiScsiPrivate->ScsiPassThru,\r
+                      &gEfiExtScsiPassThruProtocolGuid,\r
+                      &AtapiScsiPrivate->ExtScsiPassThru,\r
+                      NULL\r
+                      );\r
+    } else {\r
+      Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                      Controller,\r
+                      &gEfiScsiPassThruProtocolGuid,\r
+                      &AtapiScsiPrivate->ScsiPassThru,\r
+                      NULL\r
+                      );\r
+    }\r
+  } else {\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiExtScsiPassThruProtocolGuid,\r
+                    (VOID **) &ExtScsiPassThru,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (ExtScsiPassThru);\r
+    Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                    Controller,\r
+                    &gEfiExtScsiPassThruProtocolGuid,\r
+                    &AtapiScsiPrivate->ExtScsiPassThru,\r
+                    NULL\r
+                    );\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Restore original PCI attributes\r
+  //\r
+  AtapiScsiPrivate->PciIo->Attributes (\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
+\r
+  gBS->FreePool (AtapiScsiPrivate);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+RegisterAtapiScsiPassThru (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                  Controller,\r
+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,\r
+  IN  UINT64                      OriginalPciAttributes\r
+  )\r
+/*++\r
+  \r
+Routine Description:\r
+  Attaches SCSI Pass Thru Protocol for specified IDE channel.\r
+    \r
+Arguments:\r
+  This              - Protocol instance pointer.\r
+  Controller        - Parent device handle to the IDE channel.    \r
+  PciIo             - PCI I/O protocol attached on the "Controller".                        \r
+  \r
+Returns:\r
+  Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                Status;\r
+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;\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
+  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                = 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
+  //\r
+  // Initialize the LatestTargetId to MAX_TARGET_ID.\r
+  //\r
+  AtapiScsiPrivate->LatestTargetId  = MAX_TARGET_ID;\r
+  AtapiScsiPrivate->LatestLun       = 0;\r
+\r
+  Status = InstallScsiPassThruProtocols (&Controller, AtapiScsiPrivate);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruFunction (\r
+  IN EFI_SCSI_PASS_THRU_PROTOCOL                        *This,\r
+  IN UINT32                                             Target,\r
+  IN UINT64                                             Lun,\r
+  IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET         *Packet,\r
+  IN EFI_EVENT                                          Event OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.\r
+\r
+Arguments:\r
+\r
+  This:     The EFI_SCSI_PASS_THRU_PROTOCOL instance.\r
+  Target:   The Target ID of the ATAPI device to send the SCSI \r
+            Request Packet. To ATAPI devices attached on an IDE\r
+            Channel, Target ID 0 indicates Master device;Target\r
+            ID 1 indicates Slave device.\r
+  Lun:      The LUN of the ATAPI device to send the SCSI Request\r
+            Packet. To the ATAPI device, Lun is always 0.\r
+  Packet:   The SCSI Request Packet to send to the ATAPI device \r
+            specified by Target and Lun.\r
+  Event:    If non-blocking I/O is not supported then Event is ignored, \r
+            and blocking I/O is performed.\r
+            If Event is NULL, then blocking I/O is performed.\r
+            If Event is not NULL and non blocking I/O is supported, \r
+            then non-blocking I/O is performed, and Event will be signaled \r
+            when the SCSI Request Packet completes.      \r
+\r
+Returns:  \r
+\r
+   EFI_STATUS\r
+   \r
+--*/\r
+{\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) || (Lun != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // check the data fields in Packet parameter.\r
+  //\r
+  Status = CheckSCSIRequestPacket (Packet);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // If Request Packet targets at the IDE channel itself,\r
+  // do nothing.\r
+  //\r
+  if (Target == This->Mode->AdapterId) {\r
+    Packet->TransferLength = 0;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // According to Target ID, reset the Atapi I/O Register mapping\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
+    Target = Target % 2;\r
+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];\r
+  } else {\r
+    Target = Target % 2;\r
+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];\r
+  }\r
+\r
+  //\r
+  // the ATAPI SCSI interface does not support non-blocking I/O\r
+  // ignore the Event parameter\r
+  //\r
+  // Performs blocking I/O.\r
+  //\r
+  Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, Packet);\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruGetNextDevice (\r
+  IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT32                      *Target,\r
+  IN OUT UINT64                      *Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Used to retrieve the list of legal Target IDs for SCSI devices \r
+  on a SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - On input, a pointer to the Target ID of a SCSI \r
+                          device present on the SCSI channel.  On output, \r
+                          a pointer to the Target ID of the next SCSI device\r
+                          present on a SCSI channel.  An input value of \r
+                          0xFFFFFFFF retrieves the Target ID of the first \r
+                          SCSI device present on a SCSI channel.\r
+  Lun                   - On input, a pointer to the LUN of a SCSI device\r
+                          present on the SCSI channel. On output, a pointer\r
+                          to the LUN of the next SCSI device present on \r
+                          a SCSI channel.\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device \r
+                          on the SCSI channel was returned in Target and Lun.\r
+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.\r
+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not\r
+                           returned on a previous call to GetNextDevice().\r
+--*/\r
+{\r
+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;\r
+\r
+  //\r
+  // Retrieve Device Private Data Structure.\r
+  //\r
+  AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
+\r
+  //\r
+  // Check whether Target is valid.\r
+  //\r
+  if (Target == NULL || Lun == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*Target != 0xFFFFFFFF) &&\r
+      ((*Target != AtapiScsiPrivate->LatestTargetId) ||\r
+      (*Lun != AtapiScsiPrivate->LatestLun))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*Target == MAX_TARGET_ID) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (*Target == 0xFFFFFFFF) {\r
+    *Target = 0;\r
+  } else {\r
+    *Target = AtapiScsiPrivate->LatestTargetId + 1;\r
+  }\r
+\r
+  *Lun = 0;\r
+\r
+  //\r
+  // Update the LatestTargetId.\r
+  //\r
+  AtapiScsiPrivate->LatestTargetId  = *Target;\r
+  AtapiScsiPrivate->LatestLun       = *Lun;\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruBuildDevicePath (\r
+  IN     EFI_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN     UINT32                         Target,\r
+  IN     UINT64                         Lun,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL       **DevicePath\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - The Target ID of the SCSI device for which\r
+                          a device path node is to be allocated and built.\r
+  Lun                   - The LUN of the SCSI device for which a device \r
+                          path node is to be allocated and built.\r
+  DevicePath            - A pointer to a single device path node that \r
+                          describes the SCSI device specified by \r
+                          Target and Lun. This function is responsible \r
+                          for allocating the buffer DevicePath with the boot\r
+                          service AllocatePool().  It is the caller's \r
+                          responsibility to free DevicePath when the caller\r
+                          is finished with DevicePath.    \r
+  Returns:\r
+  EFI_SUCCESS           - The device path node that describes the SCSI device\r
+                          specified by Target and Lun was allocated and \r
+                          returned in DevicePath.\r
+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does\r
+                          not exist on the SCSI channel.\r
+  EFI_INVALID_PARAMETER - DevicePath is NULL.\r
+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate \r
+                          DevicePath.\r
+--*/\r
+{\r
+  EFI_DEV_PATH              *Node;\r
+\r
+\r
+  //\r
+  // Validate parameters passed in.\r
+  //\r
+\r
+  if (DevicePath == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // can not build device path for the SCSI Host Controller.\r
+  //\r
+  if ((Target > (MAX_TARGET_ID - 1)) || (Lun != 0)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));\r
+  if (Node == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Node->DevPath.Type    = MESSAGING_DEVICE_PATH;\r
+  Node->DevPath.SubType = MSG_ATAPI_DP;\r
+  SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));\r
+\r
+  Node->Atapi.PrimarySecondary  = (UINT8) (Target / 2);\r
+  Node->Atapi.SlaveMaster       = (UINT8) (Target % 2);\r
+  Node->Atapi.Lun               = (UINT16) Lun;\r
+\r
+  *DevicePath                   = (EFI_DEVICE_PATH_PROTOCOL *) Node;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruGetTargetLun (\r
+  IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,\r
+  OUT UINT32                         *Target,\r
+  OUT UINT64                         *Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Used to translate a device path node to a Target ID and LUN.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  DevicePath            - A pointer to the device path node that \r
+                          describes a SCSI device on the SCSI channel.\r
+  Target                - A pointer to the Target ID of a SCSI device \r
+                          on the SCSI channel. \r
+  Lun                   - A pointer to the LUN of a SCSI device on \r
+                          the SCSI channel.    \r
+Returns:\r
+\r
+  EFI_SUCCESS           - DevicePath was successfully translated to a \r
+                          Target ID and LUN, and they were returned \r
+                          in Target and Lun.\r
+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.\r
+  EFI_UNSUPPORTED       - This driver does not support the device path \r
+                          node type in DevicePath.\r
+  EFI_NOT_FOUND         - A valid translation from DevicePath to a \r
+                          Target ID and LUN does not exist.\r
+--*/\r
+{\r
+  EFI_DEV_PATH  *Node;\r
+\r
+  //\r
+  // Validate parameters passed in.\r
+  //\r
+  if (DevicePath == NULL || Target == NULL || Lun == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether the DevicePath belongs to SCSI_DEVICE_PATH\r
+  //\r
+  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
+      (DevicePath->SubType != MSG_ATAPI_DP) ||\r
+      (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Node    = (EFI_DEV_PATH *) DevicePath;\r
+\r
+  *Target = Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster;\r
+  *Lun    = Node->Atapi.Lun;\r
+\r
+  if (*Target > (MAX_TARGET_ID - 1) || *Lun != 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruResetChannel (\r
+  IN  EFI_SCSI_PASS_THRU_PROTOCOL   *This\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Resets a SCSI channel.This operation resets all the \r
+  SCSI devices connected to the SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The SCSI channel was reset.\r
+  EFI_UNSUPPORTED       - The SCSI channel does not support \r
+                          a channel reset operation.\r
+  EFI_DEVICE_ERROR      - A device error occurred while \r
+                          attempting to reset the SCSI channel.\r
+  EFI_TIMEOUT           - A timeout occurred while attempting \r
+                          to reset the SCSI channel.\r
+--*/\r
+{\r
+  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
+  // so, the IoPort pointer must point to the right I/O Register group\r
+  //\r
+  for (Index = 0; Index < 2; Index++) {\r
+    //\r
+    // Reset\r
+    //\r
+    AtapiScsiPrivate->IoPort  = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];\r
+\r
+    DeviceControlValue        = 0;\r
+    //\r
+    // set SRST bit to initiate soft reset\r
+    //\r
+    DeviceControlValue |= SRST;\r
+    //\r
+    // disable Interrupt\r
+    //\r
+    DeviceControlValue |= bit (1);\r
+    WritePortB (\r
+      AtapiScsiPrivate->PciIo,\r
+      AtapiScsiPrivate->IoPort->Alt.DeviceControl,\r
+      DeviceControlValue\r
+      );\r
+\r
+    //\r
+    // Wait 10us\r
+    //\r
+    gBS->Stall (10);\r
+\r
+    //\r
+    // Clear SRST bit\r
+    // 0xfb:1111,1011\r
+    //\r
+    DeviceControlValue &= 0xfb;\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, 31000000) != EFI_TIMEOUT) {\r
+      ResetFlag = TRUE;\r
+    }\r
+  }\r
+\r
+  if (ResetFlag) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruResetTarget (\r
+  IN EFI_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN UINT32                         Target,\r
+  IN UINT64                         Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Resets a SCSI device that is connected to a SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - The Target ID of the SCSI device to reset. \r
+  Lun                   - The LUN of the SCSI device to reset.\r
+    \r
+Returns:\r
+\r
+  EFI_SUCCESS           - The SCSI device specified by Target and \r
+                          Lun was reset.\r
+  EFI_UNSUPPORTED       - The SCSI channel does not support a target\r
+                          reset operation.\r
+  EFI_INVALID_PARAMETER - Target or Lun are invalid.\r
+  EFI_DEVICE_ERROR      - A device error occurred while attempting \r
+                          to reset the SCSI device specified by Target \r
+                          and Lun.\r
+  EFI_TIMEOUT           - A timeout occurred while attempting to reset \r
+                          the SCSI device specified by Target and Lun.\r
+--*/\r
+{\r
+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;\r
+  UINT8                     Command;\r
+  UINT8                     DeviceSelect;\r
+\r
+  AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
+\r
+  if ((Target > MAX_TARGET_ID) || (Lun != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Directly return EFI_SUCCESS if want to reset the host controller\r
+  //\r
+  if (Target == This->Mode->AdapterId) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // According to Target ID, reset the Atapi I/O Register mapping\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 = &AtapiScsiPrivate->AtapiIoPortRegisters[0];\r
+  } else {\r
+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];\r
+  }\r
+\r
+  //\r
+  // for ATAPI device, no need to wait DRDY ready after device selecting.\r
+  //\r
+  // bit7 and bit5 are both set to 1 for backward compatibility\r
+  //\r
+  DeviceSelect = (UINT8) (((bit (7) | bit (5)) | (Target << 4)));\r
+  WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);\r
+\r
+  Command = ATAPI_SOFT_RESET_CMD;\r
+  WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);\r
+\r
+  //\r
+  // BSY clear is the only status return to the host by the device\r
+  // when reset is complete.\r
+  // slave device needs at most 31s to clear BSY\r
+  //\r
+  if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  //\r
+  // stall 5 seconds to make the device status stable\r
+  //\r
+  gBS->Stall (5000000);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruFunction (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                    *This,\r
+  IN UINT8                                              *Target,\r
+  IN UINT64                                             Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET     *Packet,\r
+  IN EFI_EVENT                                          Event OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.\r
+\r
+Arguments:\r
+\r
+  This:     The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  Target:   The Target ID of the ATAPI device to send the SCSI \r
+            Request Packet. To ATAPI devices attached on an IDE\r
+            Channel, Target ID 0 indicates Master device;Target\r
+            ID 1 indicates Slave device.\r
+  Lun:      The LUN of the ATAPI device to send the SCSI Request\r
+            Packet. To the ATAPI device, Lun is always 0.\r
+  Packet:   The SCSI Request Packet to send to the ATAPI device \r
+            specified by Target and Lun.\r
+  Event:    If non-blocking I/O is not supported then Event is ignored, \r
+            and blocking I/O is performed.\r
+            If Event is NULL, then blocking I/O is performed.\r
+            If Event is not NULL and non blocking I/O is supported, \r
+            then non-blocking I/O is performed, and Event will be signaled \r
+            when the SCSI Request Packet completes.      \r
+\r
+Returns:  \r
+\r
+   EFI_STATUS\r
+   \r
+--*/\r
+{\r
+  EFI_STATUS                          Status;\r
+  ATAPI_SCSI_PASS_THRU_DEV            *AtapiScsiPrivate;\r
+  UINT8                                TargetId;\r
+  \r
+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
+\r
+  //\r
+  // For ATAPI device, UINT8 is enough to represent the SCSI ID on channel.\r
+  //\r
+  TargetId = Target[0];\r
+  \r
+  //\r
+  // Target is not allowed beyond MAX_TARGET_ID\r
+  //\r
+  if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // check the data fields in Packet parameter.\r
+  //\r
+  Status = CheckExtSCSIRequestPacket (Packet);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // If Request Packet targets at the IDE channel itself,\r
+  // do nothing.\r
+  //\r
+  if (TargetId == (UINT8)This->Mode->AdapterId) {\r
+    Packet->InTransferLength = Packet->OutTransferLength = 0;\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  //\r
+  // According to Target ID, reset the Atapi I/O Register mapping\r
+  // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],\r
+  //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]\r
+  //\r
+  if ((TargetId / 2) == 0) {\r
+    TargetId = (UINT8) (TargetId % 2);\r
+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];\r
+  } else {\r
+    TargetId = (UINT8) (TargetId % 2);\r
+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];\r
+  }\r
+  \r
+  //\r
+  // the ATAPI SCSI interface does not support non-blocking I/O\r
+  // ignore the Event parameter\r
+  //\r
+  // Performs blocking I/O.\r
+  //\r
+  Status = SubmitExtBlockingIoCommand (AtapiScsiPrivate, TargetId, Packet);\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruGetNextTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT8                           **Target,\r
+  IN OUT UINT64                          *Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Used to retrieve the list of legal Target IDs for SCSI devices \r
+  on a SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - On input, a pointer to the Target ID of a SCSI \r
+                          device present on the SCSI channel.  On output, \r
+                          a pointer to the Target ID of the next SCSI device\r
+                          present on a SCSI channel.  An input value of \r
+                          0xFFFFFFFF retrieves the Target ID of the first \r
+                          SCSI device present on a SCSI channel.\r
+  Lun                   - On input, a pointer to the LUN of a SCSI device\r
+                          present on the SCSI channel. On output, a pointer\r
+                          to the LUN of the next SCSI device present on \r
+                          a SCSI channel.\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device \r
+                          on the SCSI channel was returned in Target and Lun.\r
+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.\r
+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not\r
+                           returned on a previous call to GetNextDevice().\r
+--*/\r
+{\r
+  UINT8                          ByteIndex;\r
+  UINT8                          TargetId;\r
+  UINT8                          ScsiId[TARGET_MAX_BYTES];\r
+  ATAPI_SCSI_PASS_THRU_DEV       *AtapiScsiPrivate; \r
+\r
+  //\r
+  // Retrieve Device Private Data Structure.\r
+  //\r
+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
+\r
+  //\r
+  // Check whether Target is valid.\r
+  //\r
+  if (*Target == NULL || Lun == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);\r
+\r
+  TargetId = (*Target)[0];\r
+\r
+  //\r
+  // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.\r
+  //\r
+  if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {\r
+    for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {\r
+      if ((*Target)[ByteIndex] != 0) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    } \r
+  }\r
+  \r
+  if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&\r
+      ((TargetId != AtapiScsiPrivate->LatestTargetId) ||\r
+      (*Lun != AtapiScsiPrivate->LatestLun))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (TargetId == MAX_TARGET_ID) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0) {\r
+    SetMem (*Target, TARGET_MAX_BYTES,0);\r
+  } else {\r
+    (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);\r
+  }\r
+\r
+  *Lun = 0;\r
+\r
+  //\r
+  // Update the LatestTargetId.\r
+  //\r
+  AtapiScsiPrivate->LatestTargetId  = (*Target)[0];\r
+  AtapiScsiPrivate->LatestLun       = *Lun;\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruBuildDevicePath (\r
+  IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN     UINT8                              *Target,\r
+  IN     UINT64                             Lun,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL           **DevicePath\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - The Target ID of the SCSI device for which\r
+                          a device path node is to be allocated and built.\r
+  Lun                   - The LUN of the SCSI device for which a device \r
+                          path node is to be allocated and built.\r
+  DevicePath            - A pointer to a single device path node that \r
+                          describes the SCSI device specified by \r
+                          Target and Lun. This function is responsible \r
+                          for allocating the buffer DevicePath with the boot\r
+                          service AllocatePool().  It is the caller's \r
+                          responsibility to free DevicePath when the caller\r
+                          is finished with DevicePath.    \r
+  Returns:\r
+  EFI_SUCCESS           - The device path node that describes the SCSI device\r
+                          specified by Target and Lun was allocated and \r
+                          returned in DevicePath.\r
+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does\r
+                          not exist on the SCSI channel.\r
+  EFI_INVALID_PARAMETER - DevicePath is NULL.\r
+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate \r
+                          DevicePath.\r
+--*/\r
+{\r
+  EFI_DEV_PATH                   *Node;\r
+  UINT8                          TargetId;\r
+\r
+  TargetId = Target[0];  \r
+\r
+  //\r
+  // Validate parameters passed in.\r
+  //\r
+  \r
+  if (DevicePath == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // can not build device path for the SCSI Host Controller.\r
+  //\r
+  if ((TargetId > (MAX_TARGET_ID - 1)) || (Lun != 0)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));\r
+  if (Node == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Node->DevPath.Type    = MESSAGING_DEVICE_PATH;\r
+  Node->DevPath.SubType = MSG_ATAPI_DP;\r
+  SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));\r
+\r
+  Node->Atapi.PrimarySecondary  = (UINT8) (TargetId / 2);\r
+  Node->Atapi.SlaveMaster       = (UINT8) (TargetId % 2);\r
+  Node->Atapi.Lun               = (UINT16) Lun;\r
+\r
+  *DevicePath                   = (EFI_DEVICE_PATH_PROTOCOL *) Node;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruGetTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL           *DevicePath,\r
+  OUT UINT8                              **Target,\r
+  OUT UINT64                             *Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Used to translate a device path node to a Target ID and LUN.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  DevicePath            - A pointer to the device path node that \r
+                          describes a SCSI device on the SCSI channel.\r
+  Target                - A pointer to the Target ID of a SCSI device \r
+                          on the SCSI channel. \r
+  Lun                   - A pointer to the LUN of a SCSI device on \r
+                          the SCSI channel.    \r
+Returns:\r
+\r
+  EFI_SUCCESS           - DevicePath was successfully translated to a \r
+                          Target ID and LUN, and they were returned \r
+                          in Target and Lun.\r
+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.\r
+  EFI_UNSUPPORTED       - This driver does not support the device path \r
+                          node type in DevicePath.\r
+  EFI_NOT_FOUND         - A valid translation from DevicePath to a \r
+                          Target ID and LUN does not exist.\r
+--*/\r
+{\r
+  EFI_DEV_PATH  *Node;\r
+\r
+  //\r
+  // Validate parameters passed in.\r
+  //\r
+  if (DevicePath == NULL || Target == NULL || Lun == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Check whether the DevicePath belongs to SCSI_DEVICE_PATH\r
+  //\r
+  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
+      (DevicePath->SubType != MSG_ATAPI_DP) ||\r
+      (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  ZeroMem (*Target, TARGET_MAX_BYTES);\r
+\r
+  Node    = (EFI_DEV_PATH *) DevicePath;\r
+\r
+  (*Target)[0] = (UINT8) (Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster);\r
+  *Lun    = Node->Atapi.Lun;\r
+\r
+  if ((*Target)[0] > (MAX_TARGET_ID - 1) || *Lun != 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruResetChannel (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *This\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Resets a SCSI channel.This operation resets all the \r
+  SCSI devices connected to the SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The SCSI channel was reset.\r
+  EFI_UNSUPPORTED       - The SCSI channel does not support \r
+                          a channel reset operation.\r
+  EFI_DEVICE_ERROR      - A device error occurred while \r
+                          attempting to reset the SCSI channel.\r
+  EFI_TIMEOUT           - A timeout occurred while attempting \r
+                          to reset the SCSI channel.\r
+--*/\r
+{\r
+  UINT8                         DeviceControlValue;\r
+  UINT8                         Index;\r
+  ATAPI_SCSI_PASS_THRU_DEV      *AtapiScsiPrivate;\r
+  BOOLEAN                       ResetFlag;\r
+\r
+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
+  ResetFlag = FALSE;\r
+  //\r
+  // Reset both Primary channel and Secondary channel.\r
+  // so, the IoPort pointer must point to the right I/O Register group\r
+  // And if there is a channel reset successfully, return EFI_SUCCESS.\r
+  //\r
+  for (Index = 0; Index < 2; Index++) {\r
+    //\r
+    // Reset\r
+    //\r
+    AtapiScsiPrivate->IoPort  = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];\r
+\r
+    DeviceControlValue        = 0;\r
+    //\r
+    // set SRST bit to initiate soft reset\r
+    //\r
+    DeviceControlValue |= SRST;\r
+    //\r
+    // disable Interrupt\r
+    //\r
+    DeviceControlValue |= bit (1);\r
+    WritePortB (\r
+      AtapiScsiPrivate->PciIo,\r
+      AtapiScsiPrivate->IoPort->Alt.DeviceControl,\r
+      DeviceControlValue\r
+      );\r
+\r
+    //\r
+    // Wait 10us\r
+    //\r
+    gBS->Stall (10);\r
+\r
+    //\r
+    // Clear SRST bit\r
+    // 0xfb:1111,1011\r
+    //\r
+    DeviceControlValue &= 0xfb;\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, 31000000) != EFI_TIMEOUT) {\r
+      ResetFlag = TRUE;\r
+    }\r
+  }\r
+\r
+  if (ResetFlag) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruResetTarget (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN UINT8                              *Target,\r
+  IN UINT64                             Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Resets a SCSI device that is connected to a SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - The Target ID of the SCSI device to reset. \r
+  Lun                   - The LUN of the SCSI device to reset.\r
+    \r
+Returns:\r
+\r
+  EFI_SUCCESS           - The SCSI device specified by Target and \r
+                          Lun was reset.\r
+  EFI_UNSUPPORTED       - The SCSI channel does not support a target\r
+                          reset operation.\r
+  EFI_INVALID_PARAMETER - Target or Lun are invalid.\r
+  EFI_DEVICE_ERROR      - A device error occurred while attempting \r
+                          to reset the SCSI device specified by Target \r
+                          and Lun.\r
+  EFI_TIMEOUT           - A timeout occurred while attempting to reset \r
+                          the SCSI device specified by Target and Lun.\r
+--*/\r
+{\r
+  UINT8                         Command;\r
+  UINT8                         DeviceSelect;\r
+  UINT8                         TargetId;\r
+  ATAPI_SCSI_PASS_THRU_DEV      *AtapiScsiPrivate;\r
+  \r
+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
+  TargetId = Target[0];\r
+  \r
+  if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Directly return EFI_SUCCESS if want to reset the host controller\r
+  //\r
+  if (TargetId == This->Mode->AdapterId) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  //\r
+  // According to Target ID, reset the Atapi I/O Register mapping\r
+  // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],\r
+  //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]\r
+  //\r
+  if ((TargetId / 2) == 0) {\r
+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];\r
+  } else {\r
+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];\r
+  }\r
+  \r
+  //\r
+  // for ATAPI device, no need to wait DRDY ready after device selecting.\r
+  //\r
+  // bit7 and bit5 are both set to 1 for backward compatibility\r
+  //\r
+  DeviceSelect = (UINT8) (((bit (7) | bit (5)) | (TargetId << 4)));\r
+  WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);\r
+\r
+  Command = ATAPI_SOFT_RESET_CMD;\r
+  WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);\r
+\r
+  //\r
+  // BSY clear is the only status return to the host by the device\r
+  // when reset is complete.\r
+  // slave device needs at most 31s to clear BSY\r
+  //\r
+  if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+  \r
+  //\r
+  // stall 5 seconds to make the device status stable\r
+  //\r
+  gBS->Stall (5000000);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruGetNextTarget (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT8                           **Target\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Used to retrieve the list of legal Target IDs for SCSI devices \r
+  on a SCSI channel.\r
+\r
+Arguments:\r
+  This                  - Protocol instance pointer.\r
+  Target                - On input, a pointer to the Target ID of a SCSI \r
+                          device present on the SCSI channel.  On output, \r
+                          a pointer to the Target ID of the next SCSI device\r
+                           present on a SCSI channel.  An input value of \r
+                           0xFFFFFFFF retrieves the Target ID of the first \r
+                           SCSI device present on a SCSI channel.\r
+  Lun                   - On input, a pointer to the LUN of a SCSI device\r
+                          present on the SCSI channel. On output, a pointer\r
+                          to the LUN of the next SCSI device present on \r
+                          a SCSI channel.\r
+    \r
+Returns:\r
+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device \r
+                          on the SCSI channel was returned in Target and Lun.\r
+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.\r
+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not\r
+                          returned on a previous call to GetNextDevice().\r
+--*/\r
+{\r
+  UINT8                         TargetId;\r
+  UINT8                         ScsiId[TARGET_MAX_BYTES];\r
+  ATAPI_SCSI_PASS_THRU_DEV      *AtapiScsiPrivate;  \r
+  UINT8                         ByteIndex;\r
+\r
+  //\r
+  // Retrieve Device Private Data Structure.\r
+  //\r
+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
+\r
+  //\r
+  // Check whether Target is valid.\r
+  //\r
+  if (*Target == NULL ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  TargetId = (*Target)[0];\r
+  SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);\r
+\r
+  //\r
+  // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.\r
+  //\r
+  if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {\r
+    for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {\r
+      if ((*Target)[ByteIndex] != 0) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    }\r
+  }\r
+\r
+  if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&(TargetId != AtapiScsiPrivate->LatestTargetId)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (TargetId == MAX_TARGET_ID) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0)) {\r
+    SetMem (*Target, TARGET_MAX_BYTES, 0);\r
+  } else {\r
+    (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);\r
+  }\r
+\r
+  //\r
+  // Update the LatestTargetId.\r
+  //\r
+  AtapiScsiPrivate->LatestTargetId  = (*Target)[0];\r
+  AtapiScsiPrivate->LatestLun       = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\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
+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
+  }\r
+\r
+  if (!ValidCdbLength (Packet->CdbLength)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Packet->Cdb == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Checks whether the request command is supported.\r
+  //\r
+  if (!IsCommandValid (Packet)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+IsCommandValid (\r
+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet\r
+  )\r
+/*++\r
+  \r
+Routine Description:\r
+\r
+  Checks the requested SCSI command: \r
+  Is it supported by this driver?\r
+  Is the Data transfer direction reasonable?\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
+  UINT8 Index;\r
+  UINT8 *OpCode;\r
+\r
+  OpCode = (UINT8 *) (Packet->Cdb);\r
+\r
+  for (Index = 0; CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)); Index++) {\r
+\r
+    if (*OpCode == gSupportedATAPICommands[Index].OpCode) {\r
+      //\r
+      // Check whether the requested Command is supported by this driver\r
+      //\r
+      if (Packet->DataDirection == DataIn) {\r
+        //\r
+        // Check whether the requested data direction conforms to\r
+        // what it should be.\r
+        //\r
+        if (gSupportedATAPICommands[Index].Direction == DataOut) {\r
+          return FALSE;\r
+        }\r
+      }\r
+\r
+      if (Packet->DataDirection == DataOut) {\r
+        //\r
+        // Check whether the requested data direction conforms to\r
+        // what it should be.\r
+        //\r
+        if (gSupportedATAPICommands[Index].Direction == DataIn) {\r
+          return FALSE;\r
+        }\r
+      }\r
+\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+EFI_STATUS\r
+SubmitBlockingIoCommand (\r
+  ATAPI_SCSI_PASS_THRU_DEV                  *AtapiScsiPrivate,\r
+  UINT32                                    Target,\r
+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Performs blocking I/O request.\r
+    \r
+Arguments:\r
+\r
+  AtapiScsiPrivate:   Private data structure for the specified channel.\r
+  Target:             The Target ID of the ATAPI device to send the SCSI \r
+                      Request Packet. To ATAPI devices attached on an IDE\r
+                      Channel, Target ID 0 indicates Master device;Target\r
+                      ID 1 indicates Slave device.\r
+  Packet:             The SCSI Request Packet to send to the ATAPI device \r
+                      specified by Target.\r
+  \r
+  Returns:            EFI_STATUS  \r
+  \r
+--*/\r
+{\r
+  UINT8       PacketCommand[12];\r
+  UINT64      TimeoutInMicroSeconds;\r
+  EFI_STATUS  PacketCommandStatus;\r
+\r
+  //\r
+  // Fill ATAPI Command Packet according to CDB\r
+  //\r
+  ZeroMem (&PacketCommand, 12);\r
+  CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);\r
+\r
+  //\r
+  // Timeout is 100ns unit, convert it to 1000ns (1us) unit.\r
+  //\r
+  TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);\r
+\r
+  //\r
+  // Submit ATAPI Command Packet\r
+  //\r
+  PacketCommandStatus = AtapiPacketCommand (\r
+                          AtapiScsiPrivate,\r
+                          Target,\r
+                          PacketCommand,\r
+                          Packet->DataBuffer,\r
+                          &(Packet->TransferLength),\r
+                          (DATA_DIRECTION) Packet->DataDirection,\r
+                          TimeoutInMicroSeconds\r
+                          );\r
+  if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {\r
+    Packet->SenseDataLength = 0;\r
+    return PacketCommandStatus;\r
+  }\r
+\r
+  //\r
+  // Return SenseData if PacketCommandStatus matches\r
+  // the following return codes.\r
+  //\r
+  if ((PacketCommandStatus ==  EFI_BAD_BUFFER_SIZE) ||\r
+      (PacketCommandStatus == EFI_DEVICE_ERROR) ||\r
+      (PacketCommandStatus == EFI_TIMEOUT)) {\r
+\r
+    //\r
+    // avoid submit request sense command continuously.\r
+    //\r
+    if (PacketCommand[0] == OP_REQUEST_SENSE) {\r
+      Packet->SenseDataLength = 0;\r
+      return PacketCommandStatus;\r
+    }\r
+\r
+    RequestSenseCommand (\r
+      AtapiScsiPrivate,\r
+      Target,\r
+      Packet->Timeout,\r
+      Packet->SenseData,\r
+      &Packet->SenseDataLength\r
+      );\r
+  }\r
+\r
+  return PacketCommandStatus;\r
+}\r
+\r
+EFI_STATUS\r
+RequestSenseCommand (\r
+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,\r
+  UINT32                      Target,\r
+  UINT64                      Timeout,\r
+  VOID                        *SenseData,\r
+  UINT8                       *SenseDataLength\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Sumbit request sense command\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate  - The pionter of ATAPI_SCSI_PASS_THRU_DEV\r
+  Target            - The target ID\r
+  Timeout           - The time to complete the command\r
+  SenseData         - The buffer to fill in sense data\r
+  SenseDataLength   - The length of buffer\r
+\r
+Returns:\r
+\r
+  EFI_STATUS\r
+  \r
+--*/\r
+{\r
+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  Packet;\r
+  UINT8                                   Cdb[12];\r
+  EFI_STATUS                              Status;\r
+\r
+  ZeroMem (&Packet, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));\r
+  ZeroMem (Cdb, 12);\r
+\r
+  Cdb[0]                = OP_REQUEST_SENSE;\r
+  Cdb[4]                = (UINT8) (*SenseDataLength);\r
+\r
+  Packet.Timeout        = Timeout;\r
+  Packet.DataBuffer     = SenseData;\r
+  Packet.SenseData      = NULL;\r
+  Packet.Cdb            = Cdb;\r
+  Packet.TransferLength = *SenseDataLength;\r
+  Packet.CdbLength      = 12;\r
+  Packet.DataDirection  = DataIn;\r
+\r
+  Status                = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &Packet);\r
+  *SenseDataLength      = (UINT8) (Packet.TransferLength);\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+CheckExtSCSIRequestPacket (\r
+  EFI_EXT_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_EXT_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
+  }\r
+\r
+  if (!ValidCdbLength (Packet->CdbLength)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Packet->Cdb == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Checks whether the request command is supported.\r
+  //\r
+  if (!IsExtCommandValid (Packet)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+BOOLEAN\r
+IsExtCommandValid (\r
+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet\r
+  )\r
+/*++\r
+  \r
+Routine Description:\r
+\r
+  Checks the requested SCSI command: \r
+  Is it supported by this driver?\r
+  Is the Data transfer direction reasonable?\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
+  UINT8 Index;\r
+  UINT8 *OpCode;\r
+\r
+  OpCode = (UINT8 *) (Packet->Cdb);\r
+\r
+  for (Index = 0; CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)); Index++) {\r
+\r
+    if (*OpCode == gSupportedATAPICommands[Index].OpCode) {\r
+      //\r
+      // Check whether the requested Command is supported by this driver\r
+      //\r
+      if (Packet->DataDirection == DataIn) {\r
+        //\r
+        // Check whether the requested data direction conforms to\r
+        // what it should be.\r
+        //\r
+        if (gSupportedATAPICommands[Index].Direction == DataOut) {\r
+          return FALSE;\r
+        }\r
+      }\r
+\r
+      if (Packet->DataDirection == DataOut) {\r
+        //\r
+        // Check whether the requested data direction conforms to\r
+        // what it should be.\r
+        //\r
+        if (gSupportedATAPICommands[Index].Direction == DataIn) {\r
+          return FALSE;\r
+        }\r
+      }\r
+\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+EFI_STATUS\r
+SubmitExtBlockingIoCommand (\r
+  ATAPI_SCSI_PASS_THRU_DEV                      *AtapiScsiPrivate,\r
+  UINT8                                         Target,\r
+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Performs blocking I/O request.\r
+    \r
+Arguments:\r
+\r
+  AtapiScsiPrivate:   Private data structure for the specified channel.\r
+  Target:             The Target ID of the ATAPI device to send the SCSI \r
+                      Request Packet. To ATAPI devices attached on an IDE\r
+                      Channel, Target ID 0 indicates Master device;Target\r
+                      ID 1 indicates Slave device.\r
+  Packet:             The SCSI Request Packet to send to the ATAPI device \r
+                      specified by Target.\r
+  \r
+  Returns:            EFI_STATUS  \r
+  \r
+--*/\r
+{\r
+  UINT8       PacketCommand[12];\r
+  UINT64      TimeoutInMicroSeconds;\r
+  EFI_STATUS  PacketCommandStatus;\r
+\r
+  //\r
+  // Fill ATAPI Command Packet according to CDB\r
+  //\r
+  ZeroMem (&PacketCommand, 12);\r
+  CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);\r
+\r
+  //\r
+  // Timeout is 100ns unit, convert it to 1000ns (1us) unit.\r
+  //\r
+  TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);\r
+\r
+  //\r
+  // Submit ATAPI Command Packet\r
+  //\r
+  if (Packet->DataDirection == DataIn) {\r
+    PacketCommandStatus = AtapiPacketCommand (\r
+                              AtapiScsiPrivate,\r
+                              Target,\r
+                              PacketCommand,\r
+                              Packet->InDataBuffer,\r
+                              &(Packet->InTransferLength),\r
+                              DataIn,\r
+                              TimeoutInMicroSeconds\r
+                              );\r
+  } else {\r
+\r
+    PacketCommandStatus = AtapiPacketCommand (\r
+                            AtapiScsiPrivate,\r
+                            Target,\r
+                            PacketCommand,\r
+                            Packet->OutDataBuffer,\r
+                            &(Packet->OutTransferLength),\r
+                            DataOut,\r
+                            TimeoutInMicroSeconds\r
+                            );\r
+  }\r
+  \r
+  if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {\r
+    Packet->SenseDataLength = 0;\r
+    return PacketCommandStatus;\r
+  }\r
+  \r
+  //\r
+  // Return SenseData if PacketCommandStatus matches\r
+  // the following return codes.\r
+  //\r
+  if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||\r
+      (PacketCommandStatus == EFI_DEVICE_ERROR) ||\r
+      (PacketCommandStatus == EFI_TIMEOUT)) {\r
+\r
+    //\r
+    // avoid submit request sense command continuously.\r
+    //\r
+    if (PacketCommand[0] == OP_REQUEST_SENSE) {\r
+      Packet->SenseDataLength = 0;\r
+      return PacketCommandStatus;\r
+    }\r
+\r
+    RequestSenseCommand (\r
+      AtapiScsiPrivate,\r
+      Target,\r
+      Packet->Timeout,\r
+      Packet->SenseData,\r
+      &Packet->SenseDataLength\r
+      );\r
+  }\r
+\r
+  return PacketCommandStatus;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+AtapiPacketCommand (\r
+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,\r
+  UINT32                      Target,\r
+  UINT8                       *PacketCommand,\r
+  VOID                        *Buffer,\r
+  UINT32                      *ByteCount,\r
+  DATA_DIRECTION              Direction,\r
+  UINT64                      TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Submits ATAPI command packet to the specified ATAPI device.\r
+    \r
+Arguments:\r
+\r
+  AtapiScsiPrivate:   Private data structure for the specified channel.\r
+  Target:             The Target ID of the ATAPI device to send the SCSI \r
+                      Request Packet. To ATAPI devices attached on an IDE\r
+                      Channel, Target ID 0 indicates Master device;Target\r
+                      ID 1 indicates Slave device.\r
+  PacketCommand:      Points to the ATAPI command packet.\r
+  Buffer:             Points to the transferred data.\r
+  ByteCount:          When input,indicates the buffer size; when output,\r
+                      indicates the actually transferred data size.\r
+  Direction:          Indicates the data transfer direction. \r
+  TimeoutInMicroSeconds:\r
+                      The timeout, in micro second units, to use for the \r
+                      execution of this ATAPI command.\r
+                      A TimeoutInMicroSeconds value of 0 means that \r
+                      this function will wait indefinitely for the ATAPI \r
+                      command to execute.\r
+                      If TimeoutInMicroSeconds is greater than zero, then \r
+                      this function will return EFI_TIMEOUT if the time \r
+                      required to execute the ATAPI command is greater \r
+                      than TimeoutInMicroSeconds.\r
+  \r
+Returns:\r
+\r
+  EFI_STATUS\r
+  \r
+--*/\r
+{\r
+\r
+  UINT16      *CommandIndex;\r
+  UINT8       Count;\r
+  EFI_STATUS  Status;\r
+\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
+  //\r
+  WritePortB (\r
+    AtapiScsiPrivate->PciIo,\r
+    AtapiScsiPrivate->IoPort->Head,\r
+    (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
+  WritePortB (\r
+    AtapiScsiPrivate->PciIo,\r
+    AtapiScsiPrivate->IoPort->Reg1.Feature,\r
+    0x00\r
+    );\r
+\r
+  //\r
+  // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device\r
+  // determine how much data should be transfered.\r
+  //\r
+  WritePortB (\r
+    AtapiScsiPrivate->PciIo,\r
+    AtapiScsiPrivate->IoPort->CylinderLsb,\r
+    (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)\r
+    );\r
+  WritePortB (\r
+    AtapiScsiPrivate->PciIo,\r
+    AtapiScsiPrivate->IoPort->CylinderMsb,\r
+    (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)\r
+    );\r
+\r
+  //\r
+  //  DEFAULT_CTL:0x0a (0000,1010)\r
+  //  Disable interrupt\r
+  //\r
+  WritePortB (\r
+    AtapiScsiPrivate->PciIo,\r
+    AtapiScsiPrivate->IoPort->Alt.DeviceControl,\r
+    DEFAULT_CTL\r
+    );\r
+\r
+  //\r
+  // Send Packet command to inform device\r
+  // that the following data bytes are command packet.\r
+  //\r
+  WritePortB (\r
+    AtapiScsiPrivate->PciIo,\r
+    AtapiScsiPrivate->IoPort->Reg.Command,\r
+    PACKET_CMD\r
+    );\r
+\r
+  //\r
+  // Before data transfer, BSY should be 0 and DRQ should be 1.\r
+  // if they are not in specified time frame,\r
+  // retrieve Sense Key from Error Register before return.\r
+  //\r
+  Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Status == EFI_ABORTED) {\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    *ByteCount = 0;\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Send out command packet\r
+  //\r
+  CommandIndex = (UINT16 *) PacketCommand;\r
+  for (Count = 0; Count < 6; Count++, CommandIndex++) {\r
+    WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *CommandIndex);\r
+  }\r
+\r
+  //\r
+  // call AtapiPassThruPioReadWriteData() function to get\r
+  // requested transfer data form device.\r
+  //\r
+  return AtapiPassThruPioReadWriteData (\r
+          AtapiScsiPrivate,\r
+          Buffer,\r
+          ByteCount,\r
+          Direction,\r
+          TimeoutInMicroSeconds\r
+          );\r
+}\r
+\r
+EFI_STATUS\r
+AtapiPassThruPioReadWriteData (\r
+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate,\r
+  UINT16                    *Buffer,\r
+  UINT32                    *ByteCount,\r
+  DATA_DIRECTION            Direction,\r
+  UINT64                    TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Performs data transfer between ATAPI device and host after the\r
+  ATAPI command packet is sent.\r
+    \r
+Arguments:\r
+\r
+  AtapiScsiPrivate:   Private data structure for the specified channel.    \r
+  Buffer:             Points to the transferred data.\r
+  ByteCount:          When input,indicates the buffer size; when output,\r
+                      indicates the actually transferred data size.\r
+  Direction:          Indicates the data transfer direction. \r
+  TimeoutInMicroSeconds:\r
+                      The timeout, in micro second units, to use for the \r
+                      execution of this ATAPI command.\r
+                      A TimeoutInMicroSeconds value of 0 means that \r
+                      this function will wait indefinitely for the ATAPI \r
+                      command to execute.\r
+                      If TimeoutInMicroSeconds is greater than zero, then \r
+                      this function will return EFI_TIMEOUT if the time \r
+                      required to execute the ATAPI command is greater \r
+                      than TimeoutInMicroSeconds.\r
+ Returns:\r
+\r
+  EFI_STATUS\r
+  \r
+--*/\r
+{\r
+  UINT32      Index;\r
+  UINT32      RequiredWordCount;\r
+  UINT32      ActualWordCount;\r
+  UINT32      WordCount;\r
+  EFI_STATUS  Status;\r
+  UINT16      *ptrBuffer;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Non Data transfer request is also supported.\r
+  //\r
+  if (*ByteCount == 0 || Buffer == NULL) {\r
+    *ByteCount = 0;\r
+    if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds))) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  ptrBuffer         = Buffer;\r
+  RequiredWordCount = *ByteCount / 2;\r
+\r
+  //\r
+  // ActuralWordCount means the word count of data really transfered.\r
+  //\r
+  ActualWordCount = 0;\r
+\r
+  while (ActualWordCount < RequiredWordCount) {\r
+    //\r
+    // before each data transfer stream, the host should poll DRQ bit ready,\r
+    // which indicates device's ready for data transfer .\r
+    //\r
+    Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
+    if (EFI_ERROR (Status)) {\r
+      *ByteCount = ActualWordCount * 2;\r
+\r
+      AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);\r
+\r
+      if (ActualWordCount == 0) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      //\r
+      // ActualWordCount > 0\r
+      //\r
+      if (ActualWordCount < RequiredWordCount) {\r
+        return EFI_BAD_BUFFER_SIZE;\r
+      }\r
+    }\r
+    //\r
+    // get current data transfer size from Cylinder Registers.\r
+    //\r
+    WordCount = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderMsb) << 8;\r
+    WordCount = WordCount | ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderLsb);\r
+    WordCount = WordCount & 0xffff;\r
+    WordCount /= 2;\r
+\r
+    //\r
+    // perform a series data In/Out.\r
+    //\r
+    for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {\r
+\r
+      if (Direction == DataIn) {\r
+\r
+        *ptrBuffer = ReadPortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data);\r
+      } else {\r
+\r
+        WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *ptrBuffer);\r
+      }\r
+\r
+      ptrBuffer++;\r
+\r
+    }\r
+  }\r
+  //\r
+  // After data transfer is completed, normally, DRQ bit should clear.\r
+  //\r
+  StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
+\r
+  //\r
+  // read status register to check whether error happens.\r
+  //\r
+  Status      = AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);\r
+\r
+  *ByteCount  = ActualWordCount * 2;\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+UINT8\r
+ReadPortB (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Read one byte from a specified I/O port.\r
+\r
+Arguments:\r
+\r
+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL\r
+  Port       - IO port\r
+  \r
+Returns:\r
+\r
+  A byte read out\r
+\r
+--*/\r
+{\r
+  UINT8 Data;\r
+\r
+  Data = 0;\r
+  PciIo->Io.Read (\r
+              PciIo,\r
+              EfiPciIoWidthUint8,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              1,\r
+              &Data\r
+              );\r
+  return Data;\r
+}\r
+\r
+\r
+UINT16\r
+ReadPortW (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Read one word from a specified I/O port.\r
+\r
+Arguments:\r
+\r
+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL\r
+  Port       - IO port\r
+  \r
+Returns:\r
+\r
+  A word read out\r
+--*/\r
+{\r
+  UINT16  Data;\r
+\r
+  Data = 0;\r
+  PciIo->Io.Read (\r
+              PciIo,\r
+              EfiPciIoWidthUint16,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              1,\r
+              &Data\r
+              );\r
+  return Data;\r
+}\r
+\r
+\r
+VOID\r
+WritePortB (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINT8                 Data\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Write one byte to a specified I/O port.\r
+\r
+Arguments:\r
+\r
+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL\r
+  Port       - IO port\r
+  Data       - The data to write\r
+  \r
+Returns:\r
+\r
+   NONE\r
+\r
+--*/\r
+{\r
+  PciIo->Io.Write (\r
+              PciIo,\r
+              EfiPciIoWidthUint8,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              1,\r
+              &Data\r
+              );\r
+}\r
+\r
+\r
+VOID\r
+WritePortW (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINT16                Data\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Write one word to a specified I/O port.\r
+\r
+Arguments:\r
+\r
+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL\r
+  Port       - IO port\r
+  Data       - The data to write\r
+  \r
+Returns:\r
+\r
+   NONE\r
+   \r
+--*/\r
+{\r
+  PciIo->Io.Write (\r
+              PciIo,\r
+              EfiPciIoWidthUint16,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              1,\r
+              &Data\r
+              );\r
+}\r
+\r
+EFI_STATUS\r
+StatusDRQClear (\r
+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,\r
+  UINT64                          TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+  \r
+--*/\r
+{\r
+  UINT64  Delay;\r
+  UINT8   StatusRegister;\r
+  UINT8   ErrRegister;\r
+\r
+  if (TimeoutInMicroSeconds == 0) {\r
+    Delay = 2;\r
+  } else {\r
+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
+  }\r
+\r
+  do {\r
+\r
+    StatusRegister = ReadPortB (\r
+                      AtapiScsiPrivate->PciIo,\r
+                      AtapiScsiPrivate->IoPort->Reg.Status\r
+                      );\r
+\r
+    //\r
+    // wait for BSY == 0 and DRQ == 0\r
+    //\r
+    if ((StatusRegister & (DRQ | BSY)) == 0) {\r
+      break;\r
+    }\r
+    //\r
+    // check whether the command is aborted by the device\r
+    //\r
+    if ((StatusRegister & (BSY | ERR)) == ERR) {\r
+\r
+      ErrRegister = ReadPortB (\r
+                      AtapiScsiPrivate->PciIo,\r
+                      AtapiScsiPrivate->IoPort->Reg1.Error\r
+                      );\r
+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
+\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+    //\r
+    //  Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+\r
+    //\r
+    // Loop infinitely if not meeting expected condition\r
+    //\r
+    if (TimeoutInMicroSeconds == 0) {\r
+      Delay = 2;\r
+    }\r
+\r
+    Delay--;\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AltStatusDRQClear (\r
+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,\r
+  UINT64                          TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Check whether DRQ is clear in the Alternate Status Register. \r
+  (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should \r
+  wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is \r
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  UINT64  Delay;\r
+  UINT8   AltStatusRegister;\r
+  UINT8   ErrRegister;\r
+\r
+  if (TimeoutInMicroSeconds == 0) {\r
+    Delay = 2;\r
+  } else {\r
+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
+  }\r
+\r
+  do {\r
+\r
+    AltStatusRegister = ReadPortB (\r
+                          AtapiScsiPrivate->PciIo,\r
+                          AtapiScsiPrivate->IoPort->Alt.AltStatus\r
+                          );\r
+\r
+    //\r
+    // wait for BSY == 0 and DRQ == 0\r
+    //\r
+    if ((AltStatusRegister & (DRQ | BSY)) == 0) {\r
+      break;\r
+    }\r
+\r
+    if ((AltStatusRegister & (BSY | ERR)) == ERR) {\r
+\r
+      ErrRegister = ReadPortB (\r
+                      AtapiScsiPrivate->PciIo,\r
+                      AtapiScsiPrivate->IoPort->Reg1.Error\r
+                      );\r
+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
+\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+    //\r
+    //  Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+\r
+    //\r
+    // Loop infinitely if not meeting expected condition\r
+    //\r
+    if (TimeoutInMicroSeconds == 0) {\r
+      Delay = 2;\r
+    }\r
+\r
+    Delay--;\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+StatusDRQReady (\r
+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,\r
+  UINT64                          TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  UINT64  Delay;\r
+  UINT8   StatusRegister;\r
+  UINT8   ErrRegister;\r
+\r
+  if (TimeoutInMicroSeconds == 0) {\r
+    Delay = 2;\r
+  } else {\r
+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
+  }\r
+\r
+  do {\r
+    //\r
+    //  read Status Register will clear interrupt\r
+    //\r
+    StatusRegister = ReadPortB (\r
+                      AtapiScsiPrivate->PciIo,\r
+                      AtapiScsiPrivate->IoPort->Reg.Status\r
+                      );\r
+\r
+    //\r
+    //  BSY==0,DRQ==1\r
+    //\r
+    if ((StatusRegister & (BSY | DRQ)) == DRQ) {\r
+      break;\r
+    }\r
+\r
+    if ((StatusRegister & (BSY | ERR)) == ERR) {\r
+\r
+      ErrRegister = ReadPortB (\r
+                      AtapiScsiPrivate->PciIo,\r
+                      AtapiScsiPrivate->IoPort->Reg1.Error\r
+                      );\r
+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+\r
+    //\r
+    // Loop infinitely if not meeting expected condition\r
+    //\r
+    if (TimeoutInMicroSeconds == 0) {\r
+      Delay = 2;\r
+    }\r
+\r
+    Delay--;\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AltStatusDRQReady (\r
+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,\r
+  UINT64                          TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  UINT64  Delay;\r
+  UINT8   AltStatusRegister;\r
+  UINT8   ErrRegister;\r
+\r
+  if (TimeoutInMicroSeconds == 0) {\r
+    Delay = 2;\r
+  } else {\r
+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
+  }\r
+\r
+  do {\r
+    //\r
+    //  read Status Register will clear interrupt\r
+    //\r
+    AltStatusRegister = ReadPortB (\r
+                          AtapiScsiPrivate->PciIo,\r
+                          AtapiScsiPrivate->IoPort->Alt.AltStatus\r
+                          );\r
+    //\r
+    //  BSY==0,DRQ==1\r
+    //\r
+    if ((AltStatusRegister & (BSY | DRQ)) == DRQ) {\r
+      break;\r
+    }\r
+\r
+    if ((AltStatusRegister & (BSY | ERR)) == ERR) {\r
+\r
+      ErrRegister = ReadPortB (\r
+                      AtapiScsiPrivate->PciIo,\r
+                      AtapiScsiPrivate->IoPort->Reg1.Error\r
+                      );\r
+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+\r
+    //\r
+    // Loop infinitely if not meeting expected condition\r
+    //\r
+    if (TimeoutInMicroSeconds == 0) {\r
+      Delay = 2;\r
+    }\r
+\r
+    Delay--;\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+StatusWaitForBSYClear (\r
+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,\r
+  UINT64                      TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  UINT64  Delay;\r
+  UINT8   StatusRegister;\r
+\r
+  if (TimeoutInMicroSeconds == 0) {\r
+    Delay = 2;\r
+  } else {\r
+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
+  }\r
+\r
+  do {\r
+\r
+    StatusRegister = ReadPortB (\r
+                      AtapiScsiPrivate->PciIo,\r
+                      AtapiScsiPrivate->IoPort->Reg.Status\r
+                      );\r
+    if ((StatusRegister & BSY) == 0x00) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+\r
+    //\r
+    // Loop infinitely if not meeting expected condition\r
+    //\r
+    if (TimeoutInMicroSeconds == 0) {\r
+      Delay = 2;\r
+    }\r
+\r
+    Delay--;\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AltStatusWaitForBSYClear (\r
+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,\r
+  UINT64                      TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  UINT64  Delay;\r
+  UINT8   AltStatusRegister;\r
+\r
+  if (TimeoutInMicroSeconds == 0) {\r
+    Delay = 2;\r
+  } else {\r
+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
+  }\r
+\r
+  do {\r
+\r
+    AltStatusRegister = ReadPortB (\r
+                          AtapiScsiPrivate->PciIo,\r
+                          AtapiScsiPrivate->IoPort->Alt.AltStatus\r
+                          );\r
+    if ((AltStatusRegister & BSY) == 0x00) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+    //\r
+    // Loop infinitely if not meeting expected condition\r
+    //\r
+    if (TimeoutInMicroSeconds == 0) {\r
+      Delay = 2;\r
+    }\r
+\r
+    Delay--;\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+StatusDRDYReady (\r
+  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,\r
+  UINT64                       TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  UINT64  Delay;\r
+  UINT8   StatusRegister;\r
+  UINT8   ErrRegister;\r
+\r
+  if (TimeoutInMicroSeconds == 0) {\r
+    Delay = 2;\r
+  } else {\r
+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
+  }\r
+\r
+  do {\r
+    StatusRegister = ReadPortB (\r
+                      AtapiScsiPrivate->PciIo,\r
+                      AtapiScsiPrivate->IoPort->Reg.Status\r
+                      );\r
+    //\r
+    //  BSY == 0 , DRDY == 1\r
+    //\r
+    if ((StatusRegister & (DRDY | BSY)) == DRDY) {\r
+      break;\r
+    }\r
+\r
+    if ((StatusRegister & (BSY | ERR)) == ERR) {\r
+\r
+      ErrRegister = ReadPortB (\r
+                      AtapiScsiPrivate->PciIo,\r
+                      AtapiScsiPrivate->IoPort->Reg1.Error\r
+                      );\r
+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+    //\r
+    // Loop infinitely if not meeting expected condition\r
+    //\r
+    if (TimeoutInMicroSeconds == 0) {\r
+      Delay = 2;\r
+    }\r
+\r
+    Delay--;\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AltStatusDRDYReady (\r
+  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,\r
+  UINT64                       TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  UINT64  Delay;\r
+  UINT8   AltStatusRegister;\r
+  UINT8   ErrRegister;\r
+\r
+  if (TimeoutInMicroSeconds == 0) {\r
+    Delay = 2;\r
+  } else {\r
+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
+  }\r
+\r
+  do {\r
+    AltStatusRegister = ReadPortB (\r
+                          AtapiScsiPrivate->PciIo,\r
+                          AtapiScsiPrivate->IoPort->Alt.AltStatus\r
+                          );\r
+    //\r
+    //  BSY == 0 , DRDY == 1\r
+    //\r
+    if ((AltStatusRegister & (DRDY | BSY)) == DRDY) {\r
+      break;\r
+    }\r
+\r
+    if ((AltStatusRegister & (BSY | ERR)) == ERR) {\r
+\r
+      ErrRegister = ReadPortB (\r
+                      AtapiScsiPrivate->PciIo,\r
+                      AtapiScsiPrivate->IoPort->Reg1.Error\r
+                      );\r
+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Stall for 30 us\r
+    //\r
+    gBS->Stall (30);\r
+    //\r
+    // Loop infinitely if not meeting expected condition\r
+    //\r
+    if (TimeoutInMicroSeconds == 0) {\r
+      Delay = 2;\r
+    }\r
+\r
+    Delay--;\r
+  } while (Delay);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AtapiPassThruCheckErrorStatus (\r
+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate\r
+  )\r
+/*++  \r
+\r
+Routine Description:\r
+\r
+  Check Error Register for Error Information. \r
+  \r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  UINT8 StatusRegister;\r
+  UINT8 ErrorRegister;\r
+\r
+  StatusRegister = ReadPortB (\r
+                    AtapiScsiPrivate->PciIo,\r
+                    AtapiScsiPrivate->IoPort->Reg.Status\r
+                    );\r
+\r
+  DEBUG_CODE_BEGIN ();\r
+\r
+    if (StatusRegister & DWF) {\r
+      DEBUG (\r
+        (EFI_D_BLKIO,\r
+        "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",\r
+        StatusRegister)\r
+        );\r
+    }\r
+\r
+    if (StatusRegister & CORR) {\r
+      DEBUG (\r
+        (EFI_D_BLKIO,\r
+        "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",\r
+        StatusRegister)\r
+        );\r
+    }\r
+\r
+    if (StatusRegister & ERR) {\r
+      ErrorRegister = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg1.Error);\r
+\r
+\r
+      if (ErrorRegister & BBK_ERR) {\r
+        DEBUG (\r
+          (EFI_D_BLKIO,\r
+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",\r
+          ErrorRegister)\r
+          );\r
+      }\r
+\r
+      if (ErrorRegister & UNC_ERR) {\r
+        DEBUG (\r
+          (EFI_D_BLKIO,\r
+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",\r
+          ErrorRegister)\r
+          );\r
+      }\r
+\r
+      if (ErrorRegister & MC_ERR) {\r
+        DEBUG (\r
+          (EFI_D_BLKIO,\r
+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",\r
+          ErrorRegister)\r
+          );\r
+      }\r
+\r
+      if (ErrorRegister & ABRT_ERR) {\r
+        DEBUG (\r
+          (EFI_D_BLKIO,\r
+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",\r
+          ErrorRegister)\r
+          );\r
+      }\r
+\r
+      if (ErrorRegister & TK0NF_ERR) {\r
+        DEBUG (\r
+          (EFI_D_BLKIO,\r
+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",\r
+          ErrorRegister)\r
+          );\r
+      }\r
+\r
+      if (ErrorRegister & AMNF_ERR) {\r
+        DEBUG (\r
+          (EFI_D_BLKIO,\r
+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",\r
+          ErrorRegister)\r
+          );\r
+       }\r
+    }\r
+\r
+  DEBUG_CODE_END ();\r
+\r
+  if ((StatusRegister & (ERR | DWF | CORR)) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+\r
+  return EFI_DEVICE_ERROR;\r
+}\r
+\r
+\r
+/**\r
+  Installs Scsi Pass Thru and/or Ext Scsi Pass Thru \r
+  protocols based on feature flags. \r
+\r
+  @param Controller         The controller handle to \r
+                            install these protocols on.\r
+  @param AtapiScsiPrivate   A pointer to the protocol private\r
+                            data structure.\r
+\r
+  @retval EFI_SUCCESS       The installation succeeds. \r
+  @retval other             The installation fails. \r
+   \r
+**/\r
+EFI_STATUS\r
+InstallScsiPassThruProtocols (\r
+  IN EFI_HANDLE                     *ControllerHandle,\r
+  IN ATAPI_SCSI_PASS_THRU_DEV       *AtapiScsiPrivate\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_SCSI_PASS_THRU_PROTOCOL       *ScsiPassThru;\r
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *ExtScsiPassThru;\r
+\r
+  ScsiPassThru = &AtapiScsiPrivate->ScsiPassThru;\r
+  ExtScsiPassThru = &AtapiScsiPrivate->ExtScsiPassThru;\r
+\r
+  if (FeaturePcdGet (PcdSupportScsiPassThru)) {\r
+    ScsiPassThru = CopyMem (ScsiPassThru, &gScsiPassThruProtocolTemplate, sizeof (*ScsiPassThru));\r
+    if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {\r
+      ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));\r
+      Status = gBS->InstallMultipleProtocolInterfaces (\r
+                      ControllerHandle,\r
+                      &gEfiScsiPassThruProtocolGuid,\r
+                      ScsiPassThru,\r
+                      &gEfiExtScsiPassThruProtocolGuid,\r
+                      ExtScsiPassThru,\r
+                      NULL\r
+                      );\r
+    } else {\r
+      Status = gBS->InstallMultipleProtocolInterfaces (\r
+                      ControllerHandle,\r
+                      &gEfiScsiPassThruProtocolGuid,\r
+                      ScsiPassThru,\r
+                      NULL\r
+                      );\r
+    }\r
+  } else {\r
+    if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {\r
+      ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));\r
+      Status = gBS->InstallMultipleProtocolInterfaces (\r
+                      ControllerHandle,\r
+                      &gEfiExtScsiPassThruProtocolGuid,\r
+                      ExtScsiPassThru,\r
+                      NULL\r
+                      );\r
+    } else {\r
+      //\r
+      // This driver must support either ScsiPassThru or\r
+      // ExtScsiPassThru protocols\r
+      // \r
+      ASSERT (FALSE);\r
+      Status = EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+\r
+  return Status;\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] 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
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeAtapiPassThru(\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // Install driver model protocol(s).\r
+  //\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gAtapiScsiPassThruDriverBinding,\r
+             ImageHandle,\r
+             &gAtapiScsiPassThruComponentName,\r
+             &gAtapiScsiPassThruComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
diff --git a/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h b/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h
new file mode 100644 (file)
index 0000000..2187580
--- /dev/null
@@ -0,0 +1,1625 @@
+/** @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
+\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:  AtapiPassThru.h\r
+\r
+**/\r
+\r
+#ifndef _APT_H\r
+#define _APT_H\r
+\r
+\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Protocol/ScsiPassThru.h>\r
+#include <Protocol/ScsiPassThruExt.h>\r
+#include <Protocol/PciIo.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <IndustryStandard/pci22.h>\r
+\r
+///\r
+/// bit definition\r
+///\r
+#define bit(a)        (1 << (a))\r
+\r
+#define MAX_TARGET_ID 4\r
+\r
+//\r
+// IDE Registers\r
+//\r
+typedef union {\r
+  UINT16  Command;        /* when write */\r
+  UINT16  Status;         /* when read */\r
+} IDE_CMD_OR_STATUS;\r
+\r
+typedef union {\r
+  UINT16  Error;          /* when read */\r
+  UINT16  Feature;        /* when write */\r
+} IDE_ERROR_OR_FEATURE;\r
+\r
+typedef union {\r
+  UINT16  AltStatus;      /* when read */\r
+  UINT16  DeviceControl;  /* when write */\r
+} IDE_AltStatus_OR_DeviceControl;\r
+\r
+\r
+typedef enum {\r
+  IdePrimary    = 0,\r
+  IdeSecondary  = 1,\r
+  IdeMaxChannel = 2\r
+} EFI_IDE_CHANNEL;\r
+\r
+///\r
+\r
+\r
+//\r
+// Bit definitions in Programming Interface byte of the Class Code field\r
+// in PCI IDE controller's Configuration Space\r
+//\r
+#define IDE_PRIMARY_OPERATING_MODE            BIT0\r
+#define IDE_PRIMARY_PROGRAMMABLE_INDICATOR    BIT1\r
+#define IDE_SECONDARY_OPERATING_MODE          BIT2\r
+#define IDE_SECONDARY_PROGRAMMABLE_INDICATOR  BIT3\r
+\r
+\r
+#define ATAPI_MAX_CHANNEL 2\r
+\r
+///\r
+/// IDE registers set\r
+///\r
+typedef struct {\r
+  UINT16                          Data;\r
+  IDE_ERROR_OR_FEATURE            Reg1;\r
+  UINT16                          SectorCount;\r
+  UINT16                          SectorNumber;\r
+  UINT16                          CylinderLsb;\r
+  UINT16                          CylinderMsb;\r
+  UINT16                          Head;\r
+  IDE_CMD_OR_STATUS               Reg;\r
+  IDE_AltStatus_OR_DeviceControl  Alt;\r
+  UINT16                          DriveAddress;\r
+} IDE_BASE_REGISTERS;\r
+\r
+#define ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE  EFI_SIGNATURE_32 ('a', 's', 'p', 't')\r
+\r
+typedef struct {\r
+  UINTN                            Signature;\r
+  EFI_HANDLE                       Handle;\r
+  EFI_SCSI_PASS_THRU_PROTOCOL      ScsiPassThru;\r
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL  ExtScsiPassThru;\r
+  EFI_PCI_IO_PROTOCOL              *PciIo;\r
+  UINT64                           OriginalPciAttributes;\r
+  //\r
+  // Local Data goes here\r
+  //\r
+  IDE_BASE_REGISTERS               *IoPort;\r
+  IDE_BASE_REGISTERS               AtapiIoPortRegisters[2];\r
+  UINT32                           LatestTargetId;\r
+  UINT64                           LatestLun;\r
+} ATAPI_SCSI_PASS_THRU_DEV;\r
+\r
+//\r
+// IDE registers' base addresses\r
+//\r
+typedef struct {\r
+  UINT16  CommandBlockBaseAddr;\r
+  UINT16  ControlBlockBaseAddr;\r
+} IDE_REGISTERS_BASE_ADDR;\r
+\r
+#define ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS(a) \\r
+  CR (a, \\r
+      ATAPI_SCSI_PASS_THRU_DEV, \\r
+      ScsiPassThru, \\r
+      ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE \\r
+      )\r
+\r
+#define ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS(a) \\r
+  CR (a, \\r
+      ATAPI_SCSI_PASS_THRU_DEV, \\r
+      ExtScsiPassThru, \\r
+      ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE \\r
+      )\r
+\r
+//\r
+// Global Variables\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL   gAtapiScsiPassThruDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL   gAtapiScsiPassThruComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL  gAtapiScsiPassThruComponentName2;\r
+\r
+//\r
+// ATAPI Command op code\r
+//\r
+#define OP_INQUIRY                      0x12\r
+#define OP_LOAD_UNLOAD_CD               0xa6\r
+#define OP_MECHANISM_STATUS             0xbd\r
+#define OP_MODE_SELECT_10               0x55\r
+#define OP_MODE_SENSE_10                0x5a\r
+#define OP_PAUSE_RESUME                 0x4b\r
+#define OP_PLAY_AUDIO_10                0x45\r
+#define OP_PLAY_AUDIO_MSF               0x47\r
+#define OP_PLAY_CD                      0xbc\r
+#define OP_PLAY_CD_MSF                  0xb4\r
+#define OP_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e\r
+#define OP_READ_10                      0x28\r
+#define OP_READ_12                      0xa8\r
+#define OP_READ_CAPACITY                0x25\r
+#define OP_READ_CD                      0xbe\r
+#define OP_READ_CD_MSF                  0xb9\r
+#define OP_READ_HEADER                  0x44\r
+#define OP_READ_SUB_CHANNEL             0x42\r
+#define OP_READ_TOC                     0x43\r
+#define OP_REQUEST_SENSE                0x03\r
+#define OP_SCAN                         0xba\r
+#define OP_SEEK_10                      0x2b\r
+#define OP_SET_CD_SPEED                 0xbb\r
+#define OP_STOPPLAY_SCAN                0x4e\r
+#define OP_START_STOP_UNIT              0x1b\r
+#define OP_TEST_UNIT_READY              0x00\r
+\r
+#define OP_FORMAT_UNIT                  0x04\r
+#define OP_READ_FORMAT_CAPACITIES       0x23\r
+#define OP_VERIFY                       0x2f\r
+#define OP_WRITE_10                     0x2a\r
+#define OP_WRITE_12                     0xaa\r
+#define OP_WRITE_AND_VERIFY             0x2e\r
+\r
+//\r
+// ATA Command\r
+//\r
+#define ATAPI_SOFT_RESET_CMD  0x08\r
+\r
+typedef enum {\r
+  DataIn  = 0,\r
+  DataOut = 1,\r
+  DataBi  = 2,\r
+  NoData  = 3,\r
+  End     = 0xff\r
+} DATA_DIRECTION;\r
+\r
+typedef struct {\r
+  UINT8           OpCode;\r
+  DATA_DIRECTION  Direction;\r
+} SCSI_COMMAND_SET;\r
+\r
+#define MAX_CHANNEL         2\r
+\r
+#define ValidCdbLength(Len) ((Len) == 6 || (Len) == 10 || (Len) == 12) ? 1 : 0\r
+\r
+//\r
+// IDE registers bit definitions\r
+//\r
+// ATA Err Reg bitmap\r
+//\r
+#define BBK_ERR   bit (7) ///< Bad block detected\r
+#define UNC_ERR   bit (6) ///< Uncorrectable Data\r
+#define MC_ERR    bit (5) ///< Media Change\r
+#define IDNF_ERR  bit (4) ///< ID Not Found\r
+#define MCR_ERR   bit (3) ///< Media Change Requested\r
+#define ABRT_ERR  bit (2) ///< Aborted Command\r
+#define TK0NF_ERR bit (1) ///< Track 0 Not Found\r
+#define AMNF_ERR  bit (0) ///< Address Mark Not Found\r
+\r
+//\r
+// ATAPI Err Reg bitmap\r
+//\r
+#define SENSE_KEY_ERR (bit (7) | bit (6) | bit (5) | bit (4))\r
+#define EOM_ERR bit (1) ///< End of Media Detected\r
+#define ILI_ERR bit (0) ///< Illegal Length Indication\r
+\r
+//\r
+// Device/Head Reg\r
+//\r
+#define LBA_MODE  bit (6)\r
+#define DEV       bit (4)\r
+#define HS3       bit (3)\r
+#define HS2       bit (2)\r
+#define HS1       bit (1)\r
+#define HS0       bit (0)\r
+#define CHS_MODE  (0)\r
+#define DRV0      (0)\r
+#define DRV1      (1)\r
+#define MST_DRV   DRV0\r
+#define SLV_DRV   DRV1\r
+\r
+//\r
+// Status Reg\r
+//\r
+#define BSY   bit (7) ///< Controller Busy\r
+#define DRDY  bit (6) ///< Drive Ready\r
+#define DWF   bit (5) ///< Drive Write Fault\r
+#define DSC   bit (4) ///< Disk Seek Complete\r
+#define DRQ   bit (3) ///< Data Request\r
+#define CORR  bit (2) ///< Corrected Data\r
+#define IDX   bit (1) ///< Index\r
+#define ERR   bit (0) ///< Error\r
+#define CHECK bit (0) ///< Check bit for ATAPI Status Reg\r
+\r
+//\r
+// Device Control Reg\r
+//\r
+#define SRST  bit (2) ///< Software Reset\r
+#define IEN_L bit (1) ///< Interrupt Enable\r
+\r
+//\r
+// ATAPI Feature Register\r
+//\r
+#define OVERLAP bit (1)\r
+#define DMA     bit (0)\r
+\r
+//\r
+// ATAPI Interrupt Reason Reson Reg (ATA Sector Count Register)\r
+//\r
+#define RELEASE     bit (2)\r
+#define IO          bit (1)\r
+#define CoD         bit (0)\r
+\r
+#define PACKET_CMD  0xA0\r
+\r
+#define DEFAULT_CMD (0xa0)\r
+//\r
+// default content of device control register, disable INT\r
+//\r
+#define DEFAULT_CTL           (0x0a)\r
+#define MAX_ATAPI_BYTE_COUNT  (0xfffe)\r
+\r
+//\r
+// function prototype\r
+//\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  );\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 3066 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 3066 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruDriverEntryPoint (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  )\r
+ /*++\r
+\r
+Routine Description:\r
+\r
+  Entry point for EFI drivers.\r
+\r
+Arguments:\r
+\r
+  ImageHandle - EFI_HANDLE\r
+  SystemTable - EFI_SYSTEM_TABLE\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS\r
+  Others \r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+RegisterAtapiScsiPassThru (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL *This,\r
+  IN  EFI_HANDLE                  Controller,\r
+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,\r
+  IN  UINT64                      OriginalPciAttributes\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Attaches SCSI Pass Thru Protocol for specified IDE channel.\r
+    \r
+Arguments:\r
+  This              - Protocol instance pointer.\r
+  Controller        - Parent device handle to the IDE channel.    \r
+  PciIo             - PCI I/O protocol attached on the "Controller".                        \r
+  \r
+Returns:\r
+  Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruFunction (\r
+  IN EFI_SCSI_PASS_THRU_PROTOCOL                        *This,\r
+  IN UINT32                                             Target,\r
+  IN UINT64                                             Lun,\r
+  IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET         *Packet,\r
+  IN EFI_EVENT                                          Event OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.\r
+\r
+Arguments:\r
+\r
+  This:     The EFI_SCSI_PASS_THRU_PROTOCOL instance.\r
+  Target:   The Target ID of the ATAPI device to send the SCSI \r
+            Request Packet. To ATAPI devices attached on an IDE\r
+            Channel, Target ID 0 indicates Master device;Target\r
+            ID 1 indicates Slave device.\r
+  Lun:      The LUN of the ATAPI device to send the SCSI Request\r
+            Packet. To the ATAPI device, Lun is always 0.\r
+  Packet:   The SCSI Request Packet to send to the ATAPI device \r
+            specified by Target and Lun.\r
+  Event:    If non-blocking I/O is not supported then Event is ignored, \r
+            and blocking I/O is performed.\r
+            If Event is NULL, then blocking I/O is performed.\r
+            If Event is not NULL and non blocking I/O is supported, \r
+            then non-blocking I/O is performed, and Event will be signaled \r
+            when the SCSI Request Packet completes.      \r
+\r
+Returns:  \r
+\r
+   EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruGetNextDevice (\r
+  IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT32                      *Target,\r
+  IN OUT UINT64                      *Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Used to retrieve the list of legal Target IDs for SCSI devices \r
+  on a SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - On input, a pointer to the Target ID of a SCSI \r
+                          device present on the SCSI channel.  On output, \r
+                          a pointer to the Target ID of the next SCSI device\r
+                          present on a SCSI channel.  An input value of \r
+                          0xFFFFFFFF retrieves the Target ID of the first \r
+                          SCSI device present on a SCSI channel.\r
+  Lun                   - On input, a pointer to the LUN of a SCSI device\r
+                          present on the SCSI channel. On output, a pointer\r
+                          to the LUN of the next SCSI device present on \r
+                          a SCSI channel.\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device \r
+                          on the SCSI channel was returned in Target and Lun.\r
+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.\r
+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not\r
+                           returned on a previous call to GetNextDevice().\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruBuildDevicePath (\r
+  IN     EFI_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN     UINT32                         Target,\r
+  IN     UINT64                         Lun,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL       **DevicePath\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - The Target ID of the SCSI device for which\r
+                          a device path node is to be allocated and built.\r
+  Lun                   - The LUN of the SCSI device for which a device \r
+                          path node is to be allocated and built.\r
+  DevicePath            - A pointer to a single device path node that \r
+                          describes the SCSI device specified by \r
+                          Target and Lun. This function is responsible \r
+                          for allocating the buffer DevicePath with the boot\r
+                          service AllocatePool().  It is the caller's \r
+                          responsibility to free DevicePath when the caller\r
+                          is finished with DevicePath.    \r
+  Returns:\r
+  EFI_SUCCESS           - The device path node that describes the SCSI device\r
+                          specified by Target and Lun was allocated and \r
+                          returned in DevicePath.\r
+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does\r
+                          not exist on the SCSI channel.\r
+  EFI_INVALID_PARAMETER - DevicePath is NULL.\r
+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate \r
+                          DevicePath.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruGetTargetLun (\r
+  IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,\r
+  OUT UINT32                         *Target,\r
+  OUT UINT64                         *Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Used to translate a device path node to a Target ID and LUN.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  DevicePath            - A pointer to the device path node that \r
+                          describes a SCSI device on the SCSI channel.\r
+  Target                - A pointer to the Target ID of a SCSI device \r
+                          on the SCSI channel. \r
+  Lun                   - A pointer to the LUN of a SCSI device on \r
+                          the SCSI channel.    \r
+Returns:\r
+\r
+  EFI_SUCCESS           - DevicePath was successfully translated to a \r
+                          Target ID and LUN, and they were returned \r
+                          in Target and Lun.\r
+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.\r
+  EFI_UNSUPPORTED       - This driver does not support the device path \r
+                          node type in DevicePath.\r
+  EFI_NOT_FOUND         - A valid translation from DevicePath to a \r
+                          Target ID and LUN does not exist.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruResetChannel (\r
+  IN  EFI_SCSI_PASS_THRU_PROTOCOL   *This\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Resets a SCSI channel.This operation resets all the \r
+  SCSI devices connected to the SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The SCSI channel was reset.\r
+  EFI_UNSUPPORTED       - The SCSI channel does not support \r
+                          a channel reset operation.\r
+  EFI_DEVICE_ERROR      - A device error occurred while \r
+                          attempting to reset the SCSI channel.\r
+  EFI_TIMEOUT           - A timeout occurred while attempting \r
+                          to reset the SCSI channel.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruResetTarget (\r
+  IN EFI_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN UINT32                         Target,\r
+  IN UINT64                         Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Resets a SCSI device that is connected to a SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - The Target ID of the SCSI device to reset. \r
+  Lun                   - The LUN of the SCSI device to reset.\r
+    \r
+Returns:\r
+\r
+  EFI_SUCCESS           - The SCSI device specified by Target and \r
+                          Lun was reset.\r
+  EFI_UNSUPPORTED       - The SCSI channel does not support a target\r
+                          reset operation.\r
+  EFI_INVALID_PARAMETER - Target or Lun are invalid.\r
+  EFI_DEVICE_ERROR      - A device error occurred while attempting \r
+                          to reset the SCSI device specified by Target \r
+                          and Lun.\r
+  EFI_TIMEOUT           - A timeout occurred while attempting to reset \r
+                          the SCSI device specified by Target and Lun.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruFunction (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                    *This,\r
+  IN UINT8                                              *Target,\r
+  IN UINT64                                             Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET     *Packet,\r
+  IN EFI_EVENT                                          Event OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.\r
+\r
+Arguments:\r
+\r
+  This:     The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  Target:   The Target ID of the ATAPI device to send the SCSI \r
+            Request Packet. To ATAPI devices attached on an IDE\r
+            Channel, Target ID 0 indicates Master device;Target\r
+            ID 1 indicates Slave device.\r
+  Lun:      The LUN of the ATAPI device to send the SCSI Request\r
+            Packet. To the ATAPI device, Lun is always 0.\r
+  Packet:   The SCSI Request Packet to send to the ATAPI device \r
+            specified by Target and Lun.\r
+  Event:    If non-blocking I/O is not supported then Event is ignored, \r
+            and blocking I/O is performed.\r
+            If Event is NULL, then blocking I/O is performed.\r
+            If Event is not NULL and non blocking I/O is supported, \r
+            then non-blocking I/O is performed, and Event will be signaled \r
+            when the SCSI Request Packet completes.      \r
+\r
+Returns:  \r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruGetNextTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT8                           **Target,\r
+  IN OUT UINT64                          *Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Used to retrieve the list of legal Target IDs for SCSI devices \r
+  on a SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - On input, a pointer to the Target ID of a SCSI \r
+                          device present on the SCSI channel.  On output, \r
+                          a pointer to the Target ID of the next SCSI device\r
+                          present on a SCSI channel.  An input value of \r
+                          0xFFFFFFFF retrieves the Target ID of the first \r
+                          SCSI device present on a SCSI channel.\r
+  Lun                   - On input, a pointer to the LUN of a SCSI device\r
+                          present on the SCSI channel. On output, a pointer\r
+                          to the LUN of the next SCSI device present on \r
+                          a SCSI channel.\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device \r
+                          on the SCSI channel was returned in Target and Lun.\r
+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.\r
+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not\r
+                           returned on a previous call to GetNextDevice().\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruBuildDevicePath (\r
+  IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN     UINT8                              *Target,\r
+  IN     UINT64                             Lun,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL           **DevicePath\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - The Target ID of the SCSI device for which\r
+                          a device path node is to be allocated and built.\r
+  Lun                   - The LUN of the SCSI device for which a device \r
+                          path node is to be allocated and built.\r
+  DevicePath            - A pointer to a single device path node that \r
+                          describes the SCSI device specified by \r
+                          Target and Lun. This function is responsible \r
+                          for allocating the buffer DevicePath with the boot\r
+                          service AllocatePool().  It is the caller's \r
+                          responsibility to free DevicePath when the caller\r
+                          is finished with DevicePath.    \r
+  Returns:\r
+  EFI_SUCCESS           - The device path node that describes the SCSI device\r
+                          specified by Target and Lun was allocated and \r
+                          returned in DevicePath.\r
+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does\r
+                          not exist on the SCSI channel.\r
+  EFI_INVALID_PARAMETER - DevicePath is NULL.\r
+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate \r
+                          DevicePath.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruGetTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,\r
+  OUT UINT8                          **Target,\r
+  OUT UINT64                         *Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Used to translate a device path node to a Target ID and LUN.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  DevicePath            - A pointer to the device path node that \r
+                          describes a SCSI device on the SCSI channel.\r
+  Target                - A pointer to the Target ID of a SCSI device \r
+                          on the SCSI channel. \r
+  Lun                   - A pointer to the LUN of a SCSI device on \r
+                          the SCSI channel.    \r
+Returns:\r
+\r
+  EFI_SUCCESS           - DevicePath was successfully translated to a \r
+                          Target ID and LUN, and they were returned \r
+                          in Target and Lun.\r
+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.\r
+  EFI_UNSUPPORTED       - This driver does not support the device path \r
+                          node type in DevicePath.\r
+  EFI_NOT_FOUND         - A valid translation from DevicePath to a \r
+                          Target ID and LUN does not exist.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruResetChannel (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *This\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Resets a SCSI channel.This operation resets all the \r
+  SCSI devices connected to the SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The SCSI channel was reset.\r
+  EFI_UNSUPPORTED       - The SCSI channel does not support \r
+                          a channel reset operation.\r
+  EFI_DEVICE_ERROR      - A device error occurred while \r
+                          attempting to reset the SCSI channel.\r
+  EFI_TIMEOUT           - A timeout occurred while attempting \r
+                          to reset the SCSI channel.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruResetTarget (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN UINT8                              *Target,\r
+  IN UINT64                             Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Resets a SCSI device that is connected to a SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - The Target ID of the SCSI device to reset. \r
+  Lun                   - The LUN of the SCSI device to reset.\r
+    \r
+Returns:\r
+\r
+  EFI_SUCCESS           - The SCSI device specified by Target and \r
+                          Lun was reset.\r
+  EFI_UNSUPPORTED       - The SCSI channel does not support a target\r
+                          reset operation.\r
+  EFI_INVALID_PARAMETER - Target or Lun are invalid.\r
+  EFI_DEVICE_ERROR      - A device error occurred while attempting \r
+                          to reset the SCSI device specified by Target \r
+                          and Lun.\r
+  EFI_TIMEOUT           - A timeout occurred while attempting to reset \r
+                          the SCSI device specified by Target and Lun.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiExtScsiPassThruGetNextTarget (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT8                           **Target\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Used to retrieve the list of legal Target IDs for SCSI devices \r
+  on a SCSI channel.\r
+\r
+Arguments:\r
+  This                  - Protocol instance pointer.\r
+  Target                - On input, a pointer to the Target ID of a SCSI \r
+                          device present on the SCSI channel.  On output, \r
+                          a pointer to the Target ID of the next SCSI device\r
+                           present on a SCSI channel.  An input value of \r
+                           0xFFFFFFFF retrieves the Target ID of the first \r
+                           SCSI device present on a SCSI channel.\r
+  Lun                   - On input, a pointer to the LUN of a SCSI device\r
+                          present on the SCSI channel. On output, a pointer\r
+                          to the LUN of the next SCSI device present on \r
+                          a SCSI channel.\r
+    \r
+Returns:\r
+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device \r
+                          on the SCSI channel was returned in Target and Lun.\r
+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.\r
+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not\r
+                          returned on a previous call to GetNextDevice().\r
+\r
+--*/\r
+;\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
+\r
+EFI_STATUS\r
+SubmitBlockingIoCommand (\r
+  ATAPI_SCSI_PASS_THRU_DEV                  *AtapiScsiPrivate,\r
+  UINT32                                    Target,\r
+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Performs blocking I/O request.\r
+    \r
+Arguments:\r
+\r
+  AtapiScsiPrivate:   Private data structure for the specified channel.\r
+  Target:             The Target ID of the ATAPI device to send the SCSI \r
+                      Request Packet. To ATAPI devices attached on an IDE\r
+                      Channel, Target ID 0 indicates Master device;Target\r
+                      ID 1 indicates Slave device.\r
+  Packet:             The SCSI Request Packet to send to the ATAPI device \r
+                      specified by Target.\r
+  \r
+  Returns:            EFI_STATUS  \r
+\r
+--*/\r
+;\r
+\r
+BOOLEAN\r
+IsCommandValid (\r
+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet\r
+  )\r
+ /*++\r
+\r
+Routine Description:\r
+\r
+  Checks the requested SCSI command: \r
+  Is it supported by this driver?\r
+  Is the Data transfer direction reasonable?\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
+\r
+EFI_STATUS\r
+CheckExtSCSIRequestPacket (\r
+  EFI_EXT_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_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
+  \r
+Returns:\r
+  \r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+\r
+BOOLEAN\r
+IsExtCommandValid (\r
+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet\r
+  )\r
+/*++\r
+  \r
+Routine Description:\r
+\r
+  Checks the requested SCSI command: \r
+  Is it supported by this driver?\r
+  Is the Data transfer direction reasonable?\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
+\r
+EFI_STATUS\r
+SubmitExtBlockingIoCommand (\r
+  ATAPI_SCSI_PASS_THRU_DEV                      *AtapiScsiPrivate,\r
+  UINT8                                         Target,\r
+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Performs blocking I/O request.\r
+    \r
+Arguments:\r
+\r
+  AtapiScsiPrivate:   Private data structure for the specified channel.\r
+  Target:             The Target ID of the ATAPI device to send the SCSI \r
+                      Request Packet. To ATAPI devices attached on an IDE\r
+                      Channel, Target ID 0 indicates Master device;Target\r
+                      ID 1 indicates Slave device.\r
+  Packet:             The SCSI Request Packet to send to the ATAPI device \r
+                      specified by Target.\r
+  \r
+  Returns:            EFI_STATUS  \r
+  \r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+RequestSenseCommand (\r
+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,\r
+  UINT32                      Target,\r
+  UINT64                      Timeout,\r
+  VOID                        *SenseData,\r
+  UINT8                       *SenseDataLength\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Sumbit request sense command\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate  - The pionter of ATAPI_SCSI_PASS_THRU_DEV\r
+  Target            - The target ID\r
+  Timeout           - The time to complete the command\r
+  SenseData         - The buffer to fill in sense data\r
+  SenseDataLength   - The length of buffer\r
+\r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+AtapiPacketCommand (\r
+  ATAPI_SCSI_PASS_THRU_DEV                  *AtapiScsiPrivate,\r
+  UINT32                                    Target,\r
+  UINT8                                     *PacketCommand,\r
+  VOID                                      *Buffer,\r
+  UINT32                                    *ByteCount,\r
+  DATA_DIRECTION                            Direction,\r
+  UINT64                                    TimeOutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Submits ATAPI command packet to the specified ATAPI device.\r
+    \r
+Arguments:\r
+\r
+  AtapiScsiPrivate:   Private data structure for the specified channel.\r
+  Target:             The Target ID of the ATAPI device to send the SCSI \r
+                      Request Packet. To ATAPI devices attached on an IDE\r
+                      Channel, Target ID 0 indicates Master device;Target\r
+                      ID 1 indicates Slave device.\r
+  PacketCommand:      Points to the ATAPI command packet.\r
+  Buffer:             Points to the transferred data.\r
+  ByteCount:          When input,indicates the buffer size; when output,\r
+                      indicates the actually transferred data size.\r
+  Direction:          Indicates the data transfer direction. \r
+  TimeoutInMicroSeconds:\r
+                      The timeout, in micro second units, to use for the \r
+                      execution of this ATAPI command.\r
+                      A TimeoutInMicroSeconds value of 0 means that \r
+                      this function will wait indefinitely for the ATAPI \r
+                      command to execute.\r
+                      If TimeoutInMicroSeconds is greater than zero, then \r
+                      this function will return EFI_TIMEOUT if the time \r
+                      required to execute the ATAPI command is greater \r
+                      than TimeoutInMicroSeconds.\r
+  \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+\r
+UINT8\r
+ReadPortB (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Read one byte from a specified I/O port.\r
+\r
+Arguments:\r
+\r
+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL\r
+  Port       - IO port\r
+  \r
+Returns:\r
+\r
+  A byte read out\r
+\r
+--*/\r
+;\r
+\r
+\r
+UINT16\r
+ReadPortW (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Read one word from a specified I/O port.\r
+\r
+Arguments:\r
+\r
+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL\r
+  Port       - IO port\r
+  \r
+Returns:     \r
+\r
+  A word read out\r
+\r
+--*/\r
+;\r
+\r
+\r
+VOID\r
+WritePortB (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINT8                 Data\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Write one byte to a specified I/O port.\r
+\r
+Arguments:\r
+\r
+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL\r
+  Port       - IO port\r
+  Data       - The data to write\r
+  \r
+Returns:\r
\r
+  NONE\r
\r
+--*/\r
+;\r
+\r
+\r
+VOID\r
+WritePortW (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINT16                Data\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Write one word to a specified I/O port.\r
+\r
+Arguments:\r
+\r
+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL\r
+  Port       - IO port\r
+  Data       - The data to write\r
+  \r
+Returns:\r
+\r
+  NONE\r
+  \r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+StatusDRQClear (\r
+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,\r
+  UINT64                          TimeOutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+AltStatusDRQClear (\r
+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,\r
+  UINT64                          TimeOutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Check whether DRQ is clear in the Alternate Status Register. \r
+  (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should \r
+  wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is \r
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+StatusDRQReady (\r
+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,\r
+  UINT64                          TimeOutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+AltStatusDRQReady (\r
+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,\r
+  UINT64                          TimeOutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+StatusWaitForBSYClear (\r
+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,\r
+  UINT64                      TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+AltStatusWaitForBSYClear (\r
+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,\r
+  UINT64                      TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+StatusDRDYReady (\r
+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,\r
+  UINT64                      TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+AltStatusDRDYReady (\r
+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,\r
+  UINT64                      TimeoutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\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
+  elapsed.\r
+\r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+  TimeoutInMicroSeconds       - The time to wait for\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+AtapiPassThruPioReadWriteData (\r
+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate,\r
+  UINT16                    *Buffer,\r
+  UINT32                    *ByteCount,\r
+  DATA_DIRECTION            Direction,\r
+  UINT64                    TimeOutInMicroSeconds\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Performs data transfer between ATAPI device and host after the\r
+  ATAPI command packet is sent.\r
+    \r
+Arguments:\r
+\r
+  AtapiScsiPrivate:   Private data structure for the specified channel.    \r
+  Buffer:             Points to the transferred data.\r
+  ByteCount:          When input,indicates the buffer size; when output,\r
+                      indicates the actually transferred data size.\r
+  Direction:          Indicates the data transfer direction. \r
+  TimeoutInMicroSeconds:\r
+                      The timeout, in micro second units, to use for the \r
+                      execution of this ATAPI command.\r
+                      A TimeoutInMicroSeconds value of 0 means that \r
+                      this function will wait indefinitely for the ATAPI \r
+                      command to execute.\r
+                      If TimeoutInMicroSeconds is greater than zero, then \r
+                      this function will return EFI_TIMEOUT if the time \r
+                      required to execute the ATAPI command is greater \r
+                      than TimeoutInMicroSeconds.\r
+ Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+AtapiPassThruCheckErrorStatus (\r
+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Check Error Register for Error Information. \r
+  \r
+Arguments:\r
+\r
+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV\r
+   \r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+\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
+\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
+/**\r
+  Installs Scsi Pass Thru and/or Ext Scsi Pass Thru \r
+  protocols based on feature flags. \r
+\r
+  @param Controller         The controller handle to \r
+                            install these protocols on.\r
+  @param AtapiScsiPrivate   A pointer to the protocol private\r
+                            data structure.\r
+\r
+  @retval EFI_SUCCESS       The installation succeeds. \r
+  @retval other             The installation fails. \r
+   \r
+**/\r
+EFI_STATUS\r
+InstallScsiPassThruProtocols (\r
+  IN EFI_HANDLE                 *ControllerHandle,\r
+  IN ATAPI_SCSI_PASS_THRU_DEV   *AtapiScsiPrivate\r
+  );\r
+\r
+#endif\r
diff --git a/OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf b/OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf
new file mode 100644 (file)
index 0000000..378624e
--- /dev/null
@@ -0,0 +1,65 @@
+#/** @file\r
+# Description file for the Atapi Passthru component.\r
+#\r
+# This driver simulates SCSI devices with Atapi devices to test the SCSI io\r
+#  protocol.\r
+# Copyright (c) 2006 - 2007, Intel Corporation\r
+#\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
+#  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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = AtapiPassThru\r
+  FILE_GUID                      = E49061CE-99A7-41d3-AB3A-36E5CFBAD63E\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  EDK_RELEASE_VERSION            = 0x00020000\r
+  EFI_SPECIFICATION_VERSION      = 0x00020000\r
+\r
+  ENTRY_POINT                    = InitializeAtapiPassThru\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+#  DRIVER_BINDING                =  gAtapiScsiPassThruDriverBinding              \r
+#  COMPONENT_NAME                =  gAtapiScsiPassThruComponentName              \r
+#\r
+\r
+[Sources.common]\r
+  ComponentName.c\r
+  AtapiPassThru.c\r
+  AtapiPassThru.h\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  OptionRomPkg/OptionRomPkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiBootServicesTableLib\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  UefiLib\r
+  BaseLib\r
+  UefiDriverEntryPoint\r
+  DebugLib\r
+\r
+\r
+[Protocols]\r
+  gEfiScsiPassThruProtocolGuid                  # PROTOCOL BY_START\r
+  gEfiExtScsiPassThruProtocolGuid               # PROTOCOL BY_START\r
+  gEfiPciIoProtocolGuid                         # PROTOCOL TO_START\r
+\r
+[FeaturePcd]\r
+  gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru\r
+  gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru\r
diff --git a/OptionRomPkg/AtapiPassThruDxe/ComponentName.c b/OptionRomPkg/AtapiPassThruDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..2f04f0b
--- /dev/null
@@ -0,0 +1,175 @@
+/** @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
+\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:  ComponentName.c\r
+\r
+**/\r
+#include "AtapiPassThru.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gAtapiScsiPassThruComponentName = {\r
+  AtapiScsiPassThruComponentNameGetDriverName,\r
+  AtapiScsiPassThruComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gAtapiScsiPassThruComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) AtapiScsiPassThruComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) AtapiScsiPassThruComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtapiScsiPassThruDriverNameTable[] = {\r
+  { "eng;en", (CHAR16 *) L"ATAPI SCSI Pass Thru Driver" },\r
+  { NULL , NULL }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 3066 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mAtapiScsiPassThruDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gAtapiScsiPassThruComponentName)\r
+           );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 3066 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtapiScsiPassThruComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/OptionRomPkg/OptionRomPkg.dec b/OptionRomPkg/OptionRomPkg.dec
new file mode 100644 (file)
index 0000000..7ada9ec
--- /dev/null
@@ -0,0 +1,31 @@
+#/** @file\r
+# Option Rom Package Reference Implementations.\r
+#\r
+# This package is designed to interoperate with the EDK II open source project\r
+# at http://www.tianocore.org, and this package is required to build PCI compliant\r
+# Option ROM image for all CPU architectures, including EBC target.\r
+# A single driver can support mixes of EFI 1.1, UEFI 2.0 and UEFI 2.1. \r
+#\r
+# Copyright (c) 2007, Intel Corporation.\r
+#\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
+#**/\r
+\r
+[Defines]\r
+  DEC_SPECIFICATION              = 0x00010005\r
+  PACKAGE_NAME                   = OptionRomPkg\r
+  PACKAGE_GUID                   = AA3865E8-7F30-4f59-8696-99F560101852\r
+  PACKAGE_VERSION                = 0.1\r
+\r
+[PcdsFeatureFlag.common]\r
+  gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru|TRUE|BOOLEAN|0x00010001\r
+  gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru|TRUE|BOOLEAN|0x00010002\r
+\r
+\r
diff --git a/OptionRomPkg/OptionRomPkg.dsc b/OptionRomPkg/OptionRomPkg.dsc
new file mode 100644 (file)
index 0000000..ed53dbe
--- /dev/null
@@ -0,0 +1,92 @@
+#/** @file\r
+# Option Rom Package build validation file for All Architectures.\r
+#\r
+# This package is designed to interoperate with the EDK II open source project\r
+# at http://www.tianocore.org, and this package is required to build PCI compliant\r
+# Option ROM image for all CPU architectures, including EBC target.\r
+# A single driver can support mixes of EFI 1.1, UEFI 2.0 and UEFI 2.1. \r
+#\r
+# Copyright (c) 2007, Intel Corporation\r
+#\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
+#**/\r
+\r
+################################################################################\r
+#\r
+# Defines Section - statements that will be processed to create a Makefile.\r
+#\r
+################################################################################\r
+[Defines]\r
+  PLATFORM_NAME                  = OptionRomPkg\r
+  PLATFORM_GUID                  = C7B25F37-B1F4-4c46-99CB-3EA7DCF5FCDC\r
+  PLATFORM_VERSION               = 0.1\r
+  DSC_SPECIFICATION              = 0x00010005\r
+  OUTPUT_DIRECTORY               = Build/OptionRomPkg\r
+  SUPPORTED_ARCHITECTURES        = IA32|IPF|X64|EBC\r
+  BUILD_TARGETS                  = DEBUG|RELEASE\r
+  SKUID_IDENTIFIER               = DEFAULT\r
+\r
+################################################################################\r
+#\r
+# SKU Identification section - list of all SKU IDs supported by this\r
+#                              Platform.\r
+#\r
+################################################################################\r
+[SkuIds]\r
+  0|DEFAULT              # The entry: 0|DEFAULT is reserved and always required.\r
+\r
+[LibraryClasses.common]\r
+  DebugLib|IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf\r
+  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf\r
+  CpuLib|MdePkg/Library/CpuLib/CpuLib.inf\r
+  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf\r
+  PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf\r
+  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf\r
+  TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf\r
+  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf\r
+  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf\r
+  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf\r
+  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf\r
+  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf\r
+  MemoryAllocationLib|MdePkg/Library/DxeMemoryAllocationLib/DxeMemoryAllocationLib.inf\r
+  ReportStatusCodeLib|IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf\r
+  \r
+################################################################################\r
+#\r
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform\r
+#\r
+################################################################################\r
+[PcdsFeatureFlag.common]\r
+  gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable|FALSE\r
+  gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable|FALSE\r
+  gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable|FALSE\r
+  gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable|FALSE\r
+  gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru|TRUE\r
+  gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru|TRUE\r
+\r
+[PcdsFixedAtBuild.common]\r
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength|0x0\r
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength|0x0\r
+  gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|0x0\r
+  gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout|0x0\r
+  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x27\r
+  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000042\r
+  gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x06\r
+  gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue|0x0\r
+\r
+################################################################################\r
+#\r
+# Components Section - list of all EDK II Modules needed by this Platform\r
+#\r
+################################################################################\r
+\r
+[Components.common]\r
+  OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf\r
+  \r
diff --git a/OptionRomPkg/ReadMe.txt b/OptionRomPkg/ReadMe.txt
new file mode 100644 (file)
index 0000000..a6c160a
--- /dev/null
@@ -0,0 +1,17 @@
+For now, AtapiPassThru driver in this package is to test Scsi Bus support:\r
+ScsiBus driver should support both/either ScsiPassThru and ExtScsiPassThru\r
+installed on a controller handle.\r
\r
+AtapiPassThru driver in this package can selectively produce ScsiPassThru\r
+and/or ExtScsiPassThru protocol based on feature flags of PcdSupportScsiPassThru\r
+and PcdExtScsiPassThru.\r
+\r
+Please note that AtapiPassThru driver has not been tuned to size optimal.\r
+Neither is it feature complete: several driver model protocols required\r
+by option ROM driver, e.g. EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL Protocol. \r
+\r
+Build Validation:\r
+MYTOOLS(VS2005) IA32 X64 IPF EBC\r
+ICC             IA32 X64 IPF\r
+CYGWINGCC       IA32 X64\r
+\r