From 823f7d4f93b79c12ba521e7193bf1136ff0f2bfa Mon Sep 17 00:00:00 2001 From: qhuang8 Date: Tue, 20 Nov 2007 07:05:44 +0000 Subject: [PATCH] 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 --- OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c | 3394 +++++++++++++++++ OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h | 1625 ++++++++ .../AtapiPassThruDxe/AtapiPassThruDxe.inf | 65 + OptionRomPkg/AtapiPassThruDxe/ComponentName.c | 175 + OptionRomPkg/OptionRomPkg.dec | 31 + OptionRomPkg/OptionRomPkg.dsc | 92 + OptionRomPkg/ReadMe.txt | 17 + 7 files changed, 5399 insertions(+) create mode 100644 OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c create mode 100644 OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h create mode 100644 OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf create mode 100644 OptionRomPkg/AtapiPassThruDxe/ComponentName.c create mode 100644 OptionRomPkg/OptionRomPkg.dec create mode 100644 OptionRomPkg/OptionRomPkg.dsc create mode 100644 OptionRomPkg/ReadMe.txt diff --git a/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c b/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c new file mode 100644 index 0000000000..b15f292e93 --- /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 0000000000..2187580bb6 --- /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 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/// +/// 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 0000000000..378624e381 --- /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 0000000000..2f04f0bf3b --- /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 0000000000..7ada9ece96 --- /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 0000000000..ed53dbe832 --- /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 0000000000..a6c160a6b6 --- /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 + -- 2.39.2