diff options
Diffstat (limited to 'Core/EM/IdeBus/Atapi.c')
-rw-r--r-- | Core/EM/IdeBus/Atapi.c | 1811 |
1 files changed, 1811 insertions, 0 deletions
diff --git a/Core/EM/IdeBus/Atapi.c b/Core/EM/IdeBus/Atapi.c new file mode 100644 index 0000000..7230aac --- /dev/null +++ b/Core/EM/IdeBus/Atapi.c @@ -0,0 +1,1811 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2010, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Core/Modules/IdeBus/Atapi.c 23 8/16/12 3:24a Rajeshms $ +// +// $Revision: 23 $ +// +// $Date: 8/16/12 3:24a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Core/Modules/IdeBus/Atapi.c $ +// +// 23 8/16/12 3:24a Rajeshms +// [TAG] EIP97048 +// [Category] New Feature +// [Description] ATAPI PassThru Support using +// EFI_EXT_SCSI_PASS_THRU_PROTOCOL. +// [Files] AhciBus.c, AhciController.c, IdeBus.c, Atapi.c, PIDEBus.h, +// PAhciBus.h, ScsiPassThruAtapi.sdl, ScsiPassThruAtapi.mak, +// ScsiPassThruAtapi.c, ScsiPassThruAtapiSupport.h, ScsiPassThruAtapi.chm, +// ScsiPassThruExt.h +// +// 22 11/08/11 5:16a Deepthins +// [TAG] EIP74607 +// [Category] Improvement +// [Description] Block IO Read/Write function, the alignment should be +// proper. IoAlign value is 0 or 1 means that the buffer can be placed +// anywhere in memory. Otherwise, IoAlign must be a power of 2, and the +// requirement is that the start address of a buffer must be evenly +// divisible by IoAlign with no remainder. +// [Files] Ata.c, Atapi.c and AhciController.c +// +// 21 11/07/11 4:27a Deepthins +// [TAG] EIP74607 +// [Category] Improvement +// [Description] IoAlign values is 0 or 1 means that the buffer can be +// placed anywhere in memory. Otherwise, IoAlign must be a power of 2, and +// the requirement is that the start address of a buffer must be evenly +// divisible by 2 to the power of IoAlign with no remainder. +// [Files] Atapi.c +// +// 20 9/27/11 3:11a Rajeshms +// [TAG] EIP69295 +// [Category] New Feature +// [Description] The Timeout values used by IDE and AHCI drivers are +// made as SDL tokens, so that the timeout values can be varied. +// [Files] IdeBusBoard.c, CORE_DXE.sdl, AhciSmm.h, AhciBus.h, IDESMM.h, +// Ata.c, Atapi.c, IdeBus.c, IdeBus.h, IdeBusMaster.c, IdeBusBoard.h +// +// 19 5/02/11 12:23a Rameshr +// [TAG]- EIP 58686 +// [Category]-IMPROVEMENT +// [Description]- Update implementation of EFI_BLOCK_IO_PROTOCOL as +// described in UEFI specification Version 2.3.1, page 12.8 +// [Files]- Idebus.c, Atapi.c +// +// 18 4/12/11 4:05a Rameshr +// [TAG]- EIP 53710 +// [Category]- New Feature +// [Description]- ATAPI ODD loading type information added into ATAPI +// device structure +// [Files]- Atapi.c, Idebus.c, IdeBus.h +// +// 17 10/11/10 11:28a Krishnakumarg +// [TAG] - EIP 43249 +// [Category] - IMPROVEMENT +// [Severity] - Minor +// [Symptom] - Non-Ascii character in comments causing build problem in +// japanese XP +// [RootCause]- Presence of Non-Ascii character +// [Solution] - Remove Non-Ascii character present in the file +// [Files] - IdeSecurity.c,IDESMM.c, InstallIdeSmi, Ata.c, Atapi.c, +// IDEBusComponentName.c, IdeBusMaster.c, IdeHPA.c, IdePowerManagement.c +// +// 16 8/25/10 4:08a Rameshr +// New Feature: EIP 37748 +// Description: Move all the IDEBus Source driver SDL token into IdeBus +// Bin Driver. +// FilesModified: All. +// +// 15 7/01/09 12:23p Rameshr +// Coding Standard and File header updated. +// +// 14 6/22/09 11:38a Rameshr +// Odd Type information Saved in Atapi Device Structure. +// EIP:21548 +// +// 13 9/30/08 4:43p Felixp +// Bug fix(EIP 15310):Invalid error code (EFI_DEVICE_ERROR instead of +// EFI_NO_MEDIA) was returned for removable devices with no media +// +// 11 8/07/08 10:05a Rameshraju +// Interrupt cleared properly on Atapihandleerror. +// +// 10 4/22/08 4:29p Felixp +// New status codes added +// +// 9 3/06/08 4:42p Ambikas +// +// 8 13/04/07 3:00p Anandakrishnanl +// Ide Bus Module - Update source files to comply with AMI coding +// standard"!!! +// +// 7 3/13/06 2:21a Felixp +// +// 6 3/07/06 8:41a Srinin +// AtapiReset function returns EFI_SUCCESS +// +// 5 3/03/06 11:28a Srinin +// To detect Media not found error, check for Sense key = 2, ASC = 3A +// and ASCQ = 0/1/2. +// +// 4 1/09/06 11:36a Felixp +// +// 2 12/14/05 3:07p Srinin +// For Read Capacity command, available Buffer size is set to 8. +// +// 1 12/01/05 9:43a Felixp +// +// 9 10/21/05 1:38p Srinin +// Fixed Media detection problem with slow CDROM. +// +// 8 10/06/05 12:59p Felixp +// +// 7 7/25/05 12:52p Srinin +// Delay between successive "TestUnitReady" command changed to 10msec. +// +// 6 7/18/05 4:31p Felixp +// 64-bit compatibility warnings removed +// +// 5 3/04/05 11:34a Mandal +// +// 4 2/24/05 12:21p Felixp +// bug fix in AtapiBlkRead and AtapiBlkWrite functions: +// EFI_INVALID_PARAMETER was returned when last block is read or written +// to +// +// 3 1/18/05 3:22p Felixp +// PrintDebugMessage renamed to Trace +// +// 2 1/05/05 11:21a Srinin +// BusMaster and Password Support added. +// +// 1 12/10/04 1:01p Srinin +// Initial Checkin of IdeBus Driver. +// +// +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: ATAPI.C +// +// Description: Supports ATAPI devices +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + + +#include "IdeBus.h" +#include <Protocol\IdeBusBoard.h> + +// +//External variables +// +extern PLATFORM_IDE_PROTOCOL *gPlatformIdeProtocol; +extern EFI_GUID gEfiBlockIoProtocolGuid; + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: AtapiReset +// +// Description: Issues ATAPI Reset command. +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN BOOLEAN ExtendedVerification +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: IssueAtapiReset, InitIdeBlockIO +// +// Notes: +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS AtapiReset( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification ) +{ + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: AtapiBlkRead +// +// Description: Read from the Atapi Device +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN UINT32 MediaId, +// IN EFI_LBA LBA, +// IN UINTN BufferSize, +// OUT VOID *Buffer +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: AtapiReadWritePio, InitIdeBlockIO +// +// Notes: +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS AtapiBlkRead( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer ) +{ + UINTN DataN; + EFI_STATUS Status; + IDE_BUS_PROTOCOL *IdeBusInterface = ((IDE_BLOCK_IO*)This)->IdeBusInterface; + EFI_BLOCK_IO_MEDIA *BlkMedia = This->Media; + UINT32 BlockSize = BlkMedia->BlockSize; + ATAPI_DEVICE *AtapiDevice = IdeBusInterface->IdeDevice.AtapiDevice; + UINTN BufferAddress; + + // + //Check if Media Present + // + if ( BlkMedia->MediaPresent == FALSE ) { + Status = DetectAtapiMedia( IdeBusInterface ); + + if ( Status == EFI_SUCCESS ) { + return EFI_MEDIA_CHANGED; + } + return Status; + } + + // + //Check if Media ID matches + // + if ( BlkMedia->MediaId != MediaId ) { + return EFI_MEDIA_CHANGED; + } + + if ( BufferSize == 0 ) { + return EFI_SUCCESS; + } + + // + // If IoAlign values is 0 or 1, means that the buffer can be placed + // anywhere in memory or else IoAlign value should be power of 2. To be + // properly aligned the buffer address should be divisible by IoAlign + // with no remainder. + // + (VOID *)BufferAddress = Buffer; + if((BlkMedia->IoAlign > 1 ) && (BufferAddress % BlkMedia->IoAlign)) { + return EFI_INVALID_PARAMETER; + } + + // + //Check whether the block size is multiple of BlkMedia->BlockSize + // + DataN = BufferSize % BlkMedia->BlockSize; + + if ( DataN ) { + return EFI_BAD_BUFFER_SIZE; + } + + // Check for Valid start LBA # + if ( LBA > BlkMedia->LastBlock ) { + return EFI_INVALID_PARAMETER; + } + + // + //Check for Valid End LBA # + // + DataN = BufferSize / BlkMedia->BlockSize; + + if ( LBA + DataN > BlkMedia->LastBlock + 1 ) { + return EFI_INVALID_PARAMETER; + } + + if ( ( gPlatformIdeProtocol->IdeBusMasterSupport ) && ( gPlatformIdeProtocol->AtapiBusMasterSupport ) ) { + if ( DMACapable( IdeBusInterface )) { + Status = AtapiReadWriteBusMaster( + IdeBusInterface, + Buffer, + BufferSize, + LBA, + IdeBusInterface->IdeDevice.ReadCommand, + FALSE ); + return Status; + } + } + + + Status = AtapiReadWritePio( IdeBusInterface, + Buffer, + BufferSize, + LBA, + IdeBusInterface->IdeDevice.ReadCommand, + FALSE ); + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: AtapiBlkWrite +// +// Description: Write to the Atapi Device +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN UINT32 MediaId, +// IN EFI_LBA LBA, +// IN UINTN BufferSize, +// OUT VOID *Buffer +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: AtapiReadWritePio, InitIdeBlockIO +// +// Notes: +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS AtapiBlkWrite( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer ) +{ + UINTN DataN; + EFI_STATUS Status; + IDE_BUS_PROTOCOL *IdeBusInterface = ((IDE_BLOCK_IO*)This)->IdeBusInterface; + EFI_BLOCK_IO_MEDIA *BlkMedia = This->Media; + UINT32 BlockSize = BlkMedia->BlockSize; + UINTN BufferAddress; + + // + // Check if Media Present + // + if ( BlkMedia->MediaPresent == FALSE ) { + Status = DetectAtapiMedia( IdeBusInterface ); + + if ( Status == EFI_SUCCESS ) { + return EFI_MEDIA_CHANGED; + } + return Status; + } + + // + //Check if Media ID matches + // + if ( BlkMedia->MediaId != MediaId ) { + return EFI_MEDIA_CHANGED; + } + + if ( BufferSize == 0 ) { + return EFI_SUCCESS; + } + + // + // If IoAlign values is 0 or 1, means that the buffer can be placed + // anywhere in memory or else IoAlign value should be power of 2. To be + // properly aligned the buffer address should be divisible by IoAlign + // with no remainder. + // + (VOID *)BufferAddress = Buffer; + if((BlkMedia->IoAlign > 1 ) && (BufferAddress % BlkMedia->IoAlign)) { + return EFI_INVALID_PARAMETER; + } + + // + //Check whether the block size is multiple of BlkMedia->BlockSize + // + DataN = BufferSize % BlkMedia->BlockSize; + + if ( DataN ) { + return EFI_BAD_BUFFER_SIZE; + } + + // + //Check for Valid start LBA # + // + if ( LBA > BlkMedia->LastBlock ) { + return EFI_INVALID_PARAMETER; + } + + // + //Check for Valid End LBA # + // + DataN = BufferSize / BlkMedia->BlockSize; + + if ( LBA + DataN > BlkMedia->LastBlock + 1 ) { + return EFI_INVALID_PARAMETER; + } + + if ( ( gPlatformIdeProtocol->IdeBusMasterSupport ) && ( gPlatformIdeProtocol->AtapiBusMasterSupport ) ) { + if ( DMACapable( IdeBusInterface )) { + Status = AtapiReadWriteBusMaster( + IdeBusInterface, + Buffer, + BufferSize, + LBA, + IdeBusInterface->IdeDevice.WriteCommand, + TRUE ); + return Status; + } + } + + + Status = AtapiReadWritePio( IdeBusInterface, + Buffer, + BufferSize, + LBA, + IdeBusInterface->IdeDevice.WriteCommand, + TRUE ); + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: AtapiBlkFlush +// +// Description: Flush the cache +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: InitIdeBlockIO +// +// Notes: +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS AtapiBlkFlush( + IN EFI_BLOCK_IO_PROTOCOL *This ) +{ + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: DetectAtapiMedia +// +// Description: Detects whether a Media is present in the ATAPI Removable device or not. +// +// Input: +// IDE_BUS_INIT_PROTOCOL *IdeBusInitInterface +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: InitIdeBlockIO +// +// Notes: +// 1. Issue Read Capacity command for CDROM or Read Format command for other ATAPI devices. +// 2. If step 1 is successfull, update last LBA, Block Size, Read/Write capable, Media ID +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS DetectAtapiMedia( + IN OUT IDE_BUS_PROTOCOL *IdeBusInterface ) +{ + UINT8 *InputData, *PacketBuffer, LoopCount; + ATAPI_DEVICE *AtapiDevice = IdeBusInterface->IdeDevice.AtapiDevice; + UINT8 Current_Channel = IdeBusInterface->IdeDevice.Channel; + UINT8 Current_Device = IdeBusInterface->IdeDevice.Device; + EFI_BLOCK_IO_MEDIA *BlkMedia = IdeBusInterface->IdeBlkIo->BlkIo.Media; + EFI_STATUS Status = EFI_NOT_FOUND; + UINT16 ByteCount = 256, Data16; + BOOLEAN ReadCapacity = FALSE; + + PROGRESS_CODE( DXE_REMOVABLE_MEDIA_DETECT ); + + // + //Default Values + // + BlkMedia->MediaPresent = FALSE; + BlkMedia->LastBlock = 0x100; // Dummy value + IdeBusInterface->IdeDevice.ReadCommand = ATAPI_READ_10; + IdeBusInterface->IdeDevice.WriteCommand = ATAPI_WRITE_10; + + Status = TestUnitReady( IdeBusInterface ); + + if ((Status != EFI_MEDIA_CHANGED) && (Status != EFI_SUCCESS)) { + return Status; + } + + // + //Issue Read Capacity command + // + Status = pBS->AllocatePool( EfiBootServicesData, + ByteCount, + (VOID**)&InputData ); + + if ( EFI_ERROR( Status )) { + return Status; + } + Status = pBS->AllocatePool( EfiBootServicesData, 16, (VOID**)&PacketBuffer ); + + if ( EFI_ERROR( Status )) { + pBS->FreePool( InputData ); + return Status; + } + + ZeroMemory( PacketBuffer, 16 ); + + // + //For CDROM use Read Capacity command else use Read Format Command + // + if ( AtapiDevice->DeviceType == CDROM_DEVICE ) { + BlkMedia->BlockSize = CDROM_BLOCK_SIZE; + AtapiDevice->BlockSize = BlkMedia->BlockSize; + PacketBuffer[0] = ATAPI_READ_CAPACITY; + PacketBuffer[1] = AtapiDevice->Lun << 5; + Data16 = 8; + } + else { + BlkMedia->BlockSize = LS120_BLOCK_SIZE; + AtapiDevice->BlockSize = BlkMedia->BlockSize; + PacketBuffer[0] = ATAPI_READ_FORMAT_CAPACITIES; + PacketBuffer[1] = AtapiDevice->Lun << 5; + PacketBuffer[7] = ByteCount >> 8; + PacketBuffer[8] = ByteCount & 0xff; + Data16 = ByteCount; + } + + for ( LoopCount = 0; LoopCount < 5; LoopCount++ ) { + ByteCount = Data16; + ZeroMemory( InputData, ByteCount ); + Status = GeneralAtapiCommandAndData( IdeBusInterface, + PacketBuffer, + InputData, + &ByteCount ); + + if ( PacketBuffer[0] == ATAPI_READ_FORMAT_CAPACITIES + && AtapiDevice->Atapi_Status == ILLEGAL_REQUEST ) { + // + //If the Read Format Capacities not supported by device, try + //ReadCapacity command + // + ZeroMemory( PacketBuffer, 16 ); + BlkMedia->BlockSize = CDROM_BLOCK_SIZE; // Default size + AtapiDevice->BlockSize = BlkMedia->BlockSize; + PacketBuffer[0] = ATAPI_READ_CAPACITY; + PacketBuffer[1] = AtapiDevice->Lun << 5; + Data16 = 8; + ReadCapacity = TRUE; + } + + if ( AtapiDevice->Atapi_Status == EFI_SUCCESS ) { + break; + } + + if ( AtapiDevice->Atapi_Status == MEDIUM_NOT_PRESENT ) { + break; + } + } + + if ( Status == EFI_SUCCESS ) { + if ( ReadCapacity == TRUE ) { + BlkMedia->LastBlock = InputData[0] << 24 | InputData[1] << 16 + | InputData[2] << 8 | InputData[3]; + + BlkMedia->LastBlock--; + BlkMedia->MediaPresent = TRUE; + BlkMedia->MediaId++; + BlkMedia->BlockSize = InputData[4] << 24 | InputData[5] << 16 + | InputData[6] << 8 | InputData[7]; + + AtapiDevice->BlockSize = BlkMedia->BlockSize; + BlkMedia->ReadOnly = FALSE; + } + else if ( AtapiDevice->DeviceType == CDROM_DEVICE ) + { + BlkMedia->LastBlock = InputData[0] << 24 | InputData[1] << 16 + | InputData[2] << 8 | InputData[3]; + BlkMedia->LastBlock--; + BlkMedia->BlockSize = CDROM_BLOCK_SIZE; + AtapiDevice->BlockSize = BlkMedia->BlockSize; + BlkMedia->MediaPresent = TRUE; + BlkMedia->MediaId++; + BlkMedia->ReadOnly = TRUE; + } + else if ( InputData[8] != 3 ) // No media present + { + BlkMedia->LastBlock = InputData[4] << 24 | InputData[5] << 16 + | InputData[6] << 8 | InputData[7]; + BlkMedia->LastBlock--; + BlkMedia->MediaPresent = TRUE; + BlkMedia->MediaId++; + BlkMedia->BlockSize = InputData[9] << 16 | InputData[10] << 8 + | InputData[11]; + BlkMedia->ReadOnly = FALSE; + AtapiDevice->BlockSize = BlkMedia->BlockSize; + } + + // + // Update ReadOnly Status + // + if ( AtapiDevice->DeviceType != CDROM_DEVICE ) { + ByteCount = 256; + ZeroMemory( PacketBuffer, 16 ); + ZeroMemory( InputData, ByteCount ); + PacketBuffer[0] = ATAPI_MODE_SENSE; + PacketBuffer[2] = RETURN_ALL_PAGES; + PacketBuffer[7] = ByteCount >> 8; + PacketBuffer[8] = ByteCount & 0xff; + Status = GeneralAtapiCommandAndData( IdeBusInterface, + PacketBuffer, + InputData, + &ByteCount ); + + if ((Status == EFI_SUCCESS) && (ByteCount > 8)) { + BlkMedia->ReadOnly = (InputData[3] & 0x80) != 0 ? TRUE : FALSE; + } + } + + if(pST->Hdr.Revision >= 0x0002001F) { + // + // For Atapi Devices, Default set the 1 for logical blocks per PhysicalBlock + // + BlkMedia->LogicalBlocksPerPhysicalBlock=1; + + // + // For Atapi Devices, Default value set to 0 for Lowest Aligned LBA + // + BlkMedia->LowestAlignedLba=0; + + BlkMedia->OptimalTransferLengthGranularity=BlkMedia->BlockSize; + } + } + + pBS->FreePool( InputData ); + pBS->FreePool( PacketBuffer ); + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: AtapiInquiryData +// +// Description: Issues Atapi Inquiry Command and returns the DATA. +// +// Input: +// IDE_BUS_INIT_PROTOCOL *IdeBusInitInterface +// UINT8 *InquiryData, +// UINT32 *InquiryDataSize +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: InitIdeBlockIO +// +// Notes: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS AtapiInquiryData( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + OUT UINT8 *InquiryData, + IN OUT UINT16 *InquiryDataSize ) +{ + EFI_STATUS Status; + UINT8 *PacketBuffer; + ATAPI_DEVICE *AtapiDevice = IdeBusInterface->IdeDevice.AtapiDevice; + + + Status = pBS->AllocatePool( EfiBootServicesData, 16, (VOID**)&PacketBuffer ); + + if ( EFI_ERROR( Status )) { + return Status; + } + + ZeroMemory( PacketBuffer, 16 ); + PacketBuffer[0] = ATAPI_INQUIRY; + PacketBuffer[1] = AtapiDevice->Lun << 5; + PacketBuffer[4] = (UINT8) *InquiryDataSize; + Status = GeneralAtapiCommandAndData( IdeBusInterface, + PacketBuffer, + InquiryData, + InquiryDataSize ); + pBS->FreePool( PacketBuffer ); + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: AtapiReadWritePio +// +// Description: Read/Write data from/to the ATAPI device +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// VOID *Buffer, +// UINTN ByteCount, +// UINT64 LBA, +// UINT8 ReadWriteCommand, +// BOOLEAN READWRITE +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: AtapiBlkRead, AtapiBlkWrite +// +// Notes: +// 1. Prepare ATAPI Command Packet +// 2. Check for errors. If Media_Change, detect the new atapi media if present and return status accordingly. +// 3. Read/write data if the command packet is issues successfully. +// 4. Repeat from step 1 untill all data has been read/written. +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS AtapiReadWritePio( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN OUT VOID *Buffer, + IN UINTN ByteCount, + IN UINT64 LBA, + IN UINT8 ReadWriteCommand, + IN BOOLEAN READWRITE ) +{ + EFI_STATUS Status; + INTN TotalNumberofBlocks; + INTN TransferLength; + UINT16 BytesRead; + UINTN BytesRemainingTobeRead; + ATAPI_DEVICE *AtapiDevice = IdeBusInterface->IdeDevice.AtapiDevice; + VOID *TempBuffer = Buffer; + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + + // + //Disable Interrupt + // + IdeWriteByte( IdeBusInterface->PciIO, Regs.ControlBlock.DeviceControlReg, 2 ); + + // + //Check for CHK bit in status register before proceeding, if set give ATAPI reset + // + Status = CheckCHKonEntry( IdeBusInterface ); + + if ( EFI_ERROR( Status )) { + return Status; + } + + TotalNumberofBlocks = ByteCount / AtapiDevice->BlockSize; + + for (; TotalNumberofBlocks > 0; TotalNumberofBlocks -= TransferLength ) { + // + //Clear the buffer + // + ZeroMemory( AtapiDevice->PacketBuffer, AtapiDevice->PacketSize ); + + // + //Calculate # of blocks to be transferred + // + if ( TotalNumberofBlocks > 0xffff ) { + TransferLength = 0xffff; + } else { + TransferLength = TotalNumberofBlocks; + } + + // If the ATAPI device is old, below "ATAPI-3" standard, use one block + // per transfer. Some of the old devices don't update the ByteCount value + // before setting the DRQ bit. Instead of adding delay, we will transfer 1 block at a time. + // Even If this enabled, do it only for CDROM. LS120 write will be very slow if 1 block at time is written. + // if (IdeBusInterface->IdeDevice.IdentifyData.Major_Revision_80 < 3) TransferLength = 1; + + // Update the buffer + AtapiDevice->PacketBuffer[0] = ReadWriteCommand; + AtapiDevice->PacketBuffer[1] = AtapiDevice->Lun << 5; + AtapiDevice->PacketBuffer[2] = ((UINT32) LBA) >> 24; + AtapiDevice->PacketBuffer[3] = ((UINT32) LBA) >> 16; + AtapiDevice->PacketBuffer[4] = ((UINT16) LBA) >> 8; + AtapiDevice->PacketBuffer[5] = ((UINT8) LBA) & 0xff; + + AtapiDevice->PacketBuffer[7] = (UINT8)( TransferLength >> 8 ); // MSB + AtapiDevice->PacketBuffer[8] = (UINT8)( TransferLength & 0xff ); // LSB + + BytesRemainingTobeRead = TransferLength * AtapiDevice->BlockSize; + Status = IssueAtapiPacketCommand( IdeBusInterface, + (UINT16*) AtapiDevice->PacketBuffer, + 0, + 0xffff ); + + if ( EFI_ERROR( Status )) { + return Status; + } + + do + { + // + //Check for errors + // + Status = HandleAtapiError( IdeBusInterface ); + + if ( Status != EFI_SUCCESS ) { + // + //Check if Device is getting ready. If yes, wait till it gets ready + // + if ( AtapiDevice->Atapi_Status == BECOMING_READY ) { + Status = TestUnitReady( IdeBusInterface ); + } + + if ( Status == EFI_MEDIA_CHANGED ) { + Status = DetectAtapiMedia( IdeBusInterface ); + + // This may happen during initial power-up also. If ReinstallProtocol needs to be done, + // then differentiate between power-up nad other cases. + if ( Status == EFI_SUCCESS ) { + return EFI_MEDIA_CHANGED; // Return Media Change + } + } + return Status; + } + + //Check if DRQ asserted, else DEVICE error. Since BSY is cleared (HandleAtapiError) when control comes to this + //place, a small delay is enough. + Status = WaitforBitSet( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + DRQ, + DRQ_SET_TIMEOUT ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + if ( READWRITE ) { + Status = WriteAtapiData( IdeBusInterface, + TempBuffer, + &BytesRead ); + } + else { + Status = ReadAtapiData( IdeBusInterface, TempBuffer, &BytesRead ); + } + + // + //Update pointer + // + (UINT8*) TempBuffer += BytesRead; + BytesRemainingTobeRead -= BytesRead; + } while ( BytesRemainingTobeRead ); + + LBA += TransferLength; + // + //Check for errors + // + Status = HandleAtapiError( IdeBusInterface ); + + if ( EFI_ERROR( Status )) { + return Status; + } + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: GeneralAtapiCommandAndData +// +// Description: Issues the ATAPI cammand and reads the data +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// UINT8 *PacketBuffer, +// UINT8 *Buffer, +// IN OUT UINT16 *ByteCount +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS GeneralAtapiCommandAndData( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + UINT8 *PacketBuffer, + UINT8 *Buffer, + IN OUT UINT16 *ByteCount ) +{ + EFI_STATUS Status; + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + + Status = IssueAtapiPacketCommand( IdeBusInterface, + (UINT16*)PacketBuffer, + 0, + *ByteCount ); + + if ( EFI_ERROR( Status )) { + return Status; + } + + // + //Check for errors + // + Status = HandleAtapiError( IdeBusInterface ); + + if ( EFI_ERROR( Status )) { + return Status; + } + + if ( *ByteCount ) { + // + //Check if DRQ asserted, else DEVICE error + // + Status = WaitforBitSet( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + DRQ, + DRQ_TIMEOUT ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // + //Read the data + // + Status = ReadAtapiData( IdeBusInterface, Buffer, ByteCount ); + // + //Check for errors + // + Status = HandleAtapiError( IdeBusInterface ); + return Status; + } else { + *ByteCount = 0; + return Status; + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: IssueAtapiPacketCommand +// +// Description: Issues ATAPI Packet command and send the packet. +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// UINT16 *PacketBuffer, // Pointer to packet +// UINT16 ByteCount // Byte count Limit +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: The Packet Command and the packet are sent. Error is not analysed in this +// Routine. Once the packet is sent successfully, EFI_SUCCESS is returned. +// It is the callers responsibilty to check the status. +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IssueAtapiPacketCommand( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN UINT16 *PacketBuffer, + IN UINT8 Features, + IN UINT16 ByteCount ) +{ + IDE_DEVICE_INTERFACE *IdeDevice = &(IdeBusInterface->IdeDevice); + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + UINT8 Data8; + UINT16 Data16; + EFI_STATUS Status; + ATAPI_DEVICE *AtapiDevice = IdeBusInterface->IdeDevice.AtapiDevice; + + // + // Select the drive + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.DeviceReg, + IdeDevice->Device << 4 ); + // + // Before Writing to any register check for BSY and DRQ bit. Should be zero + // + Status = WaitforBitClear( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + BSY | DRQ, + gPlatformIdeProtocol->AtaPiBusyClearTimeout ); + + if ( EFI_ERROR( Status )) { + Status = IssueAtapiReset( IdeBusInterface, TRUE ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + } + + // + // Write Feature register. No OVL and DMA + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.FeatureReg, + Features ); + + // + //Write Byte Count + // + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBAMidReg, + (ByteCount & 0xff)); + + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBAHighReg, + (ByteCount >> 8)); + + // + //Write Command Register + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.CommandReg, + PACKET_COMMAND ); + + // Wait for 400nsec before reading the status. To accomplish it, read ATL_STATUS and ignore the result. + // Assumption is, this call will take atleast 400nsec to complete. + IdeReadByte( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + &Data8 ); + // + // Check for BSY bit to be clear 30msec + // + Data16 = 30; + Status = WaitforBitClear( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + BSY, + (UINT32) Data16 ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + // + // Check for DRQ set + // + Status = WaitforBitSet( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + DRQ, + (UINT32) Data16 ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // Write the Data + Status = IdeWriteMultipleWord( IdeBusInterface->PciIO, + Regs.CommandBlock.DataReg, + AtapiDevice->PacketSize / 2, + PacketBuffer ); + + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: IssueAtapiReset +// +// Description: Issues ATAPI Reset command +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface +// IN BOOLEAN TESTUNITREADY +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// If TESTUNITREADY is TRUE, after ATAPI Reset, TestUnitReady command is issued. +// Generally after DEVICE RESET command, ATAPI device respond to and command with +// POWER ON RESET OCCURRED and followed by MEDIA CHANGE. +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IssueAtapiReset( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN BOOLEAN TESTUNITREADY ) + +{ + IDE_DEVICE_INTERFACE *IdeDevice = &(IdeBusInterface->IdeDevice); + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + UINT8 Data8; + EFI_STATUS Status; + + PROGRESS_CODE( DXE_REMOVABLE_MEDIA_RESET ); + + // + // Select the drive + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.DeviceReg, + IdeDevice->Device << 4 ); + + // + //Disable Interrupt + // + IdeWriteByte( IdeBusInterface->PciIO, Regs.ControlBlock.DeviceControlReg, 2 ); + + // + //Issue Device reset Command + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.CommandReg, + DEVICE_RESET ); + + // + //Wait for 400nsec before reading the status. To accomplish it, read ATL_STATUS and ignore the result + // + IdeReadByte( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + &Data8 ); + + // + //Check for BSY bit to be clear + // + Status = WaitforBitClear( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + BSY, + gPlatformIdeProtocol->AtaPiResetCommandTimeout ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + IdeReadByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBAMidReg, + &Data8 ); + + if ( Data8 == (ATAPI_SIGNATURE & 0xff)) { + IdeReadByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBAHighReg, + &Data8 ); + + if ( Data8 == (ATAPI_SIGNATURE >> 8)) { + if ( TESTUNITREADY ) { + return TestUnitReady( IdeBusInterface ); + } + } + } + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: HandleAtapiError +// +// Description: Handle Atapi error if any. +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: If DF and CHK bits are not set, return EFI_SUCCESS. If either +// one of the bits are set, analyse the error and return appropraite +// error message. +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS HandleAtapiError( + IN IDE_BUS_PROTOCOL *IdeBusInterface ) +{ + IDE_DEVICE_INTERFACE *IdeDevice = &(IdeBusInterface->IdeDevice); + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + ATAPI_DEVICE *AtapiDevice = IdeBusInterface->IdeDevice.AtapiDevice; + UINT8 Data8; + EFI_STATUS Status; + UINT8 *SenseData; + UINT8 *SensePacket; + UINT16 BytesRead; + + // + //Select the drive + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.DeviceReg, + IdeDevice->Device << 4 ); + + // + //Read the status register + // + IdeReadByte( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + &Data8 ); + + // + //Check if BSY clear else DEVICE error + // + Status = WaitforBitClear( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + BSY, + gPlatformIdeProtocol->AtaPiBusyClearTimeout ); + + IdeBusInterface->AtapiSenseDataLength = 0; + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // + //Read the status register + // + IdeReadByte( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + &Data8 ); + + // + //Check for DF + // + if ( Data8 & DF ) { + AtapiDevice->Atapi_Status = DEVICE_ERROR; + return EFI_DEVICE_ERROR; + } + + // + //Check for CHK + // + if ( Data8 & CHK ) { + AtapiDevice->Atapi_Status = DEVICE_ERROR; + Status = pBS->AllocatePool( EfiBootServicesData, + 256, + (VOID**)&SenseData + ); + + if ( EFI_ERROR( Status )) { + return Status; + } + + Status = pBS->AllocatePool( EfiBootServicesData, + 16, + (VOID**)&SensePacket + ); + + if ( EFI_ERROR( Status )) { + pBS->FreePool( SenseData ); + return Status; + } + + // + //Update the buffer + // + ZeroMemory( SenseData, 256 ); + ZeroMemory( SensePacket, 16 ); + + SensePacket[0] = ATAPI_REQUEST_SENSE; + SensePacket[4] = 0xff; + + Status = IssueAtapiPacketCommand( IdeBusInterface, + (UINT16*) SensePacket, + 0, + 256 ); + + if ( EFI_ERROR( Status )) { + goto exit_HandleAtapiError; + } + + + // + //Wait for BSY to get cleared + // + Status = WaitforBitClear( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + BSY, + gPlatformIdeProtocol->AtaPiBusyClearTimeout ); + + if ( EFI_ERROR( Status )) { + goto exit_HandleAtapiError; + } + + // + //read the status register + // + IdeReadByte( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + &Data8 ); + + Status = EFI_DEVICE_ERROR; + + // + //Check for DF and CHK + // + if ( Data8 & (DF | CHK)) { + goto exit_HandleAtapiError_with_Reset; + } + + // + //Check if DRQ asserted, else DEVICE error + // + if ( !(Data8 & DRQ)) { + goto exit_HandleAtapiError_with_Reset; + } + + // + //Read the data + // + Status = ReadAtapiData( IdeBusInterface, (UINT16*)SenseData, &BytesRead ); + + Status = EFI_DEVICE_ERROR; // Default Value + AtapiDevice->Atapi_Status = DEVICE_ERROR; + + // + // Store the SenseData whcih would be used by ScsiPassThruAtapi PassThru Interface. + // + pBS->CopyMem( IdeBusInterface->AtapiSenseData, SenseData, BytesRead); + IdeBusInterface->AtapiSenseDataLength = (UINT8)BytesRead; + + if (((SenseData[2] & 0xf) == 2) && (SenseData[12] == 0x3a)) { + Status = EFI_NO_MEDIA; + AtapiDevice->Atapi_Status = MEDIUM_NOT_PRESENT; + } + + if (((SenseData[2] & 0xf) == 2) && (SenseData[12] == 0x04) + && (SenseData[13] == 0x01)) { + Status = EFI_MEDIA_CHANGED; + AtapiDevice->Atapi_Status = BECOMING_READY; + } + + if (((SenseData[2] & 0xf) == 6) && (SenseData[12] == 0x28)) { + Status = EFI_MEDIA_CHANGED; + AtapiDevice->Atapi_Status = MEDIA_CHANGED; + } + + if (((SenseData[2] & 0xf) == 7) && (SenseData[12] == 0x27)) { + Status = EFI_WRITE_PROTECTED; + AtapiDevice->Atapi_Status = WRITE_PROTECTED_MEDIA; + } + + if (((SenseData[2] & 0xf) == 6) && (SenseData[12] == 0x29)) { + AtapiDevice->Atapi_Status = POWER_ON_OR_DEVICE_RESET; + } + + if (((SenseData[2] & 0xf) == 5) && (SenseData[0] == 0x70)) { + AtapiDevice->Atapi_Status = ILLEGAL_REQUEST; + } + +exit_HandleAtapiError: + pBS->FreePool( SenseData ); + pBS->FreePool( SensePacket ); + return Status; + +exit_HandleAtapiError_with_Reset: + IssueAtapiReset( IdeBusInterface, TRUE ); + goto exit_HandleAtapiError; + } + + AtapiDevice->Atapi_Status = EFI_SUCCESS; + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: TestUnitReady +// +// Description: Issues Start/Stop unit Command +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// +// Output: +// EFI_STATUS EFI_SUCCESS : If Media is accessible +// EFI_NO_MEDIA +// EFI_MEDIA_CHANGED +// EFI_DEVICE_ERROR +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS TestUnitReady( + IN IDE_BUS_PROTOCOL *IdeBusInterface ) +{ + EFI_STATUS Status; + UINT8 *Packet; + ATAPI_DEVICE *AtapiDevice = IdeBusInterface->IdeDevice.AtapiDevice; + UINT16 ByteCount = 0; + UINT16 LoopCount; + + + Status = pBS->AllocatePool( EfiBootServicesData, 16, (VOID**)&Packet ); + + if ( EFI_ERROR( Status )) { + return Status; + } + + ZeroMemory( Packet, 16 ); + Packet[0] = ATAPI_TEST_UNIT_READY; + Packet[1] = AtapiDevice->Lun << 5; + + for ( LoopCount = 0; LoopCount < 1000; LoopCount++ ) + { + Status = GeneralAtapiCommandAndData( IdeBusInterface, + Packet, + NULL, + &ByteCount ); + + if ( Status == EFI_SUCCESS ) { + break; + } + + if ( AtapiDevice->Atapi_Status == MEDIUM_NOT_PRESENT ) { + break; + } + + if ( AtapiDevice->Atapi_Status == MEDIA_CHANGED ) { + break; + } + pBS->Stall( 10000 ); // 10msec + } + + pBS->FreePool( Packet ); + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: GetOddType +// +// Description: Find the ODD device Type and return it +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// +// Output: +// OUT UINT16 *OddType +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS GetOddType( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN OUT UINT16 *OddType ) +{ + EFI_STATUS Status; + UINT8 *PacketBuffer; + UINT8 *ProfileData; + UINT16 ProfileDataSize = 16; + ATAPI_DEVICE *AtapiDevice = IdeBusInterface->IdeDevice.AtapiDevice; + + Status = pBS->AllocatePool( EfiBootServicesData, 16, (VOID**)&PacketBuffer ); + + if ( EFI_ERROR( Status )) { + return Status; + } + Status = pBS->AllocatePool( EfiBootServicesData, 16, (VOID**)&ProfileData ); + + if ( EFI_ERROR( Status )) { + return Status; + } + ZeroMemory( ProfileData, 16 ); + ZeroMemory( PacketBuffer, 16 ); + PacketBuffer[0] = ATAPI_GET_CONFIGURATION; + // + // Get the Feature Discriptor. + // + PacketBuffer[1] = FEATURE_DISCRIPTOR; + // + // Get the Profile list + // + PacketBuffer[3] = GET_PROFILE_LIST; + // + // Responce Data Size + // + PacketBuffer[8] = 0x10; + + Status = GeneralAtapiCommandAndData( IdeBusInterface, + PacketBuffer, + ProfileData, + &ProfileDataSize ); + + if ( !EFI_ERROR( Status )) { + // + // Get the Profile Number + // + *OddType = (UINT16 )(((ProfileData[sizeof(GET_CONFIGURATION_HEADER) + 4]) << 8) + + ProfileData[sizeof(GET_CONFIGURATION_HEADER) + 5] ); + } + + pBS->FreePool( PacketBuffer ); + pBS->FreePool( ProfileData ); + + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: GetOddLoadingType +// +// Description: Find the ODD Loading Type information and return it +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// +// Output: +// OUT UINT16 *OddLoadingType +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS GetOddLoadingType( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN OUT UINT8 *OddLoadingType ) +{ + EFI_STATUS Status; + UINT8 *PacketBuffer; + UINT8 *ProfileData; + UINT16 ProfileDataSize = 16; + ATAPI_DEVICE *AtapiDevice = IdeBusInterface->IdeDevice.AtapiDevice; + + Status = pBS->AllocatePool( EfiBootServicesData, 16, (VOID**)&PacketBuffer ); + + if ( EFI_ERROR( Status )) { + return Status; + } + Status = pBS->AllocatePool( EfiBootServicesData, 16, (VOID**)&ProfileData ); + + if ( EFI_ERROR( Status )) { + return Status; + } + ZeroMemory( ProfileData, 16 ); + ZeroMemory( PacketBuffer, 16 ); + PacketBuffer[0] = ATAPI_GET_CONFIGURATION; + // + // Get the Feature Discriptor. + // + PacketBuffer[1] = FEATURE_DISCRIPTOR; + // + // Get the Removable Medium feature + // + PacketBuffer[3] = GET_REMOVEABLE_MEDIUM_FEATURE; + // + // Responce Data Size + // + PacketBuffer[8] = 0x10; + + Status = GeneralAtapiCommandAndData( IdeBusInterface, + PacketBuffer, + ProfileData, + &ProfileDataSize ); + + if ( !EFI_ERROR( Status )) { + // + // Get the ODD Loading Type + // + *OddLoadingType=(UINT8 )(((ProfileData[sizeof(GET_CONFIGURATION_HEADER)+4]) & 0xE0) >> 5); + } + + pBS->FreePool( PacketBuffer ); + pBS->FreePool( ProfileData ); + + return Status; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: CheckCHKonEntry +// +// Description: Check for CHK bit. If set Issue ATAPI reset. +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS CheckCHKonEntry( + IN IDE_BUS_PROTOCOL *IdeBusInterface ) +{ + ATAPI_DEVICE *AtapiDevice = IdeBusInterface->IdeDevice.AtapiDevice; + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + IDE_DEVICE_INTERFACE *IdeDevice = &(IdeBusInterface->IdeDevice); + UINT8 Data8; + + // + //Select the drive + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.DeviceReg, + IdeDevice ->Device << 4 ); + + // + //Disable Interrupt + // + IdeWriteByte( IdeBusInterface->PciIO, Regs.ControlBlock.DeviceControlReg, 2 ); + + // + //Read Status + // + IdeReadByte( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + &Data8 ); + + if ( Data8 & CHK ) { + return (IssueAtapiReset( IdeBusInterface, TRUE )); + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: ReadAtapiData +// +// Description: Read data from the data port based on Byte count value +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// OUT UINT8 AtapiCommand +// OUT UINT16 *BytesRead +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS ReadAtapiData( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + OUT void *Data, + OUT UINT16 *BytesRead ) +{ + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + UINT8 Data8; + UINT16 ByteCount = 0; + EFI_STATUS Status; + + // + //Get the number of Bytes to read + // + IdeReadByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBAHighReg, &Data8 ); + ByteCount = Data8 << 8; + IdeReadByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBAMidReg, &Data8 ); + ByteCount |= Data8; + + *BytesRead = ByteCount; + Status = IdeReadMultipleWord( IdeBusInterface->PciIO, + Regs.CommandBlock.DataReg, + ByteCount / 2, + Data ); + + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: WriteAtapiData +// +// Description: Write data to the data port based on Byte count value +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// OUT UINT8 AtapiCommand +// OUT UINT16 *BytesRead +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS WriteAtapiData( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + OUT void *Data, + OUT UINT16 *BytesRead ) +{ + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + UINT8 Data8; + UINT16 ByteCount = 0; + EFI_STATUS Status; + + // + //Get the number of Bytes to Write + // + IdeReadByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBAHighReg, &Data8 ); + ByteCount = Data8 << 8; + IdeReadByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBAMidReg, &Data8 ); + ByteCount |= Data8; + + *BytesRead = ByteCount; + Status = IdeWriteMultipleWord( IdeBusInterface->PciIO, + Regs.CommandBlock.DataReg, + ByteCount / 2, + Data ); + + return Status; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2010, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** |