summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus/Pci
diff options
context:
space:
mode:
authorqhuang8 <qhuang8@6f19259b-4bc3-4df7-8a09-765794883524>2007-06-27 09:29:08 +0000
committerqhuang8 <qhuang8@6f19259b-4bc3-4df7-8a09-765794883524>2007-06-27 09:29:08 +0000
commit513f3f444743f9e84f1928765192d67a72afd11c (patch)
treef5b326f7a03e7a92698e562a4414abab92be8139 /MdeModulePkg/Bus/Pci
parent56a1c2270b4d261872762eef5989b96a32de387f (diff)
downloadedk2-513f3f444743f9e84f1928765192d67a72afd11c.zip
edk2-513f3f444743f9e84f1928765192d67a72afd11c.tar.gz
edk2-513f3f444743f9e84f1928765192d67a72afd11c.tar.bz2
Add AtapiPassThru & CapsuleRuntime module to MdeModulePkg
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2806 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Bus/Pci')
-rw-r--r--MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.c2177
-rw-r--r--MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.h833
-rw-r--r--MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.inf102
-rw-r--r--MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.msa72
-rw-r--r--MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/ComponentName.c120
5 files changed, 3304 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.c b/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.c
new file mode 100644
index 0000000..f14d9e3
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.c
@@ -0,0 +1,2177 @@
+/** @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"
+
+///
+/// IDE registers' fixed address
+///
+static IDE_BASE_REGISTERS gAtapiIoPortRegisters[2] = {
+ { 0x1f0, { 0x1f1 }, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, { 0x1f7 }, { 0x3f6 }, 0x3f7, 0 },
+ { 0x170, { 0x171 }, 0x172, 0x173, 0x174, 0x175, 0x176, { 0x177 }, { 0x376 }, 0x377, 0 }
+};
+
+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 }
+};
+
+static CHAR16 *gControllerNameString = (CHAR16 *) L"ATAPI Controller";
+static CHAR16 *gAtapiChannelString = (CHAR16 *) L"ATAPI Channel";
+
+EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding = {
+ AtapiScsiPassThruDriverBindingSupported,
+ AtapiScsiPassThruDriverBindingStart,
+ AtapiScsiPassThruDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ Supported.
+
+ (Standard DriverBinding Protocol Supported() function)
+
+ @return EFI_STATUS
+
+ @todo This - add argument and description to function comment
+ @todo Controller - add argument and description to function comment
+ @todo RemainingDevicePath - add argument and description to function comment
+ @todo EFI_UNSUPPORTED - add return value to function comment
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ 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;
+}
+
+/**
+ Create handles for IDE channels specified by RemainingDevicePath.
+ Install SCSI Pass Thru Protocol onto each created handle.
+
+ (Standard DriverBinding Protocol Start() function)
+
+ @return EFI_STATUS
+
+ @todo This - add argument and description to function comment
+ @todo Controller - add argument and description to function comment
+ @todo RemainingDevicePath - add argument and description to function comment
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Create SCSI Pass Thru instance for the IDE channel.
+ //
+ Status = RegisterAtapiScsiPassThru (This, Controller, PciIo);
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if (PciIo) {
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationDisable,
+ EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Stop.
+
+ (Standard DriverBinding Protocol Stop() function)
+
+ @return EFI_STATUS
+
+ @todo This - add argument and description to function comment
+ @todo Controller - add argument and description to function comment
+ @todo NumberOfChildren - add argument and description to function comment
+ @todo ChildHandleBuffer - add argument and description to function comment
+ @todo EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
+
+ 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);
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ &AtapiScsiPrivate->ScsiPassThru
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Release Pci Io protocol on the controller handle.
+ //
+ AtapiScsiPrivate->PciIo->Attributes (
+ AtapiScsiPrivate->PciIo,
+ EfiPciIoAttributeOperationDisable,
+ EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->FreePool (AtapiScsiPrivate);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Attaches SCSI Pass Thru Protocol for specified IDE channel.
+
+ @param Controller: Parent device handle to the IDE channel.
+ @param PciIo: PCI I/O protocol attached on the "Controller".
+
+ @return EFI_SUCCESS Always returned unless installing SCSI Pass Thru Protocol failed.
+
+ @todo This - add argument and description to function comment
+ @todo Controller - add argument and description to function comment
+ @todo PciIo - add argument and description to function comment
+ @todo EFI_OUT_OF_RESOURCES - add return value to function comment
+**/
+EFI_STATUS
+RegisterAtapiScsiPassThru (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
+ UINT64 Attributes;
+
+ AtapiScsiPrivate = AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV));
+ if (AtapiScsiPrivate == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Attributes = EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE;
+ CopyMem (AtapiScsiPrivate->ChannelName, gAtapiChannelString, sizeof (gAtapiChannelString));
+
+ //
+ // Enable channel
+ //
+ PciIo->Attributes (PciIo, EfiPciIoAttributeOperationSet, Attributes, NULL);
+
+ AtapiScsiPrivate->Signature = ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE;
+ AtapiScsiPrivate->Handle = Controller;
+
+ //
+ // will reset the IoPort inside each API function.
+ //
+ AtapiScsiPrivate->IoPort = gAtapiIoPortRegisters;
+ AtapiScsiPrivate->PciIo = PciIo;
+
+ //
+ // initialize SCSI Pass Thru Protocol interface
+ //
+ AtapiScsiPrivate->ScsiPassThru.Mode = &AtapiScsiPrivate->ScsiPassThruMode;
+ AtapiScsiPrivate->ScsiPassThru.PassThru = AtapiScsiPassThruFunction;
+ AtapiScsiPrivate->ScsiPassThru.GetNextDevice = AtapiScsiPassThruGetNextDevice;
+ AtapiScsiPrivate->ScsiPassThru.BuildDevicePath = AtapiScsiPassThruBuildDevicePath;
+ AtapiScsiPrivate->ScsiPassThru.GetTargetLun = AtapiScsiPassThruGetTargetLun;
+ AtapiScsiPrivate->ScsiPassThru.ResetChannel = AtapiScsiPassThruResetChannel;
+ AtapiScsiPrivate->ScsiPassThru.ResetTarget = AtapiScsiPassThruResetTarget;
+
+ //
+ // Set Mode
+ //
+ CopyMem (AtapiScsiPrivate->ControllerName, gControllerNameString, sizeof (gControllerNameString));
+
+ AtapiScsiPrivate->ScsiPassThruMode.ControllerName = AtapiScsiPrivate->ControllerName;
+ AtapiScsiPrivate->ScsiPassThruMode.ChannelName = AtapiScsiPrivate->ChannelName;
+ AtapiScsiPrivate->ScsiPassThruMode.AdapterId = 4;
+ //
+ // non-RAID SCSI controllers should set both physical and logical attributes
+ //
+ AtapiScsiPrivate->ScsiPassThruMode.Attributes = EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
+ EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
+ AtapiScsiPrivate->ScsiPassThruMode.IoAlign = 0;
+
+ //
+ // Initialize the LatestTargetId to 0xFFFFFFFF (for the GetNextDevice() call).
+ //
+ AtapiScsiPrivate->LatestTargetId = 0xFFFFFFFF;
+ AtapiScsiPrivate->LatestLun = 0;
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &AtapiScsiPrivate->ScsiPassThru
+ );
+ return Status;
+}
+
+/**
+ Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
+
+ @param This The EFI_SCSI_PASS_THRU_PROTOCOL instance.
+ @param 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.
+ @param Lun The LUN of the ATAPI device to send the SCSI Request
+ Packet. To the ATAPI device, Lun is always 0.
+ @param Packet The SCSI Request Packet to send to the ATAPI device
+ specified by Target and Lun.
+ @param Event If non-blocking I/O is not supported then Event is ignored,
+ and blocking I/O is performed.<br>
+ If Event is NULL, then blocking I/O is performed.<br>
+ 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.
+
+ @todo This - add argument and description to function comment
+ @todo EFI_INVALID_PARAMETER - add return value to function comment
+ @todo EFI_SUCCESS - add return value to function comment
+**/
+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
+ )
+{
+ 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) {
+ 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 gAtapiIoPortRegisters[0],
+ // Target Id in [2,3] area, using gAtapiIoPortRegisters[1]
+ //
+ if ((Target / 2) == 0) {
+ AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[0];
+ } else {
+ AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[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;
+}
+
+/**
+ Used to retrieve the list of legal Target IDs for SCSI devices
+ on a SCSI channel.
+
+ @param This Protocol instance pointer.
+ @param 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.
+ @param 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.
+
+ @retval EFI_SUCCESS The Target ID and Lun of the next SCSI device
+ on the SCSI channel was returned in Target and Lun.
+ @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
+ @retval EFI_INVALID_PARAMETER Target is not 0xFFFFFFFF,and Target and Lun were not
+ returned on a previous call to GetNextDevice().
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruGetNextDevice (
+ IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT32 *Target,
+ IN OUT UINT64 *Lun
+ )
+{
+ 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;
+
+}
+
+/**
+ 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.
+
+ @param This Protocol instance pointer.
+ @param Target The Target ID of the SCSI device for which
+ a device path node is to be allocated and built.
+ @param Lun The LUN of the SCSI device for which a device
+ path node is to be allocated and built.
+ @param 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.
+
+ @retval EFI_SUCCESS The device path node that describes the SCSI device
+ specified by Target and Lun was allocated and
+ returned in DevicePath.
+ @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does
+ not exist on the SCSI channel.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate
+ DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruBuildDevicePath (
+ IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT32 Target,
+ IN UINT64 Lun,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **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;
+}
+
+/**
+ Used to translate a device path node to a Target ID and LUN.
+
+ @param This Protocol instance pointer.
+ @param DevicePath A pointer to the device path node that
+ describes a SCSI device on the SCSI channel.
+ @param Target A pointer to the Target ID of a SCSI device
+ on the SCSI channel.
+ @param Lun A pointer to the LUN of a SCSI device on
+ the SCSI channel.
+
+ @retval EFI_SUCCESS DevicePath was successfully translated to a
+ Target ID and LUN, and they were returned
+ in Target and Lun.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_INVALID_PARAMETER Target is NULL.
+ @retval EFI_INVALID_PARAMETER Lun is NULL.
+ @retval EFI_UNSUPPORTED This driver does not support the device path
+ node type in DevicePath.
+ @retval EFI_NOT_FOUND A valid translation from DevicePath to a
+ Target ID and LUN does not exist.
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruGetTargetLun (
+ IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT32 *Target,
+ OUT UINT64 *Lun
+ )
+{
+ 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;
+}
+
+/**
+ Resets a SCSI channel.This operation resets all the
+ SCSI devices connected to the SCSI channel.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The SCSI channel was reset.
+ @retval EFI_UNSUPPORTED The SCSI channel does not support
+ a channel reset operation.
+ @retval EFI_DEVICE_ERROR A device error occurred while
+ attempting to reset the SCSI channel.
+ @retval EFI_TIMEOUT A timeout occurred while attempting
+ to reset the SCSI channel.
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruResetChannel (
+ IN EFI_SCSI_PASS_THRU_PROTOCOL *This
+ )
+{
+ UINT8 DeviceControlValue;
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
+ UINT8 Index;
+
+ AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
+
+ //
+ // 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 = &gAtapiIoPortRegisters[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, 31000) == EFI_TIMEOUT) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets a SCSI device that is connected to a SCSI channel.
+
+ @param This Protocol instance pointer.
+ @param Target The Target ID of the SCSI device to reset.
+ @param Lun The LUN of the SCSI device to reset.
+
+ @retval EFI_SUCCESS The SCSI device specified by Target and
+ Lun was reset.
+ @retval EFI_UNSUPPORTED The SCSI channel does not support a target
+ reset operation.
+ @retval EFI_INVALID_PARAMETER Target or Lun are invalid.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting
+ to reset the SCSI device specified by Target
+ and Lun.
+ @retval EFI_TIMEOUT A timeout occurred while attempting to reset
+ the SCSI device specified by Target and Lun.
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruResetTarget (
+ IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT32 Target,
+ IN UINT64 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) {
+ 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 gAtapiIoPortRegisters[0],
+ // Target Id in [2,3] area, using gAtapiIoPortRegisters[1]
+ //
+ if ((Target / 2) == 0) {
+ AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[0];
+ } else {
+ AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[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, 31000))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // stall 5 seconds to make the device status stable
+ //
+ gBS->Stall (5000000);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Checks the parameters in the SCSI Request Packet to make sure
+ they are valid for a SCSI Pass Thru request.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo Packet - add argument and description to function comment
+ @todo EFI_INVALID_PARAMETER - add return value to function comment
+ @todo EFI_INVALID_PARAMETER - add return value to function comment
+ @todo EFI_INVALID_PARAMETER - add return value to function comment
+ @todo EFI_UNSUPPORTED - add return value to function comment
+ @todo EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+CheckSCSIRequestPacket (
+ EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+ )
+{
+ 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;
+}
+
+/**
+ Checks the requested SCSI command:
+ Is it supported by this driver?
+ Is the Data transfer direction reasonable?
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo Packet - add argument and description to function comment
+**/
+BOOLEAN
+IsCommandValid (
+ EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+ )
+{
+ 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;
+}
+
+/**
+ Performs blocking I/O request.
+
+ @param AtapiScsiPrivate Private data structure for the specified channel.
+ @param 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.
+ @param Packet The SCSI Request Packet to send to the ATAPI device
+ specified by Target.
+
+ @todo AtapiScsiPrivate - add argument and description to function comment
+**/
+EFI_STATUS
+SubmitBlockingIoCommand (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT32 Target,
+ EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+ )
+{
+ 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_WARN_BUFFER_TOO_SMALL) ||
+ (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;
+}
+
+/**
+ RequestSenseCommand
+
+ @param AtapiScsiPrivate
+ @param Target
+ @param Timeout
+ @param SenseData
+ @param SenseDataLength
+
+ @todo Add function description
+ @todo AtapiScsiPrivate TODO: add argument description
+ @todo Target TODO: add argument description
+ @todo Timeout TODO: add argument description
+ @todo SenseData TODO: add argument description
+ @todo SenseDataLength TODO: add argument description
+ @todo add return values
+**/
+EFI_STATUS
+RequestSenseCommand (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT32 Target,
+ UINT64 Timeout,
+ VOID *SenseData,
+ UINT8 *SenseDataLength
+ )
+{
+ 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;
+}
+
+/**
+ Submits ATAPI command packet to the specified ATAPI device.
+
+ @param AtapiScsiPrivate: Private data structure for the specified channel.
+ @param 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.
+ @param PacketCommand: Points to the ATAPI command packet.
+ @param Buffer: Points to the transferred data.
+ @param ByteCount: When input,indicates the buffer size; when output,
+ indicates the actually transferred data size.
+ @param Direction: Indicates the data transfer direction.
+ @param 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.
+ <P>
+ 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.
+ </P>
+
+ @todo AtapiScsiPrivate - add argument and description to function comment
+ @todo PacketCommand - add argument and description to function comment
+ @todo Buffer - add argument and description to function comment
+ @todo ByteCount - add argument and description to function comment
+ @todo Direction - add argument and description to function comment
+**/
+EFI_STATUS
+AtapiPacketCommand (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT32 Target,
+ UINT8 *PacketCommand,
+ VOID *Buffer,
+ UINT32 *ByteCount,
+ DATA_DIRECTION Direction,
+ UINT64 TimeoutInMicroSeconds
+ )
+{
+
+ UINT16 *CommandIndex;
+ UINT8 Count;
+ EFI_STATUS Status;
+
+ //
+ // Set all the command parameters by fill related registers.
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ Status = StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_ABORTED) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ *ByteCount = 0;
+ return Status;
+ }
+ //
+ // 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)
+ );
+
+ //
+ // 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
+ );
+}
+
+/**
+ Performs data transfer between ATAPI device and host after the
+ ATAPI command packet is sent.
+
+ @param AtapiScsiPrivate: Private data structure for the specified channel.
+ @param Buffer: Points to the transferred data.
+ @param ByteCount: When input,indicates the buffer size; when output,
+ indicates the actually transferred data size.
+ @param Direction: Indicates the data transfer direction.
+ @param 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.
+ <P>
+ 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.
+ </P>
+
+ @todo AtapiScsiPrivate - add argument and description to function comment
+ @todo Buffer - add argument and description to function comment
+ @todo ByteCount - add argument and description to function comment
+ @todo Direction - add argument and description to function comment
+ @todo EFI_DEVICE_ERROR - add return value to function comment
+ @todo EFI_DEVICE_ERROR - add return value to function comment
+ @todo EFI_WARN_BUFFER_TOO_SMALL - add return value to function comment
+**/
+EFI_STATUS
+AtapiPassThruPioReadWriteData (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT16 *Buffer,
+ UINT32 *ByteCount,
+ DATA_DIRECTION Direction,
+ UINT64 TimeoutInMicroSeconds
+ )
+{
+ 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_WARN_BUFFER_TOO_SMALL;
+ }
+ }
+ //
+ // 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;
+}
+
+
+/**
+ Read one byte from a specified I/O port.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo PciIo - add argument and description to function comment
+ @todo Port - add argument and description to function comment
+**/
+UINT8
+ReadPortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port
+ )
+{
+ UINT8 Data;
+
+ Data = 0;
+ PciIo->Io.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+ return Data;
+}
+
+
+/**
+ Read one word from a specified I/O port.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo PciIo - add argument and description to function comment
+ @todo Port - add argument and description to function comment
+**/
+UINT16
+ReadPortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port
+ )
+{
+ UINT16 Data;
+
+ Data = 0;
+ PciIo->Io.Read (
+ PciIo,
+ EfiPciIoWidthUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+ return Data;
+}
+
+
+/**
+ Write one byte to a specified I/O port.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo PciIo - add argument and description to function comment
+ @todo Port - add argument and description to function comment
+ @todo Data - add argument and description to function comment
+**/
+VOID
+WritePortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT8 Data
+ )
+{
+
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+
+}
+
+
+/**
+ Write one word to a specified I/O port.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo PciIo - add argument and description to function comment
+ @todo Port - add argument and description to function comment
+ @todo Data - add argument and description to function comment
+**/
+VOID
+WritePortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT16 Data
+ )
+{
+
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+}
+
+/**
+ 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.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo AtapiScsiPrivate - add argument and description to function comment
+ @todo TimeoutInMicroSeconds - add argument and description to function comment
+ @todo EFI_ABORTED - add return value to function comment
+ @todo EFI_TIMEOUT - add return value to function comment
+ @todo EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+StatusDRQClear (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeoutInMicroSeconds
+ )
+{
+ 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;
+}
+
+/**
+ 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.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo AtapiScsiPrivate - add argument and description to function comment
+ @todo TimeoutInMicroSeconds - add argument and description to function comment
+ @todo EFI_ABORTED - add return value to function comment
+ @todo EFI_TIMEOUT - add return value to function comment
+ @todo EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+AltStatusDRQClear (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeoutInMicroSeconds
+ )
+{
+ 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;
+}
+
+/**
+ 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.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo AtapiScsiPrivate - add argument and description to function comment
+ @todo TimeoutInMicroSeconds - add argument and description to function comment
+ @todo EFI_ABORTED - add return value to function comment
+ @todo EFI_TIMEOUT - add return value to function comment
+ @todo EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+StatusDRQReady (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeoutInMicroSeconds
+ )
+{
+ 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;
+}
+
+/**
+ 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.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo AtapiScsiPrivate - add argument and description to function comment
+ @todo TimeoutInMicroSeconds - add argument and description to function comment
+ @todo EFI_ABORTED - add return value to function comment
+ @todo EFI_TIMEOUT - add return value to function comment
+ @todo EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+AltStatusDRQReady (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeoutInMicroSeconds
+ )
+{
+ 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;
+}
+
+/**
+ 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.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo AtapiScsiPrivate - add argument and description to function comment
+ @todo TimeoutInMicroSeconds - add argument and description to function comment
+ @todo EFI_TIMEOUT - add return value to function comment
+ @todo EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+StatusWaitForBSYClear (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeoutInMicroSeconds
+ )
+{
+ 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;
+}
+
+/**
+ 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.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo AtapiScsiPrivate - add argument and description to function comment
+ @todo TimeoutInMicroSeconds - add argument and description to function comment
+ @todo EFI_TIMEOUT - add return value to function comment
+ @todo EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+AltStatusWaitForBSYClear (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeoutInMicroSeconds
+ )
+{
+ 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;
+}
+
+/**
+ 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.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo AtapiScsiPrivate - add argument and description to function comment
+ @todo TimeoutInMicroSeconds - add argument and description to function comment
+ @todo EFI_ABORTED - add return value to function comment
+ @todo EFI_TIMEOUT - add return value to function comment
+ @todo EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+StatusDRDYReady (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeoutInMicroSeconds
+ )
+{
+ 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;
+}
+
+/**
+ 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.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo AtapiScsiPrivate - add argument and description to function comment
+ @todo TimeoutInMicroSeconds - add argument and description to function comment
+ @todo EFI_ABORTED - add return value to function comment
+ @todo EFI_TIMEOUT - add return value to function comment
+ @todo EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+AltStatusDRDYReady (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeoutInMicroSeconds
+ )
+{
+ 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;
+}
+
+/**
+ Check Error Register for Error Information.
+
+ @todo function comment is missing 'Routine Description:'
+ @todo function comment is missing 'Arguments:'
+ @todo function comment is missing 'Returns:'
+ @todo AtapiScsiPrivate - add argument and description to function comment
+ @todo EFI_SUCCESS - add return value to function comment
+ @todo EFI_DEVICE_ERROR - add return value to function comment
+**/
+EFI_STATUS
+AtapiPassThruCheckErrorStatus (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate
+ )
+{
+ 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;
+}
+
+/**
+ 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 = EfiLibInstallAllDriverProtocols (
+ ImageHandle,
+ SystemTable,
+ &gAtapiScsiPassThruDriverBinding,
+ ImageHandle,
+ &gAtapiScsiPassThruComponentName,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.h b/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.h
new file mode 100644
index 0000000..49b97a8
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.h
@@ -0,0 +1,833 @@
+/** @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
+
+
+//
+// The package level header files this module uses
+//
+#include <Uefi.h>
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Protocol/ScsiPassThru.h>
+#include <Protocol/PciIo.h>
+//
+// The Library classes this module consumes
+//
+#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 <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;
+
+///
+/// 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;
+
+ UINT16 MasterSlave;
+} 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_SCSI_PASS_THRU_MODE ScsiPassThruMode;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ //
+ // Local Data goes here
+ //
+ IDE_BASE_REGISTERS *IoPort;
+
+ CHAR16 ControllerName[100];
+ CHAR16 ChannelName[100];
+
+ UINT32 LatestTargetId;
+ UINT64 LatestLun;
+
+} ATAPI_SCSI_PASS_THRU_DEV;
+
+#define ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS(a) \
+ CR (a, \
+ ATAPI_SCSI_PASS_THRU_DEV, \
+ ScsiPassThru, \
+ ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE \
+ )
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gAtapiScsiPassThruComponentName;
+
+//
+// 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,
+ NoData = 2,
+ 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
+//
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+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
+ );
+
+/**
+ AtapiScsiPassThruDriverEntryPoint
+
+ @param ImageHandle
+ @param SystemTable
+
+ @todo Add function description
+ @todo ImageHandle - add argument description
+ @todo SystemTable - add argument description
+ @todo add return values
+--*/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+;
+
+/**
+ RegisterAtapiScsiPassThru
+
+ @param This
+ @param Controller
+ @param PciIo
+
+ @todo Add function description
+ @todo This add argument description
+ @todo Controller add argument description
+ @todo PciIo add argument description
+ @todo add return values
+**/
+EFI_STATUS
+RegisterAtapiScsiPassThru (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+;
+
+/**
+ AtapiScsiPassThruFunction
+
+ @param This
+ @param Target
+ @param Lun
+ @param Packet
+ @param Event
+
+ @todo Add function description
+ @todo This - add argument description
+ @todo Target - add argument description
+ @todo Lun - add argument description
+ @todo Packet - add argument description
+ @todo Event - add argument description
+ @todo add return values
+**/
+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
+ )
+;
+
+/**
+ AtapiScsiPassThruGetNextDevice
+
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param Target TODO: add argument description
+ @param Lun TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruGetNextDevice (
+ IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT32 *Target,
+ IN OUT UINT64 *Lun
+ )
+;
+
+/**
+ AtapiScsiPassThruBuildDevicePath
+
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param Target TODO: add argument description
+ @param Lun TODO: add argument description
+ @param DevicePath TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruBuildDevicePath (
+ IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT32 Target,
+ IN UINT64 Lun,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+;
+
+/**
+ AtapiScsiPassThruGetTargetLun
+
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param DevicePath TODO: add argument description
+ @param Target TODO: add argument description
+ @param Lun TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruGetTargetLun (
+ IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT32 *Target,
+ OUT UINT64 *Lun
+ )
+;
+
+/**
+ AtapiScsiPassThruResetChannel
+
+ TODO: Add function description
+
+ @param This TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruResetChannel (
+ IN EFI_SCSI_PASS_THRU_PROTOCOL *This
+ )
+;
+
+/**
+ AtapiScsiPassThruResetTarget
+
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param Target TODO: add argument description
+ @param Lun TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+AtapiScsiPassThruResetTarget (
+ IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT32 Target,
+ IN UINT64 Lun
+ )
+;
+
+/**
+ CheckSCSIRequestPacket
+
+ TODO: Add function description
+
+ @param Packet TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+CheckSCSIRequestPacket (
+ EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+ )
+;
+
+/**
+ SubmitBlockingIoCommand
+
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+ @param Target TODO: add argument description
+ @param Packet TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+SubmitBlockingIoCommand (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT32 Target,
+ EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+ )
+;
+
+/**
+ IsCommandValid
+
+ TODO: Add function description
+
+ @param Packet - TODO: add argument description
+
+ @return TODO: add return values
+
+--*/
+BOOLEAN
+IsCommandValid (
+ EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+ )
+;
+
+/**
+ RequestSenseCommand
+
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+ @param Target TODO: add argument description
+ @param Timeout TODO: add argument description
+ @param SenseData TODO: add argument description
+ @param SenseDataLength TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+RequestSenseCommand (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT32 Target,
+ UINT64 Timeout,
+ VOID *SenseData,
+ UINT8 *SenseDataLength
+ )
+;
+
+/**
+ AtapiPacketCommand
+
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+ @param Target TODO: add argument description
+ @param PacketCommand TODO: add argument description
+ @param Buffer TODO: add argument description
+ @param ByteCount TODO: add argument description
+ @param Direction TODO: add argument description
+ @param TimeOutInMicroSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtapiPacketCommand (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT32 Target,
+ UINT8 *PacketCommand,
+ VOID *Buffer,
+ UINT32 *ByteCount,
+ DATA_DIRECTION Direction,
+ UINT64 TimeOutInMicroSeconds
+ )
+;
+
+
+/**
+ ReadPortB
+
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Port TODO: add argument description
+
+ TODO: add return values
+
+**/
+UINT8
+ReadPortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port
+ )
+;
+
+
+/**
+ ReadPortW
+
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Port TODO: add argument description
+
+ TODO: add return values
+
+**/
+UINT16
+ReadPortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port
+ )
+;
+
+
+/**
+ WritePortB
+
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Port TODO: add argument description
+ @param Data TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+WritePortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT8 Data
+ )
+;
+
+
+/**
+ WritePortW
+
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Port TODO: add argument description
+ @param Data TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+WritePortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT16 Data
+ )
+;
+
+/**
+ StatusDRQClear
+
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+ @param TimeOutInMicroSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+StatusDRQClear (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeOutInMicroSeconds
+ )
+;
+
+/**
+ AltStatusDRQClear
+
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+ @param TimeOutInMicroSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AltStatusDRQClear (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeOutInMicroSeconds
+ )
+;
+
+/**
+ StatusDRQReady
+
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+ @param TimeOutInMicroSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+StatusDRQReady (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeOutInMicroSeconds
+ )
+;
+
+/**
+ AltStatusDRQReady
+
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+ @param TimeOutInMicroSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AltStatusDRQReady (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeOutInMicroSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+ @param TimeoutInMicroSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+StatusWaitForBSYClear (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeoutInMicroSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+ @param TimeoutInMicroSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AltStatusWaitForBSYClear (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeoutInMicroSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+ @param TimeoutInMicroSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+StatusDRDYReady (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeoutInMicroSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+ @param TimeoutInMicroSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AltStatusDRDYReady (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT64 TimeoutInMicroSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+ @param Buffer TODO: add argument description
+ @param ByteCount TODO: add argument description
+ @param Direction TODO: add argument description
+ @param TimeOutInMicroSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtapiPassThruPioReadWriteData (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
+ UINT16 *Buffer,
+ UINT32 *ByteCount,
+ DATA_DIRECTION Direction,
+ UINT64 TimeOutInMicroSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param AtapiScsiPrivate TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtapiPassThruCheckErrorStatus (
+ ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate
+ )
+;
+#endif
diff --git a/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.inf b/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.inf
new file mode 100644
index 0000000..0d8fb77
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.inf
@@ -0,0 +1,102 @@
+#/** @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 Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[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 Section - list of files that are required for the build to succeed.
+#
+################################################################################
+
+[Sources.common]
+ ComponentName.c
+ AtapiPassThru.c
+ AtapiPassThru.h
+
+################################################################################
+#
+# Includes Section - list of Include locations that are required for
+# this module.
+#
+################################################################################
+
+[Includes]
+ $(WORKSPACE)/MdePkg/Include/Library
+
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+# this module.
+#
+################################################################################
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+
+################################################################################
+#
+# Library Class Section - list of Library Classes that are required for
+# this module.
+#
+################################################################################
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+
+################################################################################
+#
+# Protocol C Name Section - list of Protocol and Protocol Notify C Names
+# that this module uses or produces.
+#
+################################################################################
+
+[Protocols]
+ gEfiScsiPassThruProtocolGuid # PROTOCOL BY_START
+ gEfiPciIoProtocolGuid # PROTOCOL TO_START
+
diff --git a/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.msa b/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.msa
new file mode 100644
index 0000000..b33cb93
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.msa
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>AtapiPassThru</ModuleName>
+ <ModuleType>UEFI_DRIVER</ModuleType>
+ <GuidValue>E49061CE-99A7-41d3-AB3A-36E5CFBAD63E</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Description file for the Atapi Passthru component.</Abstract>
+ <Description>This driver simulates SCSI devices with Atapi devices to test the SCSI io
+ protocol.</Description>
+ <Copyright>Copyright (c) 2006 - 2007, Intel Corporation</Copyright>
+ <License>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.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>AtapiPassThru</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiDriverEntryPoint</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>MemoryAllocationLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>AtapiPassThru.h</Filename>
+ <Filename>AtapiPassThru.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="1E73767F-8F52-4603-AEB4-F29B510B6766"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="TO_START">
+ <ProtocolCName>gEfiPciIoProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="BY_START">
+ <ProtocolCName>gEfiScsiPassThruProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ <Extern>
+ <DriverBinding>gAtapiScsiPassThruDriverBinding</DriverBinding>
+ <ComponentName>gAtapiScsiPassThruComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
diff --git a/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/ComponentName.c b/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/ComponentName.c
new file mode 100644
index 0000000..1731571
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/ComponentName.c
@@ -0,0 +1,120 @@
+/** @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
+///
+EFI_COMPONENT_NAME_PROTOCOL gAtapiScsiPassThruComponentName = {
+ AtapiScsiPassThruComponentNameGetDriverName,
+ AtapiScsiPassThruComponentNameGetControllerName,
+ "eng"
+};
+
+static EFI_UNICODE_STRING_TABLE mAtapiScsiPassThruDriverNameTable[] = {
+ { "eng", (CHAR16 *) L"ATAPI SCSI Pass Thru Driver" },
+ { NULL , NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the driver name that 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.
+ @param DriverName 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 LookupUnicodeString (
+ Language,
+ gAtapiScsiPassThruComponentName.SupportedLanguages,
+ mAtapiScsiPassThruDriverNameTable,
+ DriverName
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param ControllerHandle 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 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 A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that 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.
+ @param ControllerName 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;
+}