Add OptionRomPkg, it contains AtapiPassThru driver for the test purpose of Scsi Bus support.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4309 6f19259b-4bc3-4df7-8a09-765794883524
diff --git a/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c b/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c
new file mode 100644
index 0000000..b15f292
--- /dev/null
+++ b/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c
@@ -0,0 +1,3394 @@
+/** @file

+  Copyright (c) 2006, Intel Corporation

+  All rights reserved. This program and the accompanying materials

+  are licensed and made available under the terms and conditions of the BSD License

+  which accompanies this distribution.  The full text of the license may be found at

+  http://opensource.org/licenses/bsd-license.php

+

+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#include "AtapiPassThru.h"

+

+

+static SCSI_COMMAND_SET     gEndTable = { 0xff, (DATA_DIRECTION) 0xff };

+

+///

+/// This table contains all the supported ATAPI commands.

+///

+static SCSI_COMMAND_SET     gSupportedATAPICommands[] = {

+  { OP_INQUIRY,                     DataIn  },

+  { OP_LOAD_UNLOAD_CD,              NoData  },

+  { OP_MECHANISM_STATUS,            DataIn  },

+  { OP_MODE_SELECT_10,              DataOut },

+  { OP_MODE_SENSE_10,               DataIn  },

+  { OP_PAUSE_RESUME,                NoData  },

+  { OP_PLAY_AUDIO_10,               DataIn  },

+  { OP_PLAY_AUDIO_MSF,              DataIn  },

+  { OP_PLAY_CD,                     DataIn  },

+  { OP_PLAY_CD_MSF,                 DataIn  },

+  { OP_PREVENT_ALLOW_MEDIUM_REMOVAL,NoData  },

+  { OP_READ_10,                     DataIn  },

+  { OP_READ_12,                     DataIn  },

+  { OP_READ_CAPACITY,               DataIn  },

+  { OP_READ_CD,                     DataIn  },

+  { OP_READ_CD_MSF,                 DataIn  },

+  { OP_READ_HEADER,                 DataIn  },

+  { OP_READ_SUB_CHANNEL,            DataIn  },

+  { OP_READ_TOC,                    DataIn  },

+  { OP_REQUEST_SENSE,               DataIn  },

+  { OP_SCAN,                        NoData  },

+  { OP_SEEK_10,                     NoData  },

+  { OP_SET_CD_SPEED,                DataOut },

+  { OP_STOPPLAY_SCAN,               NoData  },

+  { OP_START_STOP_UNIT,             NoData  },

+  { OP_TEST_UNIT_READY,             NoData  },

+  { OP_FORMAT_UNIT,                 DataOut },

+  { OP_READ_FORMAT_CAPACITIES,      DataIn  },

+  { OP_VERIFY,                      DataOut },

+  { OP_WRITE_10,                    DataOut },

+  { OP_WRITE_12,                    DataOut },

+  { OP_WRITE_AND_VERIFY,            DataOut },

+  { 0xff,                           (DATA_DIRECTION) 0xff    }

+};

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_MODE gScsiPassThruMode = {

+  L"ATAPI Controller",

+  L"ATAPI Channel",

+  4,

+  EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,

+  0

+};

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_PROTOCOL gScsiPassThruProtocolTemplate = {

+  &gScsiPassThruMode,

+  AtapiScsiPassThruFunction,

+  AtapiScsiPassThruGetNextDevice,

+  AtapiScsiPassThruBuildDevicePath,

+  AtapiScsiPassThruGetTargetLun,

+  AtapiScsiPassThruResetChannel,

+  AtapiScsiPassThruResetTarget

+};

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_MODE gExtScsiPassThruMode = {

+  4,      

+  EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,

+  0

+};

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_PROTOCOL gExtScsiPassThruProtocolTemplate = {

+  &gExtScsiPassThruMode,

+  AtapiExtScsiPassThruFunction,

+  AtapiExtScsiPassThruGetNextTargetLun,

+  AtapiExtScsiPassThruBuildDevicePath,

+  AtapiExtScsiPassThruGetTargetLun,

+  AtapiExtScsiPassThruResetChannel,

+  AtapiExtScsiPassThruResetTarget,

+  AtapiExtScsiPassThruGetNextTarget

+};

+

+EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding = {

+  AtapiScsiPassThruDriverBindingSupported,

+  AtapiScsiPassThruDriverBindingStart,

+  AtapiScsiPassThruDriverBindingStop,

+  0x10,

+  NULL,

+  NULL

+};

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverBindingSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  )

+/*++

+  

+Routine Description:

+  Test to see if this driver supports ControllerHandle. Any ControllerHandle

+  that has gEfiPciIoProtocolGuid installed and is IDE Controller it will be supported.

+    

+Arguments:

+

+  This                - Protocol instance pointer.

+  Controller          - Handle of device to test

+  RemainingDevicePath - Not used

+    

+Returns:

+    EFI_STATUS

+  

+--*/

+{

+  EFI_STATUS          Status;

+  EFI_PCI_IO_PROTOCOL *PciIo;

+  PCI_TYPE00          Pci;

+

+

+  //

+  // Open the IO Abstraction(s) needed to perform the supported test

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiPciIoProtocolGuid,

+                  (VOID **) &PciIo,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+  //

+  // Use the PCI I/O Protocol to see if Controller is a IDE Controller that

+  // can be managed by this driver.  Read the PCI Configuration Header

+  // for this device.

+  //

+  Status = PciIo->Pci.Read (

+                        PciIo,

+                        EfiPciIoWidthUint32,

+                        0,

+                        sizeof (Pci) / sizeof (UINT32),

+                        &Pci

+                        );

+  if (EFI_ERROR (Status)) {

+    gBS->CloseProtocol (

+           Controller,

+           &gEfiPciIoProtocolGuid,

+           This->DriverBindingHandle,

+           Controller

+           );

+    return EFI_UNSUPPORTED;

+  }

+

+  if (Pci.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE || Pci.Hdr.ClassCode[1] != PCI_CLASS_IDE) {

+

+    Status = EFI_UNSUPPORTED;

+  }

+

+  gBS->CloseProtocol (

+         Controller,

+         &gEfiPciIoProtocolGuid,

+         This->DriverBindingHandle,

+         Controller

+         );

+

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverBindingStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  )

+/*++

+  

+Routine Description:

+  Create handles for IDE channels specified by RemainingDevicePath.

+  Install SCSI Pass Thru Protocol onto each created handle.

+  

+Arguments:

+

+  This                - Protocol instance pointer.

+  Controller          - Handle of device to test

+  RemainingDevicePath - Not used

+    

+Returns:

+    EFI_STATUS

+    

+--*/

+{

+  EFI_STATUS          Status;

+  EFI_PCI_IO_PROTOCOL *PciIo;

+  UINT64              Supports;

+  UINT64              OriginalPciAttributes;

+

+  PciIo = NULL;

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiPciIoProtocolGuid,

+                  (VOID **) &PciIo,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // Save original PCI attributes

+  //

+  Status = PciIo->Attributes (

+                    PciIo,

+                    EfiPciIoAttributeOperationGet,

+                    0,

+                    &OriginalPciAttributes

+                    );

+

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  Status = PciIo->Attributes (

+                    PciIo,

+                    EfiPciIoAttributeOperationSupported,

+                    0,

+                    &Supports

+                    );

+  if (!EFI_ERROR (Status)) {

+    Supports &= (EFI_PCI_DEVICE_ENABLE               |

+                 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO |

+                 EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO);

+    Status = PciIo->Attributes (

+                      PciIo,

+                      EfiPciIoAttributeOperationEnable,

+                      Supports,

+                      NULL

+                      );

+  }

+  if (EFI_ERROR (Status)) {

+    goto Done;

+  }

+

+  //

+  // Create SCSI Pass Thru instance for the IDE channel.

+  //

+  Status = RegisterAtapiScsiPassThru (This, Controller, PciIo, OriginalPciAttributes);

+

+Done:

+  if (EFI_ERROR (Status)) {

+    //

+    // Restore original PCI attributes

+    //

+    PciIo->Attributes (

+                    PciIo,

+                    EfiPciIoAttributeOperationSet,

+                    OriginalPciAttributes,

+                    NULL

+                    );

+

+    gBS->CloseProtocol (

+           Controller,

+           &gEfiPciIoProtocolGuid,

+           This->DriverBindingHandle,

+           Controller

+           );

+  }

+

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverBindingStop (

+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,

+  IN  EFI_HANDLE                      Controller,

+  IN  UINTN                           NumberOfChildren,

+  IN  EFI_HANDLE                      *ChildHandleBuffer

+  )

+/*++

+  

+Routine Description:

+

+  Stop this driver on ControllerHandle. Support stoping any child handles

+  created by this driver.

+

+Arguments:

+

+  This              - Protocol instance pointer.

+  Controller        - Handle of device to stop driver on

+  NumberOfChildren  - Number of Children in the ChildHandleBuffer

+  ChildHandleBuffer - List of handles for the children we need to stop.

+  

+Returns:

+

+    EFI_STATUS

+  

+--*/

+{

+  EFI_STATUS                      Status;

+  EFI_SCSI_PASS_THRU_PROTOCOL     *ScsiPassThru;

+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate;

+

+  if (FeaturePcdGet (PcdSupportScsiPassThru)) {

+    Status = gBS->OpenProtocol (

+                    Controller,

+                    &gEfiScsiPassThruProtocolGuid,

+                    (VOID **) &ScsiPassThru,

+                    This->DriverBindingHandle,

+                    Controller,

+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                    );

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+    AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru);

+    if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {

+      Status = gBS->UninstallMultipleProtocolInterfaces (

+                      Controller,

+                      &gEfiScsiPassThruProtocolGuid,

+                      &AtapiScsiPrivate->ScsiPassThru,

+                      &gEfiExtScsiPassThruProtocolGuid,

+                      &AtapiScsiPrivate->ExtScsiPassThru,

+                      NULL

+                      );

+    } else {

+      Status = gBS->UninstallMultipleProtocolInterfaces (

+                      Controller,

+                      &gEfiScsiPassThruProtocolGuid,

+                      &AtapiScsiPrivate->ScsiPassThru,

+                      NULL

+                      );

+    }

+  } else {

+    Status = gBS->OpenProtocol (

+                    Controller,

+                    &gEfiExtScsiPassThruProtocolGuid,

+                    (VOID **) &ExtScsiPassThru,

+                    This->DriverBindingHandle,

+                    Controller,

+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                    );

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+    AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (ExtScsiPassThru);

+    Status = gBS->UninstallMultipleProtocolInterfaces (

+                    Controller,

+                    &gEfiExtScsiPassThruProtocolGuid,

+                    &AtapiScsiPrivate->ExtScsiPassThru,

+                    NULL

+                    );

+  }

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // Restore original PCI attributes

+  //

+  AtapiScsiPrivate->PciIo->Attributes (

+                  AtapiScsiPrivate->PciIo,

+                  EfiPciIoAttributeOperationSet,

+                  AtapiScsiPrivate->OriginalPciAttributes,

+                  NULL

+                  );

+

+  gBS->CloseProtocol (

+         Controller,

+         &gEfiPciIoProtocolGuid,

+         This->DriverBindingHandle,

+         Controller

+         );

+

+  gBS->FreePool (AtapiScsiPrivate);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+RegisterAtapiScsiPassThru (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN  EFI_HANDLE                  Controller,

+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,

+  IN  UINT64                      OriginalPciAttributes

+  )

+/*++

+  

+Routine Description:

+  Attaches SCSI Pass Thru Protocol for specified IDE channel.

+    

+Arguments:

+  This              - Protocol instance pointer.

+  Controller        - Parent device handle to the IDE channel.    

+  PciIo             - PCI I/O protocol attached on the "Controller".                        

+  

+Returns:

+  Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.

+

+--*/

+{

+  EFI_STATUS                Status;

+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;

+  IDE_REGISTERS_BASE_ADDR   IdeRegsBaseAddr[ATAPI_MAX_CHANNEL];

+

+  AtapiScsiPrivate = AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV));

+  if (AtapiScsiPrivate == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  AtapiScsiPrivate->Signature = ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE;

+  AtapiScsiPrivate->Handle    = Controller;

+

+  //

+  // will reset the IoPort inside each API function.

+  //

+  AtapiScsiPrivate->IoPort                = NULL;

+  AtapiScsiPrivate->PciIo                 = PciIo;

+  AtapiScsiPrivate->OriginalPciAttributes = OriginalPciAttributes;

+

+  //

+  // Obtain IDE IO port registers' base addresses

+  //

+  Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  InitAtapiIoPortRegisters(AtapiScsiPrivate, IdeRegsBaseAddr);

+

+  //

+  // Initialize the LatestTargetId to MAX_TARGET_ID.

+  //

+  AtapiScsiPrivate->LatestTargetId  = MAX_TARGET_ID;

+  AtapiScsiPrivate->LatestLun       = 0;

+

+  Status = InstallScsiPassThruProtocols (&Controller, AtapiScsiPrivate);

+

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruFunction (

+  IN EFI_SCSI_PASS_THRU_PROTOCOL                        *This,

+  IN UINT32                                             Target,

+  IN UINT64                                             Lun,

+  IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET         *Packet,

+  IN EFI_EVENT                                          Event OPTIONAL

+  )

+/*++

+

+Routine Description:

+

+  Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.

+

+Arguments:

+

+  This:     The EFI_SCSI_PASS_THRU_PROTOCOL instance.

+  Target:   The Target ID of the ATAPI device to send the SCSI 

+            Request Packet. To ATAPI devices attached on an IDE

+            Channel, Target ID 0 indicates Master device;Target

+            ID 1 indicates Slave device.

+  Lun:      The LUN of the ATAPI device to send the SCSI Request

+            Packet. To the ATAPI device, Lun is always 0.

+  Packet:   The SCSI Request Packet to send to the ATAPI device 

+            specified by Target and Lun.

+  Event:    If non-blocking I/O is not supported then Event is ignored, 

+            and blocking I/O is performed.

+            If Event is NULL, then blocking I/O is performed.

+            If Event is not NULL and non blocking I/O is supported, 

+            then non-blocking I/O is performed, and Event will be signaled 

+            when the SCSI Request Packet completes.      

+

+Returns:  

+

+   EFI_STATUS

+   

+--*/

+{

+  ATAPI_SCSI_PASS_THRU_DEV               *AtapiScsiPrivate;

+  EFI_STATUS                             Status;

+

+  AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+

+  //

+  // Target is not allowed beyond MAX_TARGET_ID

+  //

+  if ((Target > MAX_TARGET_ID) || (Lun != 0)) {

+    return EFI_INVALID_PARAMETER;

+  }

+  

+  //

+  // check the data fields in Packet parameter.

+  //

+  Status = CheckSCSIRequestPacket (Packet);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // If Request Packet targets at the IDE channel itself,

+  // do nothing.

+  //

+  if (Target == This->Mode->AdapterId) {

+    Packet->TransferLength = 0;

+    return EFI_SUCCESS;

+  }

+

+  //

+  // According to Target ID, reset the Atapi I/O Register mapping

+  // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],

+  //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]

+  //

+  if ((Target / 2) == 0) {

+    Target = Target % 2;

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];

+  } else {

+    Target = Target % 2;

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];

+  }

+

+  //

+  // the ATAPI SCSI interface does not support non-blocking I/O

+  // ignore the Event parameter

+  //

+  // Performs blocking I/O.

+  //

+  Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, Packet);

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruGetNextDevice (

+  IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN OUT UINT32                      *Target,

+  IN OUT UINT64                      *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to retrieve the list of legal Target IDs for SCSI devices 

+  on a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - On input, a pointer to the Target ID of a SCSI 

+                          device present on the SCSI channel.  On output, 

+                          a pointer to the Target ID of the next SCSI device

+                          present on a SCSI channel.  An input value of 

+                          0xFFFFFFFF retrieves the Target ID of the first 

+                          SCSI device present on a SCSI channel.

+  Lun                   - On input, a pointer to the LUN of a SCSI device

+                          present on the SCSI channel. On output, a pointer

+                          to the LUN of the next SCSI device present on 

+                          a SCSI channel.

+Returns:

+

+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device 

+                          on the SCSI channel was returned in Target and Lun.

+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.

+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not

+                           returned on a previous call to GetNextDevice().

+--*/

+{

+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;

+

+  //

+  // Retrieve Device Private Data Structure.

+  //

+  AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+

+  //

+  // Check whether Target is valid.

+  //

+  if (Target == NULL || Lun == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if ((*Target != 0xFFFFFFFF) &&

+      ((*Target != AtapiScsiPrivate->LatestTargetId) ||

+      (*Lun != AtapiScsiPrivate->LatestLun))) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (*Target == MAX_TARGET_ID) {

+    return EFI_NOT_FOUND;

+  }

+

+  if (*Target == 0xFFFFFFFF) {

+    *Target = 0;

+  } else {

+    *Target = AtapiScsiPrivate->LatestTargetId + 1;

+  }

+

+  *Lun = 0;

+

+  //

+  // Update the LatestTargetId.

+  //

+  AtapiScsiPrivate->LatestTargetId  = *Target;

+  AtapiScsiPrivate->LatestLun       = *Lun;

+

+  return EFI_SUCCESS;

+

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruBuildDevicePath (

+  IN     EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN     UINT32                         Target,

+  IN     UINT64                         Lun,

+  IN OUT EFI_DEVICE_PATH_PROTOCOL       **DevicePath

+  )

+/*++

+

+Routine Description:

+

+  Used to allocate and build a device path node for a SCSI device 

+  on a SCSI channel. Would not build device path for a SCSI Host Controller.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device for which

+                          a device path node is to be allocated and built.

+  Lun                   - The LUN of the SCSI device for which a device 

+                          path node is to be allocated and built.

+  DevicePath            - A pointer to a single device path node that 

+                          describes the SCSI device specified by 

+                          Target and Lun. This function is responsible 

+                          for allocating the buffer DevicePath with the boot

+                          service AllocatePool().  It is the caller's 

+                          responsibility to free DevicePath when the caller

+                          is finished with DevicePath.    

+  Returns:

+  EFI_SUCCESS           - The device path node that describes the SCSI device

+                          specified by Target and Lun was allocated and 

+                          returned in DevicePath.

+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does

+                          not exist on the SCSI channel.

+  EFI_INVALID_PARAMETER - DevicePath is NULL.

+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate 

+                          DevicePath.

+--*/

+{

+  EFI_DEV_PATH              *Node;

+

+

+  //

+  // Validate parameters passed in.

+  //

+

+  if (DevicePath == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // can not build device path for the SCSI Host Controller.

+  //

+  if ((Target > (MAX_TARGET_ID - 1)) || (Lun != 0)) {

+    return EFI_NOT_FOUND;

+  }

+

+  Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));

+  if (Node == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  Node->DevPath.Type    = MESSAGING_DEVICE_PATH;

+  Node->DevPath.SubType = MSG_ATAPI_DP;

+  SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));

+

+  Node->Atapi.PrimarySecondary  = (UINT8) (Target / 2);

+  Node->Atapi.SlaveMaster       = (UINT8) (Target % 2);

+  Node->Atapi.Lun               = (UINT16) Lun;

+

+  *DevicePath                   = (EFI_DEVICE_PATH_PROTOCOL *) Node;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruGetTargetLun (

+  IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,

+  OUT UINT32                         *Target,

+  OUT UINT64                         *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to translate a device path node to a Target ID and LUN.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  DevicePath            - A pointer to the device path node that 

+                          describes a SCSI device on the SCSI channel.

+  Target                - A pointer to the Target ID of a SCSI device 

+                          on the SCSI channel. 

+  Lun                   - A pointer to the LUN of a SCSI device on 

+                          the SCSI channel.    

+Returns:

+

+  EFI_SUCCESS           - DevicePath was successfully translated to a 

+                          Target ID and LUN, and they were returned 

+                          in Target and Lun.

+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.

+  EFI_UNSUPPORTED       - This driver does not support the device path 

+                          node type in DevicePath.

+  EFI_NOT_FOUND         - A valid translation from DevicePath to a 

+                          Target ID and LUN does not exist.

+--*/

+{

+  EFI_DEV_PATH  *Node;

+

+  //

+  // Validate parameters passed in.

+  //

+  if (DevicePath == NULL || Target == NULL || Lun == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Check whether the DevicePath belongs to SCSI_DEVICE_PATH

+  //

+  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||

+      (DevicePath->SubType != MSG_ATAPI_DP) ||

+      (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {

+    return EFI_UNSUPPORTED;

+  }

+

+  Node    = (EFI_DEV_PATH *) DevicePath;

+

+  *Target = Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster;

+  *Lun    = Node->Atapi.Lun;

+

+  if (*Target > (MAX_TARGET_ID - 1) || *Lun != 0) {

+    return EFI_NOT_FOUND;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruResetChannel (

+  IN  EFI_SCSI_PASS_THRU_PROTOCOL   *This

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI channel.This operation resets all the 

+  SCSI devices connected to the SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+

+Returns:

+

+  EFI_SUCCESS           - The SCSI channel was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support 

+                          a channel reset operation.

+  EFI_DEVICE_ERROR      - A device error occurred while 

+                          attempting to reset the SCSI channel.

+  EFI_TIMEOUT           - A timeout occurred while attempting 

+                          to reset the SCSI channel.

+--*/

+{

+  UINT8                     DeviceControlValue;

+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;

+  UINT8                     Index;

+  BOOLEAN                   ResetFlag;

+

+  AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+  ResetFlag = FALSE;

+

+  //

+  // Reset both Primary channel and Secondary channel.

+  // so, the IoPort pointer must point to the right I/O Register group

+  //

+  for (Index = 0; Index < 2; Index++) {

+    //

+    // Reset

+    //

+    AtapiScsiPrivate->IoPort  = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];

+

+    DeviceControlValue        = 0;

+    //

+    // set SRST bit to initiate soft reset

+    //

+    DeviceControlValue |= SRST;

+    //

+    // disable Interrupt

+    //

+    DeviceControlValue |= bit (1);

+    WritePortB (

+      AtapiScsiPrivate->PciIo,

+      AtapiScsiPrivate->IoPort->Alt.DeviceControl,

+      DeviceControlValue

+      );

+

+    //

+    // Wait 10us

+    //

+    gBS->Stall (10);

+

+    //

+    // Clear SRST bit

+    // 0xfb:1111,1011

+    //

+    DeviceControlValue &= 0xfb;

+

+    WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);

+

+    //

+    // slave device needs at most 31s to clear BSY

+    //

+    if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {

+      ResetFlag = TRUE;

+    }

+  }

+

+  if (ResetFlag) {

+    return EFI_SUCCESS;

+  }

+

+  return EFI_TIMEOUT;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruResetTarget (

+  IN EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN UINT32                         Target,

+  IN UINT64                         Lun

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI device that is connected to a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device to reset. 

+  Lun                   - The LUN of the SCSI device to reset.

+    

+Returns:

+

+  EFI_SUCCESS           - The SCSI device specified by Target and 

+                          Lun was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support a target

+                          reset operation.

+  EFI_INVALID_PARAMETER - Target or Lun are invalid.

+  EFI_DEVICE_ERROR      - A device error occurred while attempting 

+                          to reset the SCSI device specified by Target 

+                          and Lun.

+  EFI_TIMEOUT           - A timeout occurred while attempting to reset 

+                          the SCSI device specified by Target and Lun.

+--*/

+{

+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;

+  UINT8                     Command;

+  UINT8                     DeviceSelect;

+

+  AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+

+  if ((Target > MAX_TARGET_ID) || (Lun != 0)) {

+    return EFI_INVALID_PARAMETER;

+  }

+  //

+  // Directly return EFI_SUCCESS if want to reset the host controller

+  //

+  if (Target == This->Mode->AdapterId) {

+    return EFI_SUCCESS;

+  }

+

+  //

+  // According to Target ID, reset the Atapi I/O Register mapping

+  // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],

+  //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]

+  //

+  if ((Target / 2) == 0) {

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];

+  } else {

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];

+  }

+

+  //

+  // for ATAPI device, no need to wait DRDY ready after device selecting.

+  //

+  // bit7 and bit5 are both set to 1 for backward compatibility

+  //

+  DeviceSelect = (UINT8) (((bit (7) | bit (5)) | (Target << 4)));

+  WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);

+

+  Command = ATAPI_SOFT_RESET_CMD;

+  WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);

+

+  //

+  // BSY clear is the only status return to the host by the device

+  // when reset is complete.

+  // slave device needs at most 31s to clear BSY

+  //

+  if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {

+    return EFI_TIMEOUT;

+  }

+

+  //

+  // stall 5 seconds to make the device status stable

+  //

+  gBS->Stall (5000000);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruFunction (

+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                    *This,

+  IN UINT8                                              *Target,

+  IN UINT64                                             Lun,

+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET     *Packet,

+  IN EFI_EVENT                                          Event OPTIONAL

+  )

+/*++

+

+Routine Description:

+

+  Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.

+

+Arguments:

+

+  This:     The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.

+  Target:   The Target ID of the ATAPI device to send the SCSI 

+            Request Packet. To ATAPI devices attached on an IDE

+            Channel, Target ID 0 indicates Master device;Target

+            ID 1 indicates Slave device.

+  Lun:      The LUN of the ATAPI device to send the SCSI Request

+            Packet. To the ATAPI device, Lun is always 0.

+  Packet:   The SCSI Request Packet to send to the ATAPI device 

+            specified by Target and Lun.

+  Event:    If non-blocking I/O is not supported then Event is ignored, 

+            and blocking I/O is performed.

+            If Event is NULL, then blocking I/O is performed.

+            If Event is not NULL and non blocking I/O is supported, 

+            then non-blocking I/O is performed, and Event will be signaled 

+            when the SCSI Request Packet completes.      

+

+Returns:  

+

+   EFI_STATUS

+   

+--*/

+{

+  EFI_STATUS                          Status;

+  ATAPI_SCSI_PASS_THRU_DEV            *AtapiScsiPrivate;

+  UINT8                                TargetId;

+  

+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+

+  //

+  // For ATAPI device, UINT8 is enough to represent the SCSI ID on channel.

+  //

+  TargetId = Target[0];

+  

+  //

+  // Target is not allowed beyond MAX_TARGET_ID

+  //

+  if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {

+    return EFI_INVALID_PARAMETER;

+  }

+  

+  //

+  // check the data fields in Packet parameter.

+  //

+  Status = CheckExtSCSIRequestPacket (Packet);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // If Request Packet targets at the IDE channel itself,

+  // do nothing.

+  //

+  if (TargetId == (UINT8)This->Mode->AdapterId) {

+    Packet->InTransferLength = Packet->OutTransferLength = 0;

+    return EFI_SUCCESS;

+  }

+  

+  //

+  // According to Target ID, reset the Atapi I/O Register mapping

+  // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],

+  //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]

+  //

+  if ((TargetId / 2) == 0) {

+    TargetId = (UINT8) (TargetId % 2);

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];

+  } else {

+    TargetId = (UINT8) (TargetId % 2);

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];

+  }

+  

+  //

+  // the ATAPI SCSI interface does not support non-blocking I/O

+  // ignore the Event parameter

+  //

+  // Performs blocking I/O.

+  //

+  Status = SubmitExtBlockingIoCommand (AtapiScsiPrivate, TargetId, Packet);

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruGetNextTargetLun (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN OUT UINT8                           **Target,

+  IN OUT UINT64                          *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to retrieve the list of legal Target IDs for SCSI devices 

+  on a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - On input, a pointer to the Target ID of a SCSI 

+                          device present on the SCSI channel.  On output, 

+                          a pointer to the Target ID of the next SCSI device

+                          present on a SCSI channel.  An input value of 

+                          0xFFFFFFFF retrieves the Target ID of the first 

+                          SCSI device present on a SCSI channel.

+  Lun                   - On input, a pointer to the LUN of a SCSI device

+                          present on the SCSI channel. On output, a pointer

+                          to the LUN of the next SCSI device present on 

+                          a SCSI channel.

+Returns:

+

+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device 

+                          on the SCSI channel was returned in Target and Lun.

+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.

+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not

+                           returned on a previous call to GetNextDevice().

+--*/

+{

+  UINT8                          ByteIndex;

+  UINT8                          TargetId;

+  UINT8                          ScsiId[TARGET_MAX_BYTES];

+  ATAPI_SCSI_PASS_THRU_DEV       *AtapiScsiPrivate; 

+

+  //

+  // Retrieve Device Private Data Structure.

+  //

+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+

+  //

+  // Check whether Target is valid.

+  //

+  if (*Target == NULL || Lun == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);

+

+  TargetId = (*Target)[0];

+

+  //

+  // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.

+  //

+  if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {

+    for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {

+      if ((*Target)[ByteIndex] != 0) {

+        return EFI_INVALID_PARAMETER;

+      }

+    } 

+  }

+  

+  if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&

+      ((TargetId != AtapiScsiPrivate->LatestTargetId) ||

+      (*Lun != AtapiScsiPrivate->LatestLun))) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (TargetId == MAX_TARGET_ID) {

+    return EFI_NOT_FOUND;

+  }

+

+  if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0) {

+    SetMem (*Target, TARGET_MAX_BYTES,0);

+  } else {

+    (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);

+  }

+

+  *Lun = 0;

+

+  //

+  // Update the LatestTargetId.

+  //

+  AtapiScsiPrivate->LatestTargetId  = (*Target)[0];

+  AtapiScsiPrivate->LatestLun       = *Lun;

+

+  return EFI_SUCCESS;

+

+}

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruBuildDevicePath (

+  IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN     UINT8                              *Target,

+  IN     UINT64                             Lun,

+  IN OUT EFI_DEVICE_PATH_PROTOCOL           **DevicePath

+  )

+/*++

+

+Routine Description:

+

+  Used to allocate and build a device path node for a SCSI device 

+  on a SCSI channel. Would not build device path for a SCSI Host Controller.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device for which

+                          a device path node is to be allocated and built.

+  Lun                   - The LUN of the SCSI device for which a device 

+                          path node is to be allocated and built.

+  DevicePath            - A pointer to a single device path node that 

+                          describes the SCSI device specified by 

+                          Target and Lun. This function is responsible 

+                          for allocating the buffer DevicePath with the boot

+                          service AllocatePool().  It is the caller's 

+                          responsibility to free DevicePath when the caller

+                          is finished with DevicePath.    

+  Returns:

+  EFI_SUCCESS           - The device path node that describes the SCSI device

+                          specified by Target and Lun was allocated and 

+                          returned in DevicePath.

+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does

+                          not exist on the SCSI channel.

+  EFI_INVALID_PARAMETER - DevicePath is NULL.

+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate 

+                          DevicePath.

+--*/

+{

+  EFI_DEV_PATH                   *Node;

+  UINT8                          TargetId;

+

+  TargetId = Target[0];  

+

+  //

+  // Validate parameters passed in.

+  //

+  

+  if (DevicePath == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+  

+  //

+  // can not build device path for the SCSI Host Controller.

+  //

+  if ((TargetId > (MAX_TARGET_ID - 1)) || (Lun != 0)) {

+    return EFI_NOT_FOUND;

+  }

+

+  Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));

+  if (Node == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  Node->DevPath.Type    = MESSAGING_DEVICE_PATH;

+  Node->DevPath.SubType = MSG_ATAPI_DP;

+  SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));

+

+  Node->Atapi.PrimarySecondary  = (UINT8) (TargetId / 2);

+  Node->Atapi.SlaveMaster       = (UINT8) (TargetId % 2);

+  Node->Atapi.Lun               = (UINT16) Lun;

+

+  *DevicePath                   = (EFI_DEVICE_PATH_PROTOCOL *) Node;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruGetTargetLun (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN  EFI_DEVICE_PATH_PROTOCOL           *DevicePath,

+  OUT UINT8                              **Target,

+  OUT UINT64                             *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to translate a device path node to a Target ID and LUN.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  DevicePath            - A pointer to the device path node that 

+                          describes a SCSI device on the SCSI channel.

+  Target                - A pointer to the Target ID of a SCSI device 

+                          on the SCSI channel. 

+  Lun                   - A pointer to the LUN of a SCSI device on 

+                          the SCSI channel.    

+Returns:

+

+  EFI_SUCCESS           - DevicePath was successfully translated to a 

+                          Target ID and LUN, and they were returned 

+                          in Target and Lun.

+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.

+  EFI_UNSUPPORTED       - This driver does not support the device path 

+                          node type in DevicePath.

+  EFI_NOT_FOUND         - A valid translation from DevicePath to a 

+                          Target ID and LUN does not exist.

+--*/

+{

+  EFI_DEV_PATH  *Node;

+

+  //

+  // Validate parameters passed in.

+  //

+  if (DevicePath == NULL || Target == NULL || Lun == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+  

+  //

+  // Check whether the DevicePath belongs to SCSI_DEVICE_PATH

+  //

+  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||

+      (DevicePath->SubType != MSG_ATAPI_DP) ||

+      (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {

+    return EFI_UNSUPPORTED;

+  }

+

+  ZeroMem (*Target, TARGET_MAX_BYTES);

+

+  Node    = (EFI_DEV_PATH *) DevicePath;

+

+  (*Target)[0] = (UINT8) (Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster);

+  *Lun    = Node->Atapi.Lun;

+

+  if ((*Target)[0] > (MAX_TARGET_ID - 1) || *Lun != 0) {

+    return EFI_NOT_FOUND;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruResetChannel (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *This

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI channel.This operation resets all the 

+  SCSI devices connected to the SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+

+Returns:

+

+  EFI_SUCCESS           - The SCSI channel was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support 

+                          a channel reset operation.

+  EFI_DEVICE_ERROR      - A device error occurred while 

+                          attempting to reset the SCSI channel.

+  EFI_TIMEOUT           - A timeout occurred while attempting 

+                          to reset the SCSI channel.

+--*/

+{

+  UINT8                         DeviceControlValue;

+  UINT8                         Index;

+  ATAPI_SCSI_PASS_THRU_DEV      *AtapiScsiPrivate;

+  BOOLEAN                       ResetFlag;

+

+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+  ResetFlag = FALSE;

+  //

+  // Reset both Primary channel and Secondary channel.

+  // so, the IoPort pointer must point to the right I/O Register group

+  // And if there is a channel reset successfully, return EFI_SUCCESS.

+  //

+  for (Index = 0; Index < 2; Index++) {

+    //

+    // Reset

+    //

+    AtapiScsiPrivate->IoPort  = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];

+

+    DeviceControlValue        = 0;

+    //

+    // set SRST bit to initiate soft reset

+    //

+    DeviceControlValue |= SRST;

+    //

+    // disable Interrupt

+    //

+    DeviceControlValue |= bit (1);

+    WritePortB (

+      AtapiScsiPrivate->PciIo,

+      AtapiScsiPrivate->IoPort->Alt.DeviceControl,

+      DeviceControlValue

+      );

+

+    //

+    // Wait 10us

+    //

+    gBS->Stall (10);

+

+    //

+    // Clear SRST bit

+    // 0xfb:1111,1011

+    //

+    DeviceControlValue &= 0xfb;

+    

+    WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);

+

+    //

+    // slave device needs at most 31s to clear BSY

+    //

+    if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {

+      ResetFlag = TRUE;

+    }

+  }

+

+  if (ResetFlag) {

+    return EFI_SUCCESS;

+  }

+  

+  return EFI_TIMEOUT;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruResetTarget (

+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN UINT8                              *Target,

+  IN UINT64                             Lun

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI device that is connected to a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device to reset. 

+  Lun                   - The LUN of the SCSI device to reset.

+    

+Returns:

+

+  EFI_SUCCESS           - The SCSI device specified by Target and 

+                          Lun was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support a target

+                          reset operation.

+  EFI_INVALID_PARAMETER - Target or Lun are invalid.

+  EFI_DEVICE_ERROR      - A device error occurred while attempting 

+                          to reset the SCSI device specified by Target 

+                          and Lun.

+  EFI_TIMEOUT           - A timeout occurred while attempting to reset 

+                          the SCSI device specified by Target and Lun.

+--*/

+{

+  UINT8                         Command;

+  UINT8                         DeviceSelect;

+  UINT8                         TargetId;

+  ATAPI_SCSI_PASS_THRU_DEV      *AtapiScsiPrivate;

+  

+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+  TargetId = Target[0];

+  

+  if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {

+    return EFI_INVALID_PARAMETER;

+  }

+  //

+  // Directly return EFI_SUCCESS if want to reset the host controller

+  //

+  if (TargetId == This->Mode->AdapterId) {

+    return EFI_SUCCESS;

+  }

+  

+  //

+  // According to Target ID, reset the Atapi I/O Register mapping

+  // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],

+  //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]

+  //

+  if ((TargetId / 2) == 0) {

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];

+  } else {

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];

+  }

+  

+  //

+  // for ATAPI device, no need to wait DRDY ready after device selecting.

+  //

+  // bit7 and bit5 are both set to 1 for backward compatibility

+  //

+  DeviceSelect = (UINT8) (((bit (7) | bit (5)) | (TargetId << 4)));

+  WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);

+

+  Command = ATAPI_SOFT_RESET_CMD;

+  WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);

+

+  //

+  // BSY clear is the only status return to the host by the device

+  // when reset is complete.

+  // slave device needs at most 31s to clear BSY

+  //

+  if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {

+    return EFI_TIMEOUT;

+  }

+  

+  //

+  // stall 5 seconds to make the device status stable

+  //

+  gBS->Stall (5000000);

+

+  return EFI_SUCCESS;

+}

+

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruGetNextTarget (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN OUT UINT8                           **Target

+  )

+/*++

+

+Routine Description:

+  Used to retrieve the list of legal Target IDs for SCSI devices 

+  on a SCSI channel.

+

+Arguments:

+  This                  - Protocol instance pointer.

+  Target                - On input, a pointer to the Target ID of a SCSI 

+                          device present on the SCSI channel.  On output, 

+                          a pointer to the Target ID of the next SCSI device

+                           present on a SCSI channel.  An input value of 

+                           0xFFFFFFFF retrieves the Target ID of the first 

+                           SCSI device present on a SCSI channel.

+  Lun                   - On input, a pointer to the LUN of a SCSI device

+                          present on the SCSI channel. On output, a pointer

+                          to the LUN of the next SCSI device present on 

+                          a SCSI channel.

+    

+Returns:

+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device 

+                          on the SCSI channel was returned in Target and Lun.

+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.

+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not

+                          returned on a previous call to GetNextDevice().

+--*/

+{

+  UINT8                         TargetId;

+  UINT8                         ScsiId[TARGET_MAX_BYTES];

+  ATAPI_SCSI_PASS_THRU_DEV      *AtapiScsiPrivate;  

+  UINT8                         ByteIndex;

+

+  //

+  // Retrieve Device Private Data Structure.

+  //

+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+

+  //

+  // Check whether Target is valid.

+  //

+  if (*Target == NULL ) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  TargetId = (*Target)[0];

+  SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);

+

+  //

+  // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.

+  //

+  if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {

+    for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {

+      if ((*Target)[ByteIndex] != 0) {

+        return EFI_INVALID_PARAMETER;

+      }

+    }

+  }

+

+  if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&(TargetId != AtapiScsiPrivate->LatestTargetId)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (TargetId == MAX_TARGET_ID) {

+    return EFI_NOT_FOUND;

+  }

+

+  if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0)) {

+    SetMem (*Target, TARGET_MAX_BYTES, 0);

+  } else {

+    (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);

+  }

+

+  //

+  // Update the LatestTargetId.

+  //

+  AtapiScsiPrivate->LatestTargetId  = (*Target)[0];

+  AtapiScsiPrivate->LatestLun       = 0;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+GetIdeRegistersBaseAddr (

+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,

+  OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr

+  )

+/*++

+

+Routine Description:

+  Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,

+  use fixed addresses. In Native-PCI mode, get base addresses from BARs in

+  the PCI IDE controller's Configuration Space.

+

+Arguments:

+  PciIo             - Pointer to the EFI_PCI_IO_PROTOCOL instance

+  IdeRegsBaseAddr   - Pointer to IDE_REGISTERS_BASE_ADDR to

+                      receive IDE IO port registers' base addresses

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  EFI_STATUS  Status;

+  PCI_TYPE00  PciData;

+

+  Status = PciIo->Pci.Read (

+                        PciIo,

+                        EfiPciIoWidthUint8,

+                        0,

+                        sizeof (PciData),

+                        &PciData

+                        );

+

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {

+    IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  = 0x1f0;

+    IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  = 0x3f6;

+  } else {

+    //

+    // The BARs should be of IO type

+    //

+    if ((PciData.Device.Bar[0] & BIT0) == 0 ||

+        (PciData.Device.Bar[1] & BIT0) == 0) {

+      return EFI_UNSUPPORTED;

+    }

+

+    IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  =

+    (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);

+    IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  =

+    (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);

+  }

+

+  if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {

+    IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  = 0x170;

+    IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  = 0x376;

+  } else {

+    //

+    // The BARs should be of IO type

+    //

+    if ((PciData.Device.Bar[2] & BIT0) == 0 ||

+        (PciData.Device.Bar[3] & BIT0) == 0) {

+      return EFI_UNSUPPORTED;

+    }

+

+    IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  =

+    (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);

+    IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  =

+    (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);

+  }

+

+  return EFI_SUCCESS;

+}

+

+VOID

+InitAtapiIoPortRegisters (

+  IN  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,

+  IN  IDE_REGISTERS_BASE_ADDR      *IdeRegsBaseAddr

+  )

+/*++

+

+Routine Description:

+

+  Initialize each Channel's Base Address of CommandBlock and ControlBlock.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  IdeRegsBaseAddr             - The pointer of IDE_REGISTERS_BASE_ADDR

+

+Returns:

+

+  None

+

+--*/

+{

+

+  UINT8               IdeChannel;

+  UINT16              CommandBlockBaseAddr;

+  UINT16              ControlBlockBaseAddr;

+  IDE_BASE_REGISTERS  *RegisterPointer;

+

+

+  for (IdeChannel = 0; IdeChannel < ATAPI_MAX_CHANNEL; IdeChannel++) {

+

+    RegisterPointer =  &AtapiScsiPrivate->AtapiIoPortRegisters[IdeChannel];

+

+    //

+    // Initialize IDE IO port addresses, including Command Block registers

+    // and Control Block registers

+    //

+    CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr;

+    ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr;

+

+    RegisterPointer->Data = CommandBlockBaseAddr;

+    (*(UINT16 *) &RegisterPointer->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);

+    RegisterPointer->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);

+    RegisterPointer->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);

+    RegisterPointer->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);

+    RegisterPointer->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);

+    RegisterPointer->Head = (UINT16) (CommandBlockBaseAddr + 0x06);

+    (*(UINT16 *) &RegisterPointer->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);

+

+    (*(UINT16 *) &RegisterPointer->Alt) = ControlBlockBaseAddr;

+    RegisterPointer->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);

+  }

+

+}

+

+

+EFI_STATUS

+CheckSCSIRequestPacket (

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet

+  )

+/*++

+

+Routine Description:

+

+  Checks the parameters in the SCSI Request Packet to make sure

+  they are valid for a SCSI Pass Thru request.

+

+Arguments:

+

+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  if (Packet == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (!ValidCdbLength (Packet->CdbLength)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (Packet->Cdb == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Checks whether the request command is supported.

+  //

+  if (!IsCommandValid (Packet)) {

+    return EFI_UNSUPPORTED;

+  }

+

+  return EFI_SUCCESS;

+}

+

+BOOLEAN

+IsCommandValid (

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet

+  )

+/*++

+  

+Routine Description:

+

+  Checks the requested SCSI command: 

+  Is it supported by this driver?

+  Is the Data transfer direction reasonable?

+

+Arguments:

+

+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT8 Index;

+  UINT8 *OpCode;

+

+  OpCode = (UINT8 *) (Packet->Cdb);

+

+  for (Index = 0; CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)); Index++) {

+

+    if (*OpCode == gSupportedATAPICommands[Index].OpCode) {

+      //

+      // Check whether the requested Command is supported by this driver

+      //

+      if (Packet->DataDirection == DataIn) {

+        //

+        // Check whether the requested data direction conforms to

+        // what it should be.

+        //

+        if (gSupportedATAPICommands[Index].Direction == DataOut) {

+          return FALSE;

+        }

+      }

+

+      if (Packet->DataDirection == DataOut) {

+        //

+        // Check whether the requested data direction conforms to

+        // what it should be.

+        //

+        if (gSupportedATAPICommands[Index].Direction == DataIn) {

+          return FALSE;

+        }

+      }

+

+      return TRUE;

+    }

+  }

+

+  return FALSE;

+}

+

+EFI_STATUS

+SubmitBlockingIoCommand (

+  ATAPI_SCSI_PASS_THRU_DEV                  *AtapiScsiPrivate,

+  UINT32                                    Target,

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet

+  )

+/*++

+

+Routine Description:

+

+  Performs blocking I/O request.

+    

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Target:             The Target ID of the ATAPI device to send the SCSI 

+                      Request Packet. To ATAPI devices attached on an IDE

+                      Channel, Target ID 0 indicates Master device;Target

+                      ID 1 indicates Slave device.

+  Packet:             The SCSI Request Packet to send to the ATAPI device 

+                      specified by Target.

+  

+  Returns:            EFI_STATUS  

+  

+--*/

+{

+  UINT8       PacketCommand[12];

+  UINT64      TimeoutInMicroSeconds;

+  EFI_STATUS  PacketCommandStatus;

+

+  //

+  // Fill ATAPI Command Packet according to CDB

+  //

+  ZeroMem (&PacketCommand, 12);

+  CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);

+

+  //

+  // Timeout is 100ns unit, convert it to 1000ns (1us) unit.

+  //

+  TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);

+

+  //

+  // Submit ATAPI Command Packet

+  //

+  PacketCommandStatus = AtapiPacketCommand (

+                          AtapiScsiPrivate,

+                          Target,

+                          PacketCommand,

+                          Packet->DataBuffer,

+                          &(Packet->TransferLength),

+                          (DATA_DIRECTION) Packet->DataDirection,

+                          TimeoutInMicroSeconds

+                          );

+  if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {

+    Packet->SenseDataLength = 0;

+    return PacketCommandStatus;

+  }

+

+  //

+  // Return SenseData if PacketCommandStatus matches

+  // the following return codes.

+  //

+  if ((PacketCommandStatus ==  EFI_BAD_BUFFER_SIZE) ||

+      (PacketCommandStatus == EFI_DEVICE_ERROR) ||

+      (PacketCommandStatus == EFI_TIMEOUT)) {

+

+    //

+    // avoid submit request sense command continuously.

+    //

+    if (PacketCommand[0] == OP_REQUEST_SENSE) {

+      Packet->SenseDataLength = 0;

+      return PacketCommandStatus;

+    }

+

+    RequestSenseCommand (

+      AtapiScsiPrivate,

+      Target,

+      Packet->Timeout,

+      Packet->SenseData,

+      &Packet->SenseDataLength

+      );

+  }

+

+  return PacketCommandStatus;

+}

+

+EFI_STATUS

+RequestSenseCommand (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT32                      Target,

+  UINT64                      Timeout,

+  VOID                        *SenseData,

+  UINT8                       *SenseDataLength

+  )

+/*++

+

+Routine Description:

+

+  Sumbit request sense command

+

+Arguments:

+

+  AtapiScsiPrivate  - The pionter of ATAPI_SCSI_PASS_THRU_DEV

+  Target            - The target ID

+  Timeout           - The time to complete the command

+  SenseData         - The buffer to fill in sense data

+  SenseDataLength   - The length of buffer

+

+Returns:

+

+  EFI_STATUS

+  

+--*/

+{

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  Packet;

+  UINT8                                   Cdb[12];

+  EFI_STATUS                              Status;

+

+  ZeroMem (&Packet, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));

+  ZeroMem (Cdb, 12);

+

+  Cdb[0]                = OP_REQUEST_SENSE;

+  Cdb[4]                = (UINT8) (*SenseDataLength);

+

+  Packet.Timeout        = Timeout;

+  Packet.DataBuffer     = SenseData;

+  Packet.SenseData      = NULL;

+  Packet.Cdb            = Cdb;

+  Packet.TransferLength = *SenseDataLength;

+  Packet.CdbLength      = 12;

+  Packet.DataDirection  = DataIn;

+

+  Status                = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &Packet);

+  *SenseDataLength      = (UINT8) (Packet.TransferLength);

+  return Status;

+}

+

+EFI_STATUS

+CheckExtSCSIRequestPacket (

+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet

+  )

+/*++

+

+Routine Description:

+

+  Checks the parameters in the SCSI Request Packet to make sure

+  they are valid for a SCSI Pass Thru request.

+

+Arguments:

+

+  Packet       - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET

+  

+Returns:

+  

+  EFI_STATUS

+

+--*/

+{

+  if (Packet == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (!ValidCdbLength (Packet->CdbLength)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (Packet->Cdb == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+  

+  //

+  // Checks whether the request command is supported.

+  //

+  if (!IsExtCommandValid (Packet)) {

+    return EFI_UNSUPPORTED;

+  }

+

+  return EFI_SUCCESS;

+}

+

+

+BOOLEAN

+IsExtCommandValid (

+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet

+  )

+/*++

+  

+Routine Description:

+

+  Checks the requested SCSI command: 

+  Is it supported by this driver?

+  Is the Data transfer direction reasonable?

+

+Arguments:

+

+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT8 Index;

+  UINT8 *OpCode;

+

+  OpCode = (UINT8 *) (Packet->Cdb);

+

+  for (Index = 0; CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)); Index++) {

+

+    if (*OpCode == gSupportedATAPICommands[Index].OpCode) {

+      //

+      // Check whether the requested Command is supported by this driver

+      //

+      if (Packet->DataDirection == DataIn) {

+        //

+        // Check whether the requested data direction conforms to

+        // what it should be.

+        //

+        if (gSupportedATAPICommands[Index].Direction == DataOut) {

+          return FALSE;

+        }

+      }

+

+      if (Packet->DataDirection == DataOut) {

+        //

+        // Check whether the requested data direction conforms to

+        // what it should be.

+        //

+        if (gSupportedATAPICommands[Index].Direction == DataIn) {

+          return FALSE;

+        }

+      }

+

+      return TRUE;

+    }

+  }

+

+  return FALSE;

+}

+

+EFI_STATUS

+SubmitExtBlockingIoCommand (

+  ATAPI_SCSI_PASS_THRU_DEV                      *AtapiScsiPrivate,

+  UINT8                                         Target,

+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet

+  )

+/*++

+

+Routine Description:

+

+  Performs blocking I/O request.

+    

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Target:             The Target ID of the ATAPI device to send the SCSI 

+                      Request Packet. To ATAPI devices attached on an IDE

+                      Channel, Target ID 0 indicates Master device;Target

+                      ID 1 indicates Slave device.

+  Packet:             The SCSI Request Packet to send to the ATAPI device 

+                      specified by Target.

+  

+  Returns:            EFI_STATUS  

+  

+--*/

+{

+  UINT8       PacketCommand[12];

+  UINT64      TimeoutInMicroSeconds;

+  EFI_STATUS  PacketCommandStatus;

+

+  //

+  // Fill ATAPI Command Packet according to CDB

+  //

+  ZeroMem (&PacketCommand, 12);

+  CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);

+

+  //

+  // Timeout is 100ns unit, convert it to 1000ns (1us) unit.

+  //

+  TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);

+

+  //

+  // Submit ATAPI Command Packet

+  //

+  if (Packet->DataDirection == DataIn) {

+    PacketCommandStatus = AtapiPacketCommand (

+                              AtapiScsiPrivate,

+                              Target,

+                              PacketCommand,

+                              Packet->InDataBuffer,

+                              &(Packet->InTransferLength),

+                              DataIn,

+                              TimeoutInMicroSeconds

+                              );

+  } else {

+

+    PacketCommandStatus = AtapiPacketCommand (

+                            AtapiScsiPrivate,

+                            Target,

+                            PacketCommand,

+                            Packet->OutDataBuffer,

+                            &(Packet->OutTransferLength),

+                            DataOut,

+                            TimeoutInMicroSeconds

+                            );

+  }

+  

+  if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {

+    Packet->SenseDataLength = 0;

+    return PacketCommandStatus;

+  }

+  

+  //

+  // Return SenseData if PacketCommandStatus matches

+  // the following return codes.

+  //

+  if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||

+      (PacketCommandStatus == EFI_DEVICE_ERROR) ||

+      (PacketCommandStatus == EFI_TIMEOUT)) {

+

+    //

+    // avoid submit request sense command continuously.

+    //

+    if (PacketCommand[0] == OP_REQUEST_SENSE) {

+      Packet->SenseDataLength = 0;

+      return PacketCommandStatus;

+    }

+

+    RequestSenseCommand (

+      AtapiScsiPrivate,

+      Target,

+      Packet->Timeout,

+      Packet->SenseData,

+      &Packet->SenseDataLength

+      );

+  }

+

+  return PacketCommandStatus;

+}

+

+

+EFI_STATUS

+AtapiPacketCommand (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT32                      Target,

+  UINT8                       *PacketCommand,

+  VOID                        *Buffer,

+  UINT32                      *ByteCount,

+  DATA_DIRECTION              Direction,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Submits ATAPI command packet to the specified ATAPI device.

+    

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Target:             The Target ID of the ATAPI device to send the SCSI 

+                      Request Packet. To ATAPI devices attached on an IDE

+                      Channel, Target ID 0 indicates Master device;Target

+                      ID 1 indicates Slave device.

+  PacketCommand:      Points to the ATAPI command packet.

+  Buffer:             Points to the transferred data.

+  ByteCount:          When input,indicates the buffer size; when output,

+                      indicates the actually transferred data size.

+  Direction:          Indicates the data transfer direction. 

+  TimeoutInMicroSeconds:

+                      The timeout, in micro second units, to use for the 

+                      execution of this ATAPI command.

+                      A TimeoutInMicroSeconds value of 0 means that 

+                      this function will wait indefinitely for the ATAPI 

+                      command to execute.

+                      If TimeoutInMicroSeconds is greater than zero, then 

+                      this function will return EFI_TIMEOUT if the time 

+                      required to execute the ATAPI command is greater 

+                      than TimeoutInMicroSeconds.

+  

+Returns:

+

+  EFI_STATUS

+  

+--*/

+{

+

+  UINT16      *CommandIndex;

+  UINT8       Count;

+  EFI_STATUS  Status;

+

+  //

+  // Set all the command parameters by fill related registers.

+  // Before write to all the following registers, BSY must be 0.

+  //

+  Status = StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds);

+  if (EFI_ERROR (Status)) {

+    return EFI_DEVICE_ERROR;

+  }

+

+

+  //

+  // Select device via Device/Head Register.

+  // "Target = 0" indicates device 0; "Target = 1" indicates device 1

+  //

+  WritePortB (

+    AtapiScsiPrivate->PciIo,

+    AtapiScsiPrivate->IoPort->Head,

+    (UINT8) ((Target << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)

+    );

+

+  //

+  // Set all the command parameters by fill related registers.

+  // Before write to all the following registers, BSY DRQ must be 0.

+  //

+  Status =  StatusDRQClear(AtapiScsiPrivate,  TimeoutInMicroSeconds);

+

+  if (EFI_ERROR (Status)) {

+    if (Status == EFI_ABORTED) {

+      Status = EFI_DEVICE_ERROR;

+    }

+    *ByteCount = 0;

+    return Status;

+  }

+

+  //

+  // No OVL; No DMA (by setting feature register)

+  //

+  WritePortB (

+    AtapiScsiPrivate->PciIo,

+    AtapiScsiPrivate->IoPort->Reg1.Feature,

+    0x00

+    );

+

+  //

+  // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device

+  // determine how much data should be transfered.

+  //

+  WritePortB (

+    AtapiScsiPrivate->PciIo,

+    AtapiScsiPrivate->IoPort->CylinderLsb,

+    (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)

+    );

+  WritePortB (

+    AtapiScsiPrivate->PciIo,

+    AtapiScsiPrivate->IoPort->CylinderMsb,

+    (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)

+    );

+

+  //

+  //  DEFAULT_CTL:0x0a (0000,1010)

+  //  Disable interrupt

+  //

+  WritePortB (

+    AtapiScsiPrivate->PciIo,

+    AtapiScsiPrivate->IoPort->Alt.DeviceControl,

+    DEFAULT_CTL

+    );

+

+  //

+  // Send Packet command to inform device

+  // that the following data bytes are command packet.

+  //

+  WritePortB (

+    AtapiScsiPrivate->PciIo,

+    AtapiScsiPrivate->IoPort->Reg.Command,

+    PACKET_CMD

+    );

+

+  //

+  // Before data transfer, BSY should be 0 and DRQ should be 1.

+  // if they are not in specified time frame,

+  // retrieve Sense Key from Error Register before return.

+  //

+  Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);

+  if (EFI_ERROR (Status)) {

+    if (Status == EFI_ABORTED) {

+      Status = EFI_DEVICE_ERROR;

+    }

+

+    *ByteCount = 0;

+    return Status;

+  }

+

+  //

+  // Send out command packet

+  //

+  CommandIndex = (UINT16 *) PacketCommand;

+  for (Count = 0; Count < 6; Count++, CommandIndex++) {

+    WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *CommandIndex);

+  }

+

+  //

+  // call AtapiPassThruPioReadWriteData() function to get

+  // requested transfer data form device.

+  //

+  return AtapiPassThruPioReadWriteData (

+          AtapiScsiPrivate,

+          Buffer,

+          ByteCount,

+          Direction,

+          TimeoutInMicroSeconds

+          );

+}

+

+EFI_STATUS

+AtapiPassThruPioReadWriteData (

+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate,

+  UINT16                    *Buffer,

+  UINT32                    *ByteCount,

+  DATA_DIRECTION            Direction,

+  UINT64                    TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Performs data transfer between ATAPI device and host after the

+  ATAPI command packet is sent.

+    

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.    

+  Buffer:             Points to the transferred data.

+  ByteCount:          When input,indicates the buffer size; when output,

+                      indicates the actually transferred data size.

+  Direction:          Indicates the data transfer direction. 

+  TimeoutInMicroSeconds:

+                      The timeout, in micro second units, to use for the 

+                      execution of this ATAPI command.

+                      A TimeoutInMicroSeconds value of 0 means that 

+                      this function will wait indefinitely for the ATAPI 

+                      command to execute.

+                      If TimeoutInMicroSeconds is greater than zero, then 

+                      this function will return EFI_TIMEOUT if the time 

+                      required to execute the ATAPI command is greater 

+                      than TimeoutInMicroSeconds.

+ Returns:

+

+  EFI_STATUS

+  

+--*/

+{

+  UINT32      Index;

+  UINT32      RequiredWordCount;

+  UINT32      ActualWordCount;

+  UINT32      WordCount;

+  EFI_STATUS  Status;

+  UINT16      *ptrBuffer;

+

+  Status = EFI_SUCCESS;

+

+  //

+  // Non Data transfer request is also supported.

+  //

+  if (*ByteCount == 0 || Buffer == NULL) {

+    *ByteCount = 0;

+    if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds))) {

+      return EFI_DEVICE_ERROR;

+    }

+  }

+

+  ptrBuffer         = Buffer;

+  RequiredWordCount = *ByteCount / 2;

+

+  //

+  // ActuralWordCount means the word count of data really transfered.

+  //

+  ActualWordCount = 0;

+

+  while (ActualWordCount < RequiredWordCount) {

+    //

+    // before each data transfer stream, the host should poll DRQ bit ready,

+    // which indicates device's ready for data transfer .

+    //

+    Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);

+    if (EFI_ERROR (Status)) {

+      *ByteCount = ActualWordCount * 2;

+

+      AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);

+

+      if (ActualWordCount == 0) {

+        return EFI_DEVICE_ERROR;

+      }

+      //

+      // ActualWordCount > 0

+      //

+      if (ActualWordCount < RequiredWordCount) {

+        return EFI_BAD_BUFFER_SIZE;

+      }

+    }

+    //

+    // get current data transfer size from Cylinder Registers.

+    //

+    WordCount = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderMsb) << 8;

+    WordCount = WordCount | ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderLsb);

+    WordCount = WordCount & 0xffff;

+    WordCount /= 2;

+

+    //

+    // perform a series data In/Out.

+    //

+    for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {

+

+      if (Direction == DataIn) {

+

+        *ptrBuffer = ReadPortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data);

+      } else {

+

+        WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *ptrBuffer);

+      }

+

+      ptrBuffer++;

+

+    }

+  }

+  //

+  // After data transfer is completed, normally, DRQ bit should clear.

+  //

+  StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);

+

+  //

+  // read status register to check whether error happens.

+  //

+  Status      = AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);

+

+  *ByteCount  = ActualWordCount * 2;

+

+  return Status;

+}

+

+

+UINT8

+ReadPortB (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port

+  )

+/*++

+

+Routine Description:

+

+  Read one byte from a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  

+Returns:

+

+  A byte read out

+

+--*/

+{

+  UINT8 Data;

+

+  Data = 0;

+  PciIo->Io.Read (

+              PciIo,

+              EfiPciIoWidthUint8,

+              EFI_PCI_IO_PASS_THROUGH_BAR,

+              (UINT64) Port,

+              1,

+              &Data

+              );

+  return Data;

+}

+

+

+UINT16

+ReadPortW (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port

+  )

+/*++

+

+Routine Description:

+

+  Read one word from a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  

+Returns:

+

+  A word read out

+--*/

+{

+  UINT16  Data;

+

+  Data = 0;

+  PciIo->Io.Read (

+              PciIo,

+              EfiPciIoWidthUint16,

+              EFI_PCI_IO_PASS_THROUGH_BAR,

+              (UINT64) Port,

+              1,

+              &Data

+              );

+  return Data;

+}

+

+

+VOID

+WritePortB (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port,

+  IN  UINT8                 Data

+  )

+/*++

+

+Routine Description:

+

+  Write one byte to a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  Data       - The data to write

+  

+Returns:

+

+   NONE

+

+--*/

+{

+  PciIo->Io.Write (

+              PciIo,

+              EfiPciIoWidthUint8,

+              EFI_PCI_IO_PASS_THROUGH_BAR,

+              (UINT64) Port,

+              1,

+              &Data

+              );

+}

+

+

+VOID

+WritePortW (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port,

+  IN  UINT16                Data

+  )

+/*++

+

+Routine Description:

+

+  Write one word to a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  Data       - The data to write

+  

+Returns:

+

+   NONE

+   

+--*/

+{

+  PciIo->Io.Write (

+              PciIo,

+              EfiPciIoWidthUint16,

+              EFI_PCI_IO_PASS_THROUGH_BAR,

+              (UINT64) Port,

+              1,

+              &Data

+              );

+}

+

+EFI_STATUS

+StatusDRQClear (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is clear in the Status Register. (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+  

+--*/

+{

+  UINT64  Delay;

+  UINT8   StatusRegister;

+  UINT8   ErrRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+

+    StatusRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg.Status

+                      );

+

+    //

+    // wait for BSY == 0 and DRQ == 0

+    //

+    if ((StatusRegister & (DRQ | BSY)) == 0) {

+      break;

+    }

+    //

+    // check whether the command is aborted by the device

+    //

+    if ((StatusRegister & (BSY | ERR)) == ERR) {

+

+      ErrRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg1.Error

+                      );

+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

+

+        return EFI_ABORTED;

+      }

+    }

+    //

+    //  Stall for 30 us

+    //

+    gBS->Stall (30);

+

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+AltStatusDRQClear (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is clear in the Alternate Status Register. 

+  (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should 

+  wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   AltStatusRegister;

+  UINT8   ErrRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+

+    AltStatusRegister = ReadPortB (

+                          AtapiScsiPrivate->PciIo,

+                          AtapiScsiPrivate->IoPort->Alt.AltStatus

+                          );

+

+    //

+    // wait for BSY == 0 and DRQ == 0

+    //

+    if ((AltStatusRegister & (DRQ | BSY)) == 0) {

+      break;

+    }

+

+    if ((AltStatusRegister & (BSY | ERR)) == ERR) {

+

+      ErrRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg1.Error

+                      );

+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

+

+        return EFI_ABORTED;

+      }

+    }

+    //

+    //  Stall for 30 us

+    //

+    gBS->Stall (30);

+

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+StatusDRQReady (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is ready in the Status Register. (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   StatusRegister;

+  UINT8   ErrRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+    //

+    //  read Status Register will clear interrupt

+    //

+    StatusRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg.Status

+                      );

+

+    //

+    //  BSY==0,DRQ==1

+    //

+    if ((StatusRegister & (BSY | DRQ)) == DRQ) {

+      break;

+    }

+

+    if ((StatusRegister & (BSY | ERR)) == ERR) {

+

+      ErrRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg1.Error

+                      );

+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

+        return EFI_ABORTED;

+      }

+    }

+

+    //

+    // Stall for 30 us

+    //

+    gBS->Stall (30);

+

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+AltStatusDRQReady (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is ready in the Alternate Status Register. 

+  (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   AltStatusRegister;

+  UINT8   ErrRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+    //

+    //  read Status Register will clear interrupt

+    //

+    AltStatusRegister = ReadPortB (

+                          AtapiScsiPrivate->PciIo,

+                          AtapiScsiPrivate->IoPort->Alt.AltStatus

+                          );

+    //

+    //  BSY==0,DRQ==1

+    //

+    if ((AltStatusRegister & (BSY | DRQ)) == DRQ) {

+      break;

+    }

+

+    if ((AltStatusRegister & (BSY | ERR)) == ERR) {

+

+      ErrRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg1.Error

+                      );

+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

+        return EFI_ABORTED;

+      }

+    }

+

+    //

+    // Stall for 30 us

+    //

+    gBS->Stall (30);

+

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+StatusWaitForBSYClear (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether BSY is clear in the Status Register.

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   StatusRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+

+    StatusRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg.Status

+                      );

+    if ((StatusRegister & BSY) == 0x00) {

+      break;

+    }

+

+    //

+    // Stall for 30 us

+    //

+    gBS->Stall (30);

+

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+AltStatusWaitForBSYClear (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether BSY is clear in the Alternate Status Register.

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   AltStatusRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+

+    AltStatusRegister = ReadPortB (

+                          AtapiScsiPrivate->PciIo,

+                          AtapiScsiPrivate->IoPort->Alt.AltStatus

+                          );

+    if ((AltStatusRegister & BSY) == 0x00) {

+      break;

+    }

+

+    //

+    // Stall for 30 us

+    //

+    gBS->Stall (30);

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+StatusDRDYReady (

+  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,

+  UINT64                       TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRDY is ready in the Status Register. 

+  (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   StatusRegister;

+  UINT8   ErrRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+    StatusRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg.Status

+                      );

+    //

+    //  BSY == 0 , DRDY == 1

+    //

+    if ((StatusRegister & (DRDY | BSY)) == DRDY) {

+      break;

+    }

+

+    if ((StatusRegister & (BSY | ERR)) == ERR) {

+

+      ErrRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg1.Error

+                      );

+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

+        return EFI_ABORTED;

+      }

+    }

+

+    //

+    // Stall for 30 us

+    //

+    gBS->Stall (30);

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+AltStatusDRDYReady (

+  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,

+  UINT64                       TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRDY is ready in the Alternate Status Register. 

+  (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   AltStatusRegister;

+  UINT8   ErrRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+    AltStatusRegister = ReadPortB (

+                          AtapiScsiPrivate->PciIo,

+                          AtapiScsiPrivate->IoPort->Alt.AltStatus

+                          );

+    //

+    //  BSY == 0 , DRDY == 1

+    //

+    if ((AltStatusRegister & (DRDY | BSY)) == DRDY) {

+      break;

+    }

+

+    if ((AltStatusRegister & (BSY | ERR)) == ERR) {

+

+      ErrRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg1.Error

+                      );

+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

+        return EFI_ABORTED;

+      }

+    }

+

+    //

+    // Stall for 30 us

+    //

+    gBS->Stall (30);

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+AtapiPassThruCheckErrorStatus (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate

+  )

+/*++  

+

+Routine Description:

+

+  Check Error Register for Error Information. 

+  

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT8 StatusRegister;

+  UINT8 ErrorRegister;

+

+  StatusRegister = ReadPortB (

+                    AtapiScsiPrivate->PciIo,

+                    AtapiScsiPrivate->IoPort->Reg.Status

+                    );

+

+  DEBUG_CODE_BEGIN ();

+

+    if (StatusRegister & DWF) {

+      DEBUG (

+        (EFI_D_BLKIO,

+        "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",

+        StatusRegister)

+        );

+    }

+

+    if (StatusRegister & CORR) {

+      DEBUG (

+        (EFI_D_BLKIO,

+        "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",

+        StatusRegister)

+        );

+    }

+

+    if (StatusRegister & ERR) {

+      ErrorRegister = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg1.Error);

+

+

+      if (ErrorRegister & BBK_ERR) {

+        DEBUG (

+          (EFI_D_BLKIO,

+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",

+          ErrorRegister)

+          );

+      }

+

+      if (ErrorRegister & UNC_ERR) {

+        DEBUG (

+          (EFI_D_BLKIO,

+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",

+          ErrorRegister)

+          );

+      }

+

+      if (ErrorRegister & MC_ERR) {

+        DEBUG (

+          (EFI_D_BLKIO,

+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",

+          ErrorRegister)

+          );

+      }

+

+      if (ErrorRegister & ABRT_ERR) {

+        DEBUG (

+          (EFI_D_BLKIO,

+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",

+          ErrorRegister)

+          );

+      }

+

+      if (ErrorRegister & TK0NF_ERR) {

+        DEBUG (

+          (EFI_D_BLKIO,

+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",

+          ErrorRegister)

+          );

+      }

+

+      if (ErrorRegister & AMNF_ERR) {

+        DEBUG (

+          (EFI_D_BLKIO,

+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",

+          ErrorRegister)

+          );

+       }

+    }

+

+  DEBUG_CODE_END ();

+

+  if ((StatusRegister & (ERR | DWF | CORR)) == 0) {

+    return EFI_SUCCESS;

+  }

+

+

+  return EFI_DEVICE_ERROR;

+}

+

+

+/**

+  Installs Scsi Pass Thru and/or Ext Scsi Pass Thru 

+  protocols based on feature flags. 

+

+  @param Controller         The controller handle to 

+                            install these protocols on.

+  @param AtapiScsiPrivate   A pointer to the protocol private

+                            data structure.

+

+  @retval EFI_SUCCESS       The installation succeeds. 

+  @retval other             The installation fails. 

+   

+**/

+EFI_STATUS

+InstallScsiPassThruProtocols (

+  IN EFI_HANDLE                     *ControllerHandle,

+  IN ATAPI_SCSI_PASS_THRU_DEV       *AtapiScsiPrivate

+  )

+{

+  EFI_STATUS                        Status;

+  EFI_SCSI_PASS_THRU_PROTOCOL       *ScsiPassThru;

+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *ExtScsiPassThru;

+

+  ScsiPassThru = &AtapiScsiPrivate->ScsiPassThru;

+  ExtScsiPassThru = &AtapiScsiPrivate->ExtScsiPassThru;

+

+  if (FeaturePcdGet (PcdSupportScsiPassThru)) {

+    ScsiPassThru = CopyMem (ScsiPassThru, &gScsiPassThruProtocolTemplate, sizeof (*ScsiPassThru));

+    if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {

+      ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));

+      Status = gBS->InstallMultipleProtocolInterfaces (

+                      ControllerHandle,

+                      &gEfiScsiPassThruProtocolGuid,

+                      ScsiPassThru,

+                      &gEfiExtScsiPassThruProtocolGuid,

+                      ExtScsiPassThru,

+                      NULL

+                      );

+    } else {

+      Status = gBS->InstallMultipleProtocolInterfaces (

+                      ControllerHandle,

+                      &gEfiScsiPassThruProtocolGuid,

+                      ScsiPassThru,

+                      NULL

+                      );

+    }

+  } else {

+    if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {

+      ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));

+      Status = gBS->InstallMultipleProtocolInterfaces (

+                      ControllerHandle,

+                      &gEfiExtScsiPassThruProtocolGuid,

+                      ExtScsiPassThru,

+                      NULL

+                      );

+    } else {

+      //

+      // This driver must support either ScsiPassThru or

+      // ExtScsiPassThru protocols

+      // 

+      ASSERT (FALSE);

+      Status = EFI_UNSUPPORTED;

+    }

+  }

+

+  return Status;

+}

+

+/**

+  The user Entry Point for module AtapiPassThru. The user code starts with this function.

+

+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.

+  @param[in] SystemTable    A pointer to the EFI System Table.

+

+  @retval EFI_SUCCESS       The entry point is executed successfully.

+  @retval other             Some error occurs when executing this entry point.

+

+**/

+EFI_STATUS

+EFIAPI

+InitializeAtapiPassThru(

+  IN EFI_HANDLE           ImageHandle,

+  IN EFI_SYSTEM_TABLE     *SystemTable

+  )

+{

+  EFI_STATUS              Status;

+

+  //

+  // Install driver model protocol(s).

+  //

+  Status = EfiLibInstallDriverBindingComponentName2 (

+             ImageHandle,

+             SystemTable,

+             &gAtapiScsiPassThruDriverBinding,

+             ImageHandle,

+             &gAtapiScsiPassThruComponentName,

+             &gAtapiScsiPassThruComponentName2

+             );

+  ASSERT_EFI_ERROR (Status);

+

+  return Status;

+}

diff --git a/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h b/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h
new file mode 100644
index 0000000..2187580
--- /dev/null
+++ b/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h
@@ -0,0 +1,1625 @@
+/** @file

+  Copyright (c) 2006, Intel Corporation

+  All rights reserved. This program and the accompanying materials

+  are licensed and made available under the terms and conditions of the BSD License

+  which accompanies this distribution.  The full text of the license may be found at

+  http://opensource.org/licenses/bsd-license.php

+

+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+  Module Name:  AtapiPassThru.h

+

+**/

+

+#ifndef _APT_H

+#define _APT_H

+

+

+

+#include <Uefi.h>

+

+#include <Protocol/ScsiPassThru.h>

+#include <Protocol/ScsiPassThruExt.h>

+#include <Protocol/PciIo.h>

+

+#include <Library/DebugLib.h>

+#include <Library/UefiDriverEntryPoint.h>

+#include <Library/BaseLib.h>

+#include <Library/UefiLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/PcdLib.h>

+#include <IndustryStandard/pci22.h>

+

+///

+/// bit definition

+///

+#define bit(a)        (1 << (a))

+

+#define MAX_TARGET_ID 4

+

+//

+// IDE Registers

+//

+typedef union {

+  UINT16  Command;        /* when write */

+  UINT16  Status;         /* when read */

+} IDE_CMD_OR_STATUS;

+

+typedef union {

+  UINT16  Error;          /* when read */

+  UINT16  Feature;        /* when write */

+} IDE_ERROR_OR_FEATURE;

+

+typedef union {

+  UINT16  AltStatus;      /* when read */

+  UINT16  DeviceControl;  /* when write */

+} IDE_AltStatus_OR_DeviceControl;

+

+

+typedef enum {

+  IdePrimary    = 0,

+  IdeSecondary  = 1,

+  IdeMaxChannel = 2

+} EFI_IDE_CHANNEL;

+

+///

+

+

+//

+// Bit definitions in Programming Interface byte of the Class Code field

+// in PCI IDE controller's Configuration Space

+//

+#define IDE_PRIMARY_OPERATING_MODE            BIT0

+#define IDE_PRIMARY_PROGRAMMABLE_INDICATOR    BIT1

+#define IDE_SECONDARY_OPERATING_MODE          BIT2

+#define IDE_SECONDARY_PROGRAMMABLE_INDICATOR  BIT3

+

+

+#define ATAPI_MAX_CHANNEL 2

+

+///

+/// IDE registers set

+///

+typedef struct {

+  UINT16                          Data;

+  IDE_ERROR_OR_FEATURE            Reg1;

+  UINT16                          SectorCount;

+  UINT16                          SectorNumber;

+  UINT16                          CylinderLsb;

+  UINT16                          CylinderMsb;

+  UINT16                          Head;

+  IDE_CMD_OR_STATUS               Reg;

+  IDE_AltStatus_OR_DeviceControl  Alt;

+  UINT16                          DriveAddress;

+} IDE_BASE_REGISTERS;

+

+#define ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE  EFI_SIGNATURE_32 ('a', 's', 'p', 't')

+

+typedef struct {

+  UINTN                            Signature;

+  EFI_HANDLE                       Handle;

+  EFI_SCSI_PASS_THRU_PROTOCOL      ScsiPassThru;

+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL  ExtScsiPassThru;

+  EFI_PCI_IO_PROTOCOL              *PciIo;

+  UINT64                           OriginalPciAttributes;

+  //

+  // Local Data goes here

+  //

+  IDE_BASE_REGISTERS               *IoPort;

+  IDE_BASE_REGISTERS               AtapiIoPortRegisters[2];

+  UINT32                           LatestTargetId;

+  UINT64                           LatestLun;

+} ATAPI_SCSI_PASS_THRU_DEV;

+

+//

+// IDE registers' base addresses

+//

+typedef struct {

+  UINT16  CommandBlockBaseAddr;

+  UINT16  ControlBlockBaseAddr;

+} IDE_REGISTERS_BASE_ADDR;

+

+#define ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS(a) \

+  CR (a, \

+      ATAPI_SCSI_PASS_THRU_DEV, \

+      ScsiPassThru, \

+      ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE \

+      )

+

+#define ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS(a) \

+  CR (a, \

+      ATAPI_SCSI_PASS_THRU_DEV, \

+      ExtScsiPassThru, \

+      ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE \

+      )

+

+//

+// Global Variables

+//

+extern EFI_DRIVER_BINDING_PROTOCOL   gAtapiScsiPassThruDriverBinding;

+extern EFI_COMPONENT_NAME_PROTOCOL   gAtapiScsiPassThruComponentName;

+extern EFI_COMPONENT_NAME2_PROTOCOL  gAtapiScsiPassThruComponentName2;

+

+//

+// ATAPI Command op code

+//

+#define OP_INQUIRY                      0x12

+#define OP_LOAD_UNLOAD_CD               0xa6

+#define OP_MECHANISM_STATUS             0xbd

+#define OP_MODE_SELECT_10               0x55

+#define OP_MODE_SENSE_10                0x5a

+#define OP_PAUSE_RESUME                 0x4b

+#define OP_PLAY_AUDIO_10                0x45

+#define OP_PLAY_AUDIO_MSF               0x47

+#define OP_PLAY_CD                      0xbc

+#define OP_PLAY_CD_MSF                  0xb4

+#define OP_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e

+#define OP_READ_10                      0x28

+#define OP_READ_12                      0xa8

+#define OP_READ_CAPACITY                0x25

+#define OP_READ_CD                      0xbe

+#define OP_READ_CD_MSF                  0xb9

+#define OP_READ_HEADER                  0x44

+#define OP_READ_SUB_CHANNEL             0x42

+#define OP_READ_TOC                     0x43

+#define OP_REQUEST_SENSE                0x03

+#define OP_SCAN                         0xba

+#define OP_SEEK_10                      0x2b

+#define OP_SET_CD_SPEED                 0xbb

+#define OP_STOPPLAY_SCAN                0x4e

+#define OP_START_STOP_UNIT              0x1b

+#define OP_TEST_UNIT_READY              0x00

+

+#define OP_FORMAT_UNIT                  0x04

+#define OP_READ_FORMAT_CAPACITIES       0x23

+#define OP_VERIFY                       0x2f

+#define OP_WRITE_10                     0x2a

+#define OP_WRITE_12                     0xaa

+#define OP_WRITE_AND_VERIFY             0x2e

+

+//

+// ATA Command

+//

+#define ATAPI_SOFT_RESET_CMD  0x08

+

+typedef enum {

+  DataIn  = 0,

+  DataOut = 1,

+  DataBi  = 2,

+  NoData  = 3,

+  End     = 0xff

+} DATA_DIRECTION;

+

+typedef struct {

+  UINT8           OpCode;

+  DATA_DIRECTION  Direction;

+} SCSI_COMMAND_SET;

+

+#define MAX_CHANNEL         2

+

+#define ValidCdbLength(Len) ((Len) == 6 || (Len) == 10 || (Len) == 12) ? 1 : 0

+

+//

+// IDE registers bit definitions

+//

+// ATA Err Reg bitmap

+//

+#define BBK_ERR   bit (7) ///< Bad block detected

+#define UNC_ERR   bit (6) ///< Uncorrectable Data

+#define MC_ERR    bit (5) ///< Media Change

+#define IDNF_ERR  bit (4) ///< ID Not Found

+#define MCR_ERR   bit (3) ///< Media Change Requested

+#define ABRT_ERR  bit (2) ///< Aborted Command

+#define TK0NF_ERR bit (1) ///< Track 0 Not Found

+#define AMNF_ERR  bit (0) ///< Address Mark Not Found

+

+//

+// ATAPI Err Reg bitmap

+//

+#define SENSE_KEY_ERR (bit (7) | bit (6) | bit (5) | bit (4))

+#define EOM_ERR bit (1) ///< End of Media Detected

+#define ILI_ERR bit (0) ///< Illegal Length Indication

+

+//

+// Device/Head Reg

+//

+#define LBA_MODE  bit (6)

+#define DEV       bit (4)

+#define HS3       bit (3)

+#define HS2       bit (2)

+#define HS1       bit (1)

+#define HS0       bit (0)

+#define CHS_MODE  (0)

+#define DRV0      (0)

+#define DRV1      (1)

+#define MST_DRV   DRV0

+#define SLV_DRV   DRV1

+

+//

+// Status Reg

+//

+#define BSY   bit (7) ///< Controller Busy

+#define DRDY  bit (6) ///< Drive Ready

+#define DWF   bit (5) ///< Drive Write Fault

+#define DSC   bit (4) ///< Disk Seek Complete

+#define DRQ   bit (3) ///< Data Request

+#define CORR  bit (2) ///< Corrected Data

+#define IDX   bit (1) ///< Index

+#define ERR   bit (0) ///< Error

+#define CHECK bit (0) ///< Check bit for ATAPI Status Reg

+

+//

+// Device Control Reg

+//

+#define SRST  bit (2) ///< Software Reset

+#define IEN_L bit (1) ///< Interrupt Enable

+

+//

+// ATAPI Feature Register

+//

+#define OVERLAP bit (1)

+#define DMA     bit (0)

+

+//

+// ATAPI Interrupt Reason Reson Reg (ATA Sector Count Register)

+//

+#define RELEASE     bit (2)

+#define IO          bit (1)

+#define CoD         bit (0)

+

+#define PACKET_CMD  0xA0

+

+#define DEFAULT_CMD (0xa0)

+//

+// default content of device control register, disable INT

+//

+#define DEFAULT_CTL           (0x0a)

+#define MAX_ATAPI_BYTE_COUNT  (0xfffe)

+

+//

+// function prototype

+//

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverBindingSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  );

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverBindingStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  );

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverBindingStop (

+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,

+  IN  EFI_HANDLE                      Controller,

+  IN  UINTN                           NumberOfChildren,

+  IN  EFI_HANDLE                      *ChildHandleBuffer

+  );

+

+//

+// EFI Component Name Functions

+//

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 3066 or ISO 639-2 language code format.

+

+  @param  DriverName[out]       A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,

+  IN  CHAR8                        *Language,

+  OUT CHAR16                       **DriverName

+  );

+

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  ControllerHandle[in]  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+

+  @param  ChildHandle[in]       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 3066 or ISO 639-2 language code format.

+

+  @param  ControllerName[out]   A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+

+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,

+  IN  EFI_HANDLE                                      ControllerHandle,

+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,

+  IN  CHAR8                                           *Language,

+  OUT CHAR16                                          **ControllerName

+  );

+

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverEntryPoint (

+  IN EFI_HANDLE         ImageHandle,

+  IN EFI_SYSTEM_TABLE   *SystemTable

+  )

+ /*++

+

+Routine Description:

+

+  Entry point for EFI drivers.

+

+Arguments:

+

+  ImageHandle - EFI_HANDLE

+  SystemTable - EFI_SYSTEM_TABLE

+

+Returns:

+

+  EFI_SUCCESS

+  Others 

+

+--*/

+;

+

+EFI_STATUS

+RegisterAtapiScsiPassThru (

+  IN  EFI_DRIVER_BINDING_PROTOCOL *This,

+  IN  EFI_HANDLE                  Controller,

+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,

+  IN  UINT64                      OriginalPciAttributes

+  )

+/*++

+

+Routine Description:

+  Attaches SCSI Pass Thru Protocol for specified IDE channel.

+    

+Arguments:

+  This              - Protocol instance pointer.

+  Controller        - Parent device handle to the IDE channel.    

+  PciIo             - PCI I/O protocol attached on the "Controller".                        

+  

+Returns:

+  Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruFunction (

+  IN EFI_SCSI_PASS_THRU_PROTOCOL                        *This,

+  IN UINT32                                             Target,

+  IN UINT64                                             Lun,

+  IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET         *Packet,

+  IN EFI_EVENT                                          Event OPTIONAL

+  )

+/*++

+

+Routine Description:

+

+  Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.

+

+Arguments:

+

+  This:     The EFI_SCSI_PASS_THRU_PROTOCOL instance.

+  Target:   The Target ID of the ATAPI device to send the SCSI 

+            Request Packet. To ATAPI devices attached on an IDE

+            Channel, Target ID 0 indicates Master device;Target

+            ID 1 indicates Slave device.

+  Lun:      The LUN of the ATAPI device to send the SCSI Request

+            Packet. To the ATAPI device, Lun is always 0.

+  Packet:   The SCSI Request Packet to send to the ATAPI device 

+            specified by Target and Lun.

+  Event:    If non-blocking I/O is not supported then Event is ignored, 

+            and blocking I/O is performed.

+            If Event is NULL, then blocking I/O is performed.

+            If Event is not NULL and non blocking I/O is supported, 

+            then non-blocking I/O is performed, and Event will be signaled 

+            when the SCSI Request Packet completes.      

+

+Returns:  

+

+   EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruGetNextDevice (

+  IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN OUT UINT32                      *Target,

+  IN OUT UINT64                      *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to retrieve the list of legal Target IDs for SCSI devices 

+  on a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - On input, a pointer to the Target ID of a SCSI 

+                          device present on the SCSI channel.  On output, 

+                          a pointer to the Target ID of the next SCSI device

+                          present on a SCSI channel.  An input value of 

+                          0xFFFFFFFF retrieves the Target ID of the first 

+                          SCSI device present on a SCSI channel.

+  Lun                   - On input, a pointer to the LUN of a SCSI device

+                          present on the SCSI channel. On output, a pointer

+                          to the LUN of the next SCSI device present on 

+                          a SCSI channel.

+Returns:

+

+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device 

+                          on the SCSI channel was returned in Target and Lun.

+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.

+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not

+                           returned on a previous call to GetNextDevice().

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruBuildDevicePath (

+  IN     EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN     UINT32                         Target,

+  IN     UINT64                         Lun,

+  IN OUT EFI_DEVICE_PATH_PROTOCOL       **DevicePath

+  )

+/*++

+

+Routine Description:

+

+  Used to allocate and build a device path node for a SCSI device 

+  on a SCSI channel. Would not build device path for a SCSI Host Controller.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device for which

+                          a device path node is to be allocated and built.

+  Lun                   - The LUN of the SCSI device for which a device 

+                          path node is to be allocated and built.

+  DevicePath            - A pointer to a single device path node that 

+                          describes the SCSI device specified by 

+                          Target and Lun. This function is responsible 

+                          for allocating the buffer DevicePath with the boot

+                          service AllocatePool().  It is the caller's 

+                          responsibility to free DevicePath when the caller

+                          is finished with DevicePath.    

+  Returns:

+  EFI_SUCCESS           - The device path node that describes the SCSI device

+                          specified by Target and Lun was allocated and 

+                          returned in DevicePath.

+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does

+                          not exist on the SCSI channel.

+  EFI_INVALID_PARAMETER - DevicePath is NULL.

+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate 

+                          DevicePath.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruGetTargetLun (

+  IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,

+  OUT UINT32                         *Target,

+  OUT UINT64                         *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to translate a device path node to a Target ID and LUN.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  DevicePath            - A pointer to the device path node that 

+                          describes a SCSI device on the SCSI channel.

+  Target                - A pointer to the Target ID of a SCSI device 

+                          on the SCSI channel. 

+  Lun                   - A pointer to the LUN of a SCSI device on 

+                          the SCSI channel.    

+Returns:

+

+  EFI_SUCCESS           - DevicePath was successfully translated to a 

+                          Target ID and LUN, and they were returned 

+                          in Target and Lun.

+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.

+  EFI_UNSUPPORTED       - This driver does not support the device path 

+                          node type in DevicePath.

+  EFI_NOT_FOUND         - A valid translation from DevicePath to a 

+                          Target ID and LUN does not exist.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruResetChannel (

+  IN  EFI_SCSI_PASS_THRU_PROTOCOL   *This

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI channel.This operation resets all the 

+  SCSI devices connected to the SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+

+Returns:

+

+  EFI_SUCCESS           - The SCSI channel was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support 

+                          a channel reset operation.

+  EFI_DEVICE_ERROR      - A device error occurred while 

+                          attempting to reset the SCSI channel.

+  EFI_TIMEOUT           - A timeout occurred while attempting 

+                          to reset the SCSI channel.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruResetTarget (

+  IN EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN UINT32                         Target,

+  IN UINT64                         Lun

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI device that is connected to a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device to reset. 

+  Lun                   - The LUN of the SCSI device to reset.

+    

+Returns:

+

+  EFI_SUCCESS           - The SCSI device specified by Target and 

+                          Lun was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support a target

+                          reset operation.

+  EFI_INVALID_PARAMETER - Target or Lun are invalid.

+  EFI_DEVICE_ERROR      - A device error occurred while attempting 

+                          to reset the SCSI device specified by Target 

+                          and Lun.

+  EFI_TIMEOUT           - A timeout occurred while attempting to reset 

+                          the SCSI device specified by Target and Lun.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruFunction (

+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                    *This,

+  IN UINT8                                              *Target,

+  IN UINT64                                             Lun,

+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET     *Packet,

+  IN EFI_EVENT                                          Event OPTIONAL

+  )

+/*++

+

+Routine Description:

+

+  Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.

+

+Arguments:

+

+  This:     The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.

+  Target:   The Target ID of the ATAPI device to send the SCSI 

+            Request Packet. To ATAPI devices attached on an IDE

+            Channel, Target ID 0 indicates Master device;Target

+            ID 1 indicates Slave device.

+  Lun:      The LUN of the ATAPI device to send the SCSI Request

+            Packet. To the ATAPI device, Lun is always 0.

+  Packet:   The SCSI Request Packet to send to the ATAPI device 

+            specified by Target and Lun.

+  Event:    If non-blocking I/O is not supported then Event is ignored, 

+            and blocking I/O is performed.

+            If Event is NULL, then blocking I/O is performed.

+            If Event is not NULL and non blocking I/O is supported, 

+            then non-blocking I/O is performed, and Event will be signaled 

+            when the SCSI Request Packet completes.      

+

+Returns:  

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruGetNextTargetLun (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN OUT UINT8                           **Target,

+  IN OUT UINT64                          *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to retrieve the list of legal Target IDs for SCSI devices 

+  on a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - On input, a pointer to the Target ID of a SCSI 

+                          device present on the SCSI channel.  On output, 

+                          a pointer to the Target ID of the next SCSI device

+                          present on a SCSI channel.  An input value of 

+                          0xFFFFFFFF retrieves the Target ID of the first 

+                          SCSI device present on a SCSI channel.

+  Lun                   - On input, a pointer to the LUN of a SCSI device

+                          present on the SCSI channel. On output, a pointer

+                          to the LUN of the next SCSI device present on 

+                          a SCSI channel.

+Returns:

+

+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device 

+                          on the SCSI channel was returned in Target and Lun.

+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.

+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not

+                           returned on a previous call to GetNextDevice().

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruBuildDevicePath (

+  IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN     UINT8                              *Target,

+  IN     UINT64                             Lun,

+  IN OUT EFI_DEVICE_PATH_PROTOCOL           **DevicePath

+  )

+/*++

+

+Routine Description:

+

+  Used to allocate and build a device path node for a SCSI device 

+  on a SCSI channel. Would not build device path for a SCSI Host Controller.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device for which

+                          a device path node is to be allocated and built.

+  Lun                   - The LUN of the SCSI device for which a device 

+                          path node is to be allocated and built.

+  DevicePath            - A pointer to a single device path node that 

+                          describes the SCSI device specified by 

+                          Target and Lun. This function is responsible 

+                          for allocating the buffer DevicePath with the boot

+                          service AllocatePool().  It is the caller's 

+                          responsibility to free DevicePath when the caller

+                          is finished with DevicePath.    

+  Returns:

+  EFI_SUCCESS           - The device path node that describes the SCSI device

+                          specified by Target and Lun was allocated and 

+                          returned in DevicePath.

+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does

+                          not exist on the SCSI channel.

+  EFI_INVALID_PARAMETER - DevicePath is NULL.

+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate 

+                          DevicePath.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruGetTargetLun (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,

+  OUT UINT8                          **Target,

+  OUT UINT64                         *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to translate a device path node to a Target ID and LUN.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  DevicePath            - A pointer to the device path node that 

+                          describes a SCSI device on the SCSI channel.

+  Target                - A pointer to the Target ID of a SCSI device 

+                          on the SCSI channel. 

+  Lun                   - A pointer to the LUN of a SCSI device on 

+                          the SCSI channel.    

+Returns:

+

+  EFI_SUCCESS           - DevicePath was successfully translated to a 

+                          Target ID and LUN, and they were returned 

+                          in Target and Lun.

+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.

+  EFI_UNSUPPORTED       - This driver does not support the device path 

+                          node type in DevicePath.

+  EFI_NOT_FOUND         - A valid translation from DevicePath to a 

+                          Target ID and LUN does not exist.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruResetChannel (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *This

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI channel.This operation resets all the 

+  SCSI devices connected to the SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+

+Returns:

+

+  EFI_SUCCESS           - The SCSI channel was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support 

+                          a channel reset operation.

+  EFI_DEVICE_ERROR      - A device error occurred while 

+                          attempting to reset the SCSI channel.

+  EFI_TIMEOUT           - A timeout occurred while attempting 

+                          to reset the SCSI channel.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruResetTarget (

+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN UINT8                              *Target,

+  IN UINT64                             Lun

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI device that is connected to a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device to reset. 

+  Lun                   - The LUN of the SCSI device to reset.

+    

+Returns:

+

+  EFI_SUCCESS           - The SCSI device specified by Target and 

+                          Lun was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support a target

+                          reset operation.

+  EFI_INVALID_PARAMETER - Target or Lun are invalid.

+  EFI_DEVICE_ERROR      - A device error occurred while attempting 

+                          to reset the SCSI device specified by Target 

+                          and Lun.

+  EFI_TIMEOUT           - A timeout occurred while attempting to reset 

+                          the SCSI device specified by Target and Lun.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruGetNextTarget (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN OUT UINT8                           **Target

+  )

+/*++

+

+Routine Description:

+  Used to retrieve the list of legal Target IDs for SCSI devices 

+  on a SCSI channel.

+

+Arguments:

+  This                  - Protocol instance pointer.

+  Target                - On input, a pointer to the Target ID of a SCSI 

+                          device present on the SCSI channel.  On output, 

+                          a pointer to the Target ID of the next SCSI device

+                           present on a SCSI channel.  An input value of 

+                           0xFFFFFFFF retrieves the Target ID of the first 

+                           SCSI device present on a SCSI channel.

+  Lun                   - On input, a pointer to the LUN of a SCSI device

+                          present on the SCSI channel. On output, a pointer

+                          to the LUN of the next SCSI device present on 

+                          a SCSI channel.

+    

+Returns:

+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device 

+                          on the SCSI channel was returned in Target and Lun.

+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.

+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not

+                          returned on a previous call to GetNextDevice().

+

+--*/

+;

+

+EFI_STATUS

+CheckSCSIRequestPacket (

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet

+  )

+/*++

+

+Routine Description:

+

+  Checks the parameters in the SCSI Request Packet to make sure

+  they are valid for a SCSI Pass Thru request.

+

+Arguments:

+

+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+SubmitBlockingIoCommand (

+  ATAPI_SCSI_PASS_THRU_DEV                  *AtapiScsiPrivate,

+  UINT32                                    Target,

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet

+  )

+/*++

+

+Routine Description:

+

+  Performs blocking I/O request.

+    

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Target:             The Target ID of the ATAPI device to send the SCSI 

+                      Request Packet. To ATAPI devices attached on an IDE

+                      Channel, Target ID 0 indicates Master device;Target

+                      ID 1 indicates Slave device.

+  Packet:             The SCSI Request Packet to send to the ATAPI device 

+                      specified by Target.

+  

+  Returns:            EFI_STATUS  

+

+--*/

+;

+

+BOOLEAN

+IsCommandValid (

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet

+  )

+ /*++

+

+Routine Description:

+

+  Checks the requested SCSI command: 

+  Is it supported by this driver?

+  Is the Data transfer direction reasonable?

+

+Arguments:

+

+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+CheckExtSCSIRequestPacket (

+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet

+  )

+/*++

+

+Routine Description:

+

+  Checks the parameters in the SCSI Request Packet to make sure

+  they are valid for a SCSI Pass Thru request.

+

+Arguments:

+

+  Packet       - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET

+  

+Returns:

+  

+  EFI_STATUS

+

+--*/

+;

+

+

+BOOLEAN

+IsExtCommandValid (

+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet

+  )

+/*++

+  

+Routine Description:

+

+  Checks the requested SCSI command: 

+  Is it supported by this driver?

+  Is the Data transfer direction reasonable?

+

+Arguments:

+

+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+SubmitExtBlockingIoCommand (

+  ATAPI_SCSI_PASS_THRU_DEV                      *AtapiScsiPrivate,

+  UINT8                                         Target,

+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet

+  )

+/*++

+

+Routine Description:

+

+  Performs blocking I/O request.

+    

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Target:             The Target ID of the ATAPI device to send the SCSI 

+                      Request Packet. To ATAPI devices attached on an IDE

+                      Channel, Target ID 0 indicates Master device;Target

+                      ID 1 indicates Slave device.

+  Packet:             The SCSI Request Packet to send to the ATAPI device 

+                      specified by Target.

+  

+  Returns:            EFI_STATUS  

+  

+--*/

+;

+

+EFI_STATUS

+RequestSenseCommand (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT32                      Target,

+  UINT64                      Timeout,

+  VOID                        *SenseData,

+  UINT8                       *SenseDataLength

+  )

+/*++

+

+Routine Description:

+

+  Sumbit request sense command

+

+Arguments:

+

+  AtapiScsiPrivate  - The pionter of ATAPI_SCSI_PASS_THRU_DEV

+  Target            - The target ID

+  Timeout           - The time to complete the command

+  SenseData         - The buffer to fill in sense data

+  SenseDataLength   - The length of buffer

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AtapiPacketCommand (

+  ATAPI_SCSI_PASS_THRU_DEV                  *AtapiScsiPrivate,

+  UINT32                                    Target,

+  UINT8                                     *PacketCommand,

+  VOID                                      *Buffer,

+  UINT32                                    *ByteCount,

+  DATA_DIRECTION                            Direction,

+  UINT64                                    TimeOutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Submits ATAPI command packet to the specified ATAPI device.

+    

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Target:             The Target ID of the ATAPI device to send the SCSI 

+                      Request Packet. To ATAPI devices attached on an IDE

+                      Channel, Target ID 0 indicates Master device;Target

+                      ID 1 indicates Slave device.

+  PacketCommand:      Points to the ATAPI command packet.

+  Buffer:             Points to the transferred data.

+  ByteCount:          When input,indicates the buffer size; when output,

+                      indicates the actually transferred data size.

+  Direction:          Indicates the data transfer direction. 

+  TimeoutInMicroSeconds:

+                      The timeout, in micro second units, to use for the 

+                      execution of this ATAPI command.

+                      A TimeoutInMicroSeconds value of 0 means that 

+                      this function will wait indefinitely for the ATAPI 

+                      command to execute.

+                      If TimeoutInMicroSeconds is greater than zero, then 

+                      this function will return EFI_TIMEOUT if the time 

+                      required to execute the ATAPI command is greater 

+                      than TimeoutInMicroSeconds.

+  

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+

+UINT8

+ReadPortB (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port

+  )

+/*++

+

+Routine Description:

+

+  Read one byte from a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  

+Returns:

+

+  A byte read out

+

+--*/

+;

+

+

+UINT16

+ReadPortW (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port

+  )

+/*++

+

+Routine Description:

+

+  Read one word from a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  

+Returns:     

+

+  A word read out

+

+--*/

+;

+

+

+VOID

+WritePortB (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port,

+  IN  UINT8                 Data

+  )

+/*++

+

+Routine Description:

+

+  Write one byte to a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  Data       - The data to write

+  

+Returns:

+ 

+  NONE

+ 

+--*/

+;

+

+

+VOID

+WritePortW (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port,

+  IN  UINT16                Data

+  )

+/*++

+

+Routine Description:

+

+  Write one word to a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  Data       - The data to write

+  

+Returns:

+

+  NONE

+  

+--*/

+;

+

+EFI_STATUS

+StatusDRQClear (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeOutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is clear in the Status Register. (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AltStatusDRQClear (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeOutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is clear in the Alternate Status Register. 

+  (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should 

+  wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+StatusDRQReady (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeOutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is ready in the Status Register. (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AltStatusDRQReady (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeOutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is ready in the Alternate Status Register. 

+  (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+StatusWaitForBSYClear (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether BSY is clear in the Status Register.

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AltStatusWaitForBSYClear (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether BSY is clear in the Alternate Status Register.

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+StatusDRDYReady (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRDY is ready in the Status Register. 

+  (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AltStatusDRDYReady (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRDY is ready in the Alternate Status Register. 

+  (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AtapiPassThruPioReadWriteData (

+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate,

+  UINT16                    *Buffer,

+  UINT32                    *ByteCount,

+  DATA_DIRECTION            Direction,

+  UINT64                    TimeOutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Performs data transfer between ATAPI device and host after the

+  ATAPI command packet is sent.

+    

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.    

+  Buffer:             Points to the transferred data.

+  ByteCount:          When input,indicates the buffer size; when output,

+                      indicates the actually transferred data size.

+  Direction:          Indicates the data transfer direction. 

+  TimeoutInMicroSeconds:

+                      The timeout, in micro second units, to use for the 

+                      execution of this ATAPI command.

+                      A TimeoutInMicroSeconds value of 0 means that 

+                      this function will wait indefinitely for the ATAPI 

+                      command to execute.

+                      If TimeoutInMicroSeconds is greater than zero, then 

+                      this function will return EFI_TIMEOUT if the time 

+                      required to execute the ATAPI command is greater 

+                      than TimeoutInMicroSeconds.

+ Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AtapiPassThruCheckErrorStatus (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate

+  )

+/*++

+

+Routine Description:

+

+  Check Error Register for Error Information. 

+  

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+

+EFI_STATUS

+GetIdeRegistersBaseAddr (

+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,

+  OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr

+  )

+/*++

+

+Routine Description:

+  Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,

+  use fixed addresses. In Native-PCI mode, get base addresses from BARs in

+  the PCI IDE controller's Configuration Space.

+

+Arguments:

+  PciIo             - Pointer to the EFI_PCI_IO_PROTOCOL instance

+  IdeRegsBaseAddr   - Pointer to IDE_REGISTERS_BASE_ADDR to 

+                      receive IDE IO port registers' base addresses

+                      

+Returns:

+

+  EFI_STATUS

+    

+--*/

+;

+

+

+VOID

+InitAtapiIoPortRegisters (

+  IN  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,

+  IN  IDE_REGISTERS_BASE_ADDR      *IdeRegsBaseAddr

+  )

+/*++

+

+Routine Description:

+

+  Initialize each Channel's Base Address of CommandBlock and ControlBlock.

+

+Arguments:

+    

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  IdeRegsBaseAddr             - The pointer of IDE_REGISTERS_BASE_ADDR

+  

+Returns:

+  

+  None

+

+--*/  

+;

+

+/**

+  Installs Scsi Pass Thru and/or Ext Scsi Pass Thru 

+  protocols based on feature flags. 

+

+  @param Controller         The controller handle to 

+                            install these protocols on.

+  @param AtapiScsiPrivate   A pointer to the protocol private

+                            data structure.

+

+  @retval EFI_SUCCESS       The installation succeeds. 

+  @retval other             The installation fails. 

+   

+**/

+EFI_STATUS

+InstallScsiPassThruProtocols (

+  IN EFI_HANDLE                 *ControllerHandle,

+  IN ATAPI_SCSI_PASS_THRU_DEV   *AtapiScsiPrivate

+  );

+

+#endif

diff --git a/OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf b/OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf
new file mode 100644
index 0000000..378624e
--- /dev/null
+++ b/OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf
@@ -0,0 +1,65 @@
+#/** @file

+# Description file for the Atapi Passthru component.

+#

+# This driver simulates SCSI devices with Atapi devices to test the SCSI io

+#  protocol.

+# Copyright (c) 2006 - 2007, Intel Corporation

+#

+#  All rights reserved. This program and the accompanying materials

+#  are licensed and made available under the terms and conditions of the BSD License

+#  which accompanies this distribution. The full text of the license may be found at

+#  http://opensource.org/licenses/bsd-license.php

+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+#

+#

+#**/

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = AtapiPassThru

+  FILE_GUID                      = E49061CE-99A7-41d3-AB3A-36E5CFBAD63E

+  MODULE_TYPE                    = UEFI_DRIVER

+  VERSION_STRING                 = 1.0

+  EDK_RELEASE_VERSION            = 0x00020000

+  EFI_SPECIFICATION_VERSION      = 0x00020000

+

+  ENTRY_POINT                    = InitializeAtapiPassThru

+

+#

+# The following information is for reference only and not required by the build tools.

+#

+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC

+#

+#  DRIVER_BINDING                =  gAtapiScsiPassThruDriverBinding              

+#  COMPONENT_NAME                =  gAtapiScsiPassThruComponentName              

+#

+

+[Sources.common]

+  ComponentName.c

+  AtapiPassThru.c

+  AtapiPassThru.h

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  OptionRomPkg/OptionRomPkg.dec

+

+[LibraryClasses]

+  UefiBootServicesTableLib

+  MemoryAllocationLib

+  BaseMemoryLib

+  UefiLib

+  BaseLib

+  UefiDriverEntryPoint

+  DebugLib

+

+

+[Protocols]

+  gEfiScsiPassThruProtocolGuid                  # PROTOCOL BY_START

+  gEfiExtScsiPassThruProtocolGuid               # PROTOCOL BY_START

+  gEfiPciIoProtocolGuid                         # PROTOCOL TO_START

+

+[FeaturePcd]

+  gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru

+  gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru

diff --git a/OptionRomPkg/AtapiPassThruDxe/ComponentName.c b/OptionRomPkg/AtapiPassThruDxe/ComponentName.c
new file mode 100644
index 0000000..2f04f0b
--- /dev/null
+++ b/OptionRomPkg/AtapiPassThruDxe/ComponentName.c
@@ -0,0 +1,175 @@
+/** @file

+  Copyright (c) 2006, Intel Corporation                                                         

+  All rights reserved. This program and the accompanying materials                          

+  are licensed and made available under the terms and conditions of the BSD License         

+  which accompanies this distribution.  The full text of the license may be found at        

+  http://opensource.org/licenses/bsd-license.php                                            

+

+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     

+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             

+

+  Module Name:  ComponentName.c

+

+**/

+#include "AtapiPassThru.h"

+

+//

+// EFI Component Name Protocol

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gAtapiScsiPassThruComponentName = {

+  AtapiScsiPassThruComponentNameGetDriverName,

+  AtapiScsiPassThruComponentNameGetControllerName,

+  "eng"

+};

+

+//

+// EFI Component Name 2 Protocol

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gAtapiScsiPassThruComponentName2 = {

+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) AtapiScsiPassThruComponentNameGetDriverName,

+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) AtapiScsiPassThruComponentNameGetControllerName,

+  "en"

+};

+

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtapiScsiPassThruDriverNameTable[] = {

+  { "eng;en", (CHAR16 *) L"ATAPI SCSI Pass Thru Driver" },

+  { NULL , NULL }

+};

+

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 3066 or ISO 639-2 language code format.

+

+  @param  DriverName[out]       A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,

+  IN  CHAR8                        *Language,

+  OUT CHAR16                       **DriverName

+  )

+{

+  return LookupUnicodeString2 (

+           Language,

+           This->SupportedLanguages,

+           mAtapiScsiPassThruDriverNameTable,

+           DriverName,

+           (BOOLEAN)(This == &gAtapiScsiPassThruComponentName)

+           );

+}

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  ControllerHandle[in]  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+

+  @param  ChildHandle[in]       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 3066 or ISO 639-2 language code format.

+

+  @param  ControllerName[out]   A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+

+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,

+  IN  EFI_HANDLE                                      ControllerHandle,

+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,

+  IN  CHAR8                                           *Language,

+  OUT CHAR16                                          **ControllerName

+  )

+{

+  return EFI_UNSUPPORTED;

+}

diff --git a/OptionRomPkg/OptionRomPkg.dec b/OptionRomPkg/OptionRomPkg.dec
new file mode 100644
index 0000000..7ada9ec
--- /dev/null
+++ b/OptionRomPkg/OptionRomPkg.dec
@@ -0,0 +1,31 @@
+#/** @file

+# Option Rom Package Reference Implementations.

+#

+# This package is designed to interoperate with the EDK II open source project

+# at http://www.tianocore.org, and this package is required to build PCI compliant

+# Option ROM image for all CPU architectures, including EBC target.

+# A single driver can support mixes of EFI 1.1, UEFI 2.0 and UEFI 2.1. 

+#

+# Copyright (c) 2007, Intel Corporation.

+#

+# All rights reserved. This program and the accompanying materials

+# are licensed and made available under the terms and conditions of the BSD License

+# which accompanies this distribution. The full text of the license may be found at

+# http://opensource.org/licenses/bsd-license.php

+#

+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+#

+#**/

+

+[Defines]

+  DEC_SPECIFICATION              = 0x00010005

+  PACKAGE_NAME                   = OptionRomPkg

+  PACKAGE_GUID                   = AA3865E8-7F30-4f59-8696-99F560101852

+  PACKAGE_VERSION                = 0.1

+

+[PcdsFeatureFlag.common]

+  gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru|TRUE|BOOLEAN|0x00010001

+  gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru|TRUE|BOOLEAN|0x00010002

+

+

diff --git a/OptionRomPkg/OptionRomPkg.dsc b/OptionRomPkg/OptionRomPkg.dsc
new file mode 100644
index 0000000..ed53dbe
--- /dev/null
+++ b/OptionRomPkg/OptionRomPkg.dsc
@@ -0,0 +1,92 @@
+#/** @file

+# Option Rom Package build validation file for All Architectures.

+#

+# This package is designed to interoperate with the EDK II open source project

+# at http://www.tianocore.org, and this package is required to build PCI compliant

+# Option ROM image for all CPU architectures, including EBC target.

+# A single driver can support mixes of EFI 1.1, UEFI 2.0 and UEFI 2.1. 

+#

+# Copyright (c) 2007, Intel Corporation

+#

+# All rights reserved. This program and the accompanying materials

+# are licensed and made available under the terms and conditions of the BSD License

+# which accompanies this distribution. The full text of the license may be found at

+# http://opensource.org/licenses/bsd-license.php

+#

+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+#

+#**/

+

+################################################################################

+#

+# Defines Section - statements that will be processed to create a Makefile.

+#

+################################################################################

+[Defines]

+  PLATFORM_NAME                  = OptionRomPkg

+  PLATFORM_GUID                  = C7B25F37-B1F4-4c46-99CB-3EA7DCF5FCDC

+  PLATFORM_VERSION               = 0.1

+  DSC_SPECIFICATION              = 0x00010005

+  OUTPUT_DIRECTORY               = Build/OptionRomPkg

+  SUPPORTED_ARCHITECTURES        = IA32|IPF|X64|EBC

+  BUILD_TARGETS                  = DEBUG|RELEASE

+  SKUID_IDENTIFIER               = DEFAULT

+

+################################################################################

+#

+# SKU Identification section - list of all SKU IDs supported by this

+#                              Platform.

+#

+################################################################################

+[SkuIds]

+  0|DEFAULT              # The entry: 0|DEFAULT is reserved and always required.

+

+[LibraryClasses.common]

+  DebugLib|IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf

+  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf

+  CpuLib|MdePkg/Library/CpuLib/CpuLib.inf

+  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf

+  PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf

+  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf

+  TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf

+  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf

+  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf

+  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf

+  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf

+  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf

+  MemoryAllocationLib|MdePkg/Library/DxeMemoryAllocationLib/DxeMemoryAllocationLib.inf

+  ReportStatusCodeLib|IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf

+  

+################################################################################

+#

+# Pcd Section - list of all EDK II PCD Entries defined by this Platform

+#

+################################################################################

+[PcdsFeatureFlag.common]

+  gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable|FALSE

+  gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable|FALSE

+  gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable|FALSE

+  gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable|FALSE

+  gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru|TRUE

+  gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru|TRUE

+

+[PcdsFixedAtBuild.common]

+  gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength|0x0

+  gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength|0x0

+  gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|0x0

+  gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout|0x0

+  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x27

+  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000042

+  gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x06

+  gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue|0x0

+

+################################################################################

+#

+# Components Section - list of all EDK II Modules needed by this Platform

+#

+################################################################################

+

+[Components.common]

+  OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf

+  

diff --git a/OptionRomPkg/ReadMe.txt b/OptionRomPkg/ReadMe.txt
new file mode 100644
index 0000000..a6c160a
--- /dev/null
+++ b/OptionRomPkg/ReadMe.txt
@@ -0,0 +1,17 @@
+For now, AtapiPassThru driver in this package is to test Scsi Bus support:

+ScsiBus driver should support both/either ScsiPassThru and ExtScsiPassThru

+installed on a controller handle.

+ 

+AtapiPassThru driver in this package can selectively produce ScsiPassThru

+and/or ExtScsiPassThru protocol based on feature flags of PcdSupportScsiPassThru

+and PcdExtScsiPassThru.

+

+Please note that AtapiPassThru driver has not been tuned to size optimal.

+Neither is it feature complete: several driver model protocols required

+by option ROM driver, e.g. EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL Protocol. 

+

+Build Validation:

+MYTOOLS(VS2005) IA32 X64 IPF EBC

+ICC             IA32 X64 IPF

+CYGWINGCC       IA32 X64

+