diff options
Diffstat (limited to 'Core/EM/IdeBus/Ata.c')
-rw-r--r-- | Core/EM/IdeBus/Ata.c | 2986 |
1 files changed, 2986 insertions, 0 deletions
diff --git a/Core/EM/IdeBus/Ata.c b/Core/EM/IdeBus/Ata.c new file mode 100644 index 0000000..00cabb0 --- /dev/null +++ b/Core/EM/IdeBus/Ata.c @@ -0,0 +1,2986 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (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/Ata.c 34 1/03/12 11:22p Rajkumarkc $ +// +// $Revision: 34 $ +// +// $Date: 1/03/12 11:22p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Core/Modules/IdeBus/Ata.c $ +// +// 34 1/03/12 11:22p Rajkumarkc +// // [TAG] EIP 79612 & 80003 +// // [Category] Bug Fix +// // [Description]System hangs with Blue screen during Win8 installation +// // in IDE Mode (AMD Platforms) +// // Use PLATFORM_IDE_PROTOCOL data instead of hard coded +// // macro POWERON_BUSY_CLEAR_TIMEOUT in Ata.c file +// // [Files] Ata.c +// +// 33 12/05/11 6:12p Rajkumarkc +// [TAG] EIP77142 +// [Category] Improvement +// [Description] Added the function 'IdeNonDataCommandExp' in the +// 'IDE_BUS_PROTOCOL' and removed +// the existing function 'IdeNonDataCommand' for supporting +// the upper 24bits of LBA. +// [Files] +// Ata.c +// IdeBus.c +// Idebus.h +// PIDEBus.h +// +// 32 11/08/11 5:15a Deepthins +// [TAG] EIP74607 +// [Category] Improvement +// [Description] Block IO Read/Write function, the allignment 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, AhciController.c +// +// 31 11/07/11 4:25a 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] Ata.c +// +// 30 11/07/11 12:37a Deepthins +// [TAG] EIP73941 +// [Category] Improvement +// [Description] BufferSize is 0 , ReadBlock function should return +// EFI_SUCCESS without actual reading. +// [Files] Ata.c +// +// 29 9/27/11 3:10a Rajeshms +// [TAG] EIP69295 +// [Category] Improvement +// [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 +// +// 28 8/12/11 4:12a Lavanyap +// [TAG] EIP66476 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] AtaPioDataOut fails for data write commands +// [RootCause] TempBuffer pointer has been assigned for both data read +// and write commands. +// [Solution] TempBuffer pointer has to be assigned only for data read +// commands. +// [Files] Ata.c +// +// 27 3/28/11 4:44p Artems +// EIP 53849: fixed bug with build error in 32-bit debug mode +// +// 26 12/23/10 3:54a Lavanyap +// [TAG] - EIP41445 +// [Category] - NEW FEATURE +// [Description] - Created SataPioDataOut and AtaPioDataOut protocol +// function that can accept additional input parameters. +// [Files] - AhciBus.h, AhciBus.c, AhciController.c, Ata.c, IdeBus.c, +// IdeBus.h, IdeBusMaster.c,PAhciBus.h, PIdeBus.h +// +// 25 11/02/10 12:01a Rameshr +// [TAG] - EIP 45266 +// [Category]- BUG FIX +// [Severity]- Minor +// [Symptom] - E-SATA card will hang up on post and debug card show "AE +// [RootCause]- Device doesn't support any of the UDMA mode and function +// ReturnMsbbit returns incorrect values +// [Solution] - If any of the bit is not set in Input value, ReturnMsbbit +// returns 0xFF. +// [Files] - Ata.c, AhciBus.c +// +// 24 10/11/10 11:27a 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 +// +// 23 9/24/10 12:47a Rameshr +// [TAG] - EIP 44713 +// [Category]- BUG FIX +// [Severity]- Major +// [Symptom] - SECURITY_ERASE_UNIT command is not working +// [RootCause] - Security Erase unit command timeout value is not proper. +// So getting Timeout error for this command. +// [Solution] - Security Erase command timeout value should be from the +// Identify packet command word 89 +// [Files] - Ata.c +// +// 22 8/25/10 4:07a Rameshr +// New Feature: EIP 37748 +// Description: Move all the IDEBus Source driver SDL token into IdeBus +// Bin Driver. +// FilesModified: All. +// +// 21 4/16/10 4:05p Pats +// EIP 30719: Support for the HDD with sector size more than 512bytes. +// +// 20 7/01/09 12:23p Rameshr +// Coding Standard and File header updated. +// +// 19 6/16/09 10:13a Rameshr +// if the Erase command timeout value is 0 or 255, wait for the Erase +// command completion without timeout value +// EIP:20630 +// +// 18 3/29/09 11:13a Rameshr +// Security Erase command timeout value should be from the Identify packet +// command word 89 +// EIP 20630 +// +// 17 4/22/08 2:02p Felixp +// DXE_IDE_DETECT progress code moved from ATA.c to IdeBus.c +// DXE_IDE_ENABLE progress code added +// +// 16 3/06/08 4:42p Ambikas +// +// 15 3/04/08 7:51p Felixp +// +// 13 28/02/08 7:06p Anandakrishnanl +// Changed timeout values and DMA capability logic for DisableIdeInterrupt +// routine. +// +// 12 13/04/07 2:59p Anandakrishnanl +// Ide Bus Module - Update source files to comply with AMI coding +// standard"!!! +// +// 11 5/03/07 11:40a Anandakrishnanl +// Fix in Check Controller presence to detect Hard disk above 400 GB. +// +// 10 2/12/07 3:41p Pats +// Eliminated Check Drive Ready to reduce boot time on reset. +// +// 9 10/27/06 4:20p Felixp +// Reverted back to the previous version +// +// 7 10/12/06 2:02p Srinin +// Fixed problem in multiple read/Write word in PIO mode. +// +// 6 8/24/06 9:30a Felixp +// x64 support (bug fixes) +// +// 5 3/13/06 2:20a Felixp +// +// 4 1/09/06 11:36a Felixp +// +// 2 12/14/05 3:06p Srinin +// Idedevice detection logic modified. +// +// 1 12/01/05 9:43a Felixp +// +// 11 9/27/05 4:41p Olegi +// DisableIdeInterrupt is modified, added code to clear interrupt request. +// +// 10 8/22/05 4:31p Srinin +// ATA/ATAPI identification changed. +// +// 9 7/18/05 4:31p Felixp +// 64-bit compatibility warnings removed +// +// 8 4/25/05 9:55a Felixp +// bug fix in IssueAtaReadWriteCommand +// +// 7 3/04/05 11:33a Mandal +// +// 6 2/24/05 12:21p Felixp +// bug fix in AtaBlkRead and AtaBlkWrite functions: +// EFI_INVALID_PARAMETER was returned when last block is read or written +// to +// +// 5 2/01/05 12:59p Srinin +// IDE HotPlug Support added. +// +// 4 1/28/05 1:19p Felixp +// IdeBus is linked together with CORE_DXE +// +// 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: Ata.c +// +// Description: ATA Services +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + + +#include "IdeBus.h" +#include <Protocol\IdeBusBoard.h> + +extern PLATFORM_IDE_PROTOCOL *gPlatformIdeProtocol; + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: DetectIdeDevice +// +// Description: Detects the ATA/ATAPI device +// +// Input: +// IDE_BUS_PROTOCOL *IdeBusInterface; +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: IdeBusStart +// +// Notes: +// Here is the control flow of this function: +// 1. If controller not present return EFI_NOT_FOUND +// 2. If BSY bit not clear and DRDY not set, return EFI_DEVICE_ERROR +// 3. If Identify command fails, return EFI_NOT_FOUND +// 4. Else return Success +// +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS DetectIdeDevice( + IN IDE_BUS_PROTOCOL *IdeBusInterface ) +{ + EFI_STATUS Status; + UINT16 Index; + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + UINT8 Data8; + + // + // Check if the controller is present + // + Status = ControllerPresence( IdeBusInterface ); + + if ( Status == EFI_NOT_FOUND ) { + // + // Status Reg is 0xff + // + return EFI_NOT_FOUND; + } + + if ( Status == EFI_DEVICE_ERROR ) { + IdeSoftReset( IdeBusInterface ); + + // + //3 Sec loop + // + for ( Index = 0; Index < 300; Index++ ) { + // + //check for BSY bit to be clear + // + Status = WaitforBitClear( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + BSY, + 1 ); // 1 msec + + if ( Status == EFI_SUCCESS ) { + break; + } + pBS->Stall( 10000 ); // 10Msec + } + + Status = ControllerPresence( IdeBusInterface ); + + if ( EFI_ERROR( Status )) { + // + // Device couldn't be detected + // + return EFI_NOT_FOUND; + } + } + + // + //Disable Interrupt + // + DisableIdeInterrupt( IdeBusInterface ); + + // + //Select the drive + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.DeviceReg, + IdeBusInterface->IdeDevice.Device << 4 ); + + // + //Check for BSY bit to be clear + // + Status = WaitforBitClear( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + BSY, + gPlatformIdeProtocol->PoweonBusyClearTimeout ); // 10 sec + + // + //Check Drive ready. ATAPI devices will not set DRDY bit after reset + // + Status = CheckDriveReady( IdeBusInterface ); + + if ( EFI_ERROR( Status )) { + Status = AtapiIdentifyCommand( IdeBusInterface, + &(IdeBusInterface->IdeDevice.IdentifyData)); + IdeBusInterface->IdeDevice.DeviceType = ATAPI; + return Status; + } + + // + //Detect ATA device + // + Status = AtaIdentifyCommand( IdeBusInterface, + &(IdeBusInterface->IdeDevice.IdentifyData)); + IdeBusInterface->IdeDevice.DeviceType = ATA; + + if ( Status == EFI_SUCCESS ) { + return EFI_SUCCESS; + } + + // + //Detect ATAPI Device. After failing the ATA Identify command, ATAPI device if present, + //should have the signature EB14h + // + Status = EFI_NOT_FOUND; + IdeReadByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBAMidReg, + &Data8 ); + + if ( Data8 == (ATAPI_SIGNATURE & 0xff)) { + IdeReadByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBAHighReg, + &Data8 ); + + if ( Data8 == (ATAPI_SIGNATURE >> 8)) { + IdeBusInterface->IdeDevice.DeviceType = ATAPI; + Status = AtapiIdentifyCommand( IdeBusInterface, + &(IdeBusInterface->IdeDevice. + IdentifyData)); + } + } + + if ( EFI_ERROR( Status )) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: ControllerPresence +// +// Description: Detects the ATA/ATAPI Controller +// +// Input: +// IDE_BUS_PROTOCOL *IdeBusInterface; +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: DetectIdeDevice +// +// Notes: +// Here is the control flow of this function: +// 1. Select the drive +// 2. Read status Register +// 3. If Status_Reg = 0xff, return Not_Found +// 4. Check if Busy bit is clear, return Found +// 5. If the BUS is not floating return EFI_DEVICE_ERROR +// +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS ControllerPresence( + IN IDE_BUS_PROTOCOL *IdeBusInterface ) +{ + UINT8 Device = IdeBusInterface->IdeDevice.Device; + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + UINT8 Data8; + UINT8 Temp; + UINT16 Index; + + // + //Select the drive + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.DeviceReg, + Device << 4 ); + + // + //Read the status Register + // + IdeReadByte( IdeBusInterface->PciIO, Regs.CommandBlock.StatusReg, &Data8 ); + + if ( Data8 == 0xff ) { + return EFI_NOT_FOUND; + } + + Index = 0; + + do + { + // + // Status Register is not 0xff. + // + Temp = Data8; + + //60 usec delay + pBS->Stall( 60 ); + + // + //Read the status Register + // + IdeReadByte( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + &Data8 ); + + // + //Return Success if controller present + // + if ( !(Data8 & 0x80)) { + return EFI_SUCCESS; + } + + Data8 |= Temp; + // + //Keep bits 7,6,3 and 0 + // + Data8 &= 0xc9; + + if ( Data8 == 0xc9 ) { + //Check for Bus Floating + //Select the drive + Data8 = (Device & 1) ? 0xA0 : 0xB0; + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.DeviceReg, + Data8 ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.SectorCountReg, + 0xff ); + IdeReadByte( IdeBusInterface->PciIO, + Regs.CommandBlock.DeviceReg, + &Temp ); + //Decide Controller Present or Not + return (Temp == Data8) ? EFI_SUCCESS : EFI_DEVICE_ERROR; + } + Index++; + } while ( Index < 350 ); + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: AtaReset +// +// Description: Reset ATA device +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: InitIdeBlockIO +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AtaReset( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification ) +{ + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: AtaBlkRead +// +// Description: Read from ATA 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: InitIdeBlockIO, AtaReadWritePio +// +// Notes: +// 1. Check for error conditions. +// 2. Call AtaReadWritePio. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AtaBlkRead( + 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; + UINTN BufferAddress; + + // + //Check if Media ID matches + // + if ( BlkMedia->MediaId != MediaId ) { + return EFI_MEDIA_CHANGED; + } + + if ( BlkMedia->MediaPresent == FALSE ) { + return EFI_NO_MEDIA; + } + + 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 ) { + if ( DMACapable( IdeBusInterface )) { + Status = AtaReadWriteBusMaster( IdeBusInterface, + Buffer, + BufferSize, + LBA, + IdeBusInterface->IdeDevice.ReadCommand, + 0 ); + return Status; + } + } + + + Status = AtaReadWritePio( IdeBusInterface, + Buffer, + BufferSize, + LBA, + IdeBusInterface->IdeDevice.ReadCommand, + 0 ); + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: AtaBlkWrite +// +// Description: Write to ATA 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: InitIdeBlockIO, AtaReadWritePio +// +// Notes: +// 1. Check for error conditions. +// 2. Call AtaReadWritePio. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AtaBlkWrite( + 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 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 ) { + if ( DMACapable( IdeBusInterface )) { + Status = AtaReadWriteBusMaster( IdeBusInterface, + Buffer, + BufferSize, + LBA, + IdeBusInterface->IdeDevice.WriteCommand, + 1 ); + return Status; + } + } + + Status = AtaReadWritePio( IdeBusInterface, + Buffer, + BufferSize, + LBA, + IdeBusInterface->IdeDevice.WriteCommand, + 1 ); + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: AtaBlkFlush +// +// Description: Flush the cache +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: InitIdeBlockIO +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AtaBlkFlush( + IN EFI_BLOCK_IO_PROTOCOL *This ) +{ + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: AtaReadWritePio +// +// Description: Issues Read/Write Command and Read/Write the data from/to the ATA device +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// VOID *Buffer, +// UINTN ByteCount, +// UINT64 LBA +// IN UINT8 ReadWriteCommand, +// IN BOOLEAN ReadWrite Read/Write = 0/1 +// +// Output: +// *Buffer +// +// Modified: +// +// Referrals: AtaBlkWrite, AtaBlkRead +// +// Notes: +// 1. Check if Multiple sectors can be read/written to the ATA device. +// 2. Check for 48-bit LBA support. +// 3. Issue the command based on step 1 and step 2 results. +// 4. check for errors. +// 5. If success read/write data. +// 6. Based on step 1 results, complete the read/write sequence +// 7. If all sectors are not completed, goto step 3. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AtaReadWritePio( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN OUT VOID *Buffer, + IN UINTN ByteCount, + IN UINT64 LBA, + IN UINT8 ReadWriteCommand, + IN BOOLEAN ReadWrite ) +{ + EFI_STATUS Status; + INT32 WordCount; + UINT32 SectorCount; + UINTN Remainder; + UINT8 Data8; + IDE_DEVICE_INTERFACE *IdeDevice = &(IdeBusInterface->IdeDevice); + UINT8 BlockSize = 1; // 1 sector Default + VOID *TempBuffer; + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + INT64 LoopCount; + INT64 MaxSectorCount; + INT64 Total_Number_Of_Sectors; + UINT32 EraseCommandTimeout = 0; + UINT32 SectorSize = ATA_SECTOR_BYTES; + BOOLEAN SectorGTBytes = FALSE; + + // + //Check if the device supports Multiple sector Read/Write + // + if ( IdeDevice->IdentifyData.Valid_Bits_59 & 0x100 ) { + BlockSize = (UINT8) IdeDevice->IdentifyData.Valid_Bits_59; + } + + // + // Error Checking + // + if ( BlockSize == 0 ) { + BlockSize = 1; + } + + if((IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[2] & BIT14) && // WORD 106 valid? - BIT 14 - 1 + (!(IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[2] & BIT15)) && // WORD 106 valid? - BIT 15 - 0 + (IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[2] & BIT12)) { // WORD 106 bit 12 - Sectorsize > 256 words + // The sector size is in words 117-118. + SectorSize = (UINT32)(IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[13] + \ + (IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[14] << 16)) * 2; + } + // + // Disable Interrupt + // + IdeWriteByte( IdeBusInterface->PciIO, Regs.ControlBlock.DeviceControlReg, 2 ); + + if ( Check48BitCommand( ReadWriteCommand )) { + MaxSectorCount = MAX_SECTOR_COUNT_PIO_48BIT; + } + else { + MaxSectorCount = MAX_SECTOR_COUNT_PIO; + } + + // + //Calculate the total number of Sectors to be transferred + // + Total_Number_Of_Sectors = ByteCount / SectorSize; //512 + // If the caller is requesting less bytes than one sector, we need to + // allocate space for one sector. + if ((ByteCount < SectorSize) && (ByteCount > 0)) { + Status = pBS->AllocatePool( EfiBootServicesData, + SectorSize, + (VOID**)&TempBuffer ); + if ( EFI_ERROR( Status )) { + return EFI_OUT_OF_RESOURCES; + } + SectorGTBytes = TRUE; + Total_Number_Of_Sectors = 1; + } else { + TempBuffer = Buffer; + } + + for (; + Total_Number_Of_Sectors > 0; + Total_Number_Of_Sectors -= MaxSectorCount ) + { + if ( Total_Number_Of_Sectors > MaxSectorCount ) { + SectorCount = 0; + } else { + SectorCount = (UINT32) Total_Number_Of_Sectors; + } + + Status = IssueAtaReadWriteCommand( IdeBusInterface, + LBA, + SectorCount, + ReadWriteCommand, + NULL ); + + if ( EFI_ERROR( Status )) { + return EFI_INVALID_PARAMETER; + } + + // + //Update LBA for next loop + // + if ( SectorCount ) { + LBA += SectorCount; + LoopCount = (SectorCount / BlockSize); + LoopCount += ((SectorCount % BlockSize) > 0 ? 1 : 0); + } + else { + LBA += MaxSectorCount; + LoopCount = Div64( MaxSectorCount, BlockSize, &Remainder ); + LoopCount += (Remainder > 0 ? 1 : 0); + } + + // + //For Security Erase command the time out value comes from Identify Data. + // + if ( ReadWriteCommand == SECURITY_ERASE_UNIT ) { + EraseCommandTimeout = (UINT32)( IdeBusInterface->IdeDevice.IdentifyData.Time_security_Earse_89 ); + + if ( EraseCommandTimeout <= 254 ) { + EraseCommandTimeout = EraseCommandTimeout * 2 * 1000 * 60; //Value * 2Minitues + } + else { + EraseCommandTimeout = 0; // No Timeout Value + } + } + + // + //Read Data + // + for (; LoopCount > 0; LoopCount -= 1 ) { + // + //Wait for Command completion + // + if ( ReadWriteCommand == SECURITY_ERASE_UNIT ) { + Status = WaitForCmdCompletionWithTimeOutValue( IdeBusInterface, + EraseCommandTimeout ); + } + else { + Status = WaitForCmdCompletion( IdeBusInterface ); + } + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // + //Check for DRQ + // + Status = WaitforBitSet( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + DRQ, + DRQ_TIMEOUT ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // + //Caluculate # of Words to be read/written + // + if ( SectorCount ) { + if ( SectorCount >= BlockSize ) { + WordCount = (BlockSize * SectorSize) / 2; + } + else { + WordCount = (SectorCount * SectorSize) / 2; // Partial Block will be transferred + } + } + else { + WordCount = (BlockSize * SectorSize) / 2; + } + + if ( BlockSize == 1 ) { + WordCount = (SectorSize) / 2; + } + + if ( ReadWrite ) { + Status = IdeWriteMultipleWord( IdeBusInterface->PciIO, + Regs.CommandBlock.DataReg, + WordCount, + TempBuffer ); + } else { + Status = IdeReadMultipleWord( IdeBusInterface->PciIO, + Regs.CommandBlock.DataReg, + WordCount, + TempBuffer ); + } + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // + //Check for errors. + // + IdeReadByte( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + &Data8 ); + + if ( Data8 & 0x21 ) { // ERR OR DF bit set ? + return EFI_DEVICE_ERROR; + } + + ((UINT8*)TempBuffer) += (WordCount * 2); + + if ( SectorCount ) { + SectorCount -= (WordCount * 2) / SectorSize; + } + else { + SectorCount = (UINT32) ( MaxSectorCount - ((WordCount * 2) / SectorSize)); + } + } + } + if (SectorGTBytes) { + pBS->CopyMem( Buffer, TempBuffer, ByteCount); + pBS->FreePool( TempBuffer ); + } + + // + // Check for errors + // + if ( ReadWriteCommand == SECURITY_ERASE_UNIT ) { + Status = WaitForCmdCompletionWithTimeOutValue( IdeBusInterface, + EraseCommandTimeout ); + } else { + Status = WaitForCmdCompletion( IdeBusInterface ); + } + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: AtaPioDataIn +// +// Description: Issues command which require data to be read +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// VOID *Buffer, +// UINT32 ByteCount, +// UINT8 SectorCount, +// UINT8 LBALow, +// UINT8 LBAMid, +// UINT8 LBAHigh, +// UINT8 Device, +// UINT8 Command, +// BOOLEAN Multiple // to determine the block size +// Output: +// *Buffer +// +// Modified: +// +// Referrals: +// +// Notes: +// Used to get Identify command data etc. +// 1. Issue the command +// 2. Check for errors. +// 3. Check if Data is ready. If yes, read it else return error. +// +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AtaPioDataIn( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + OUT VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 Features, + IN UINT8 SectorCount, + IN UINT8 LBALow, + IN UINT8 LBAMid, + IN UINT8 LBAHigh, + IN UINT8 Device, + IN UINT8 Command, + IN BOOLEAN Multiple ) +{ + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + EFI_STATUS Status; + UINT8 Data8; + UINT32 BlockSize; + VOID *TempBuffer = Buffer; + UINT32 SectorSize = ATA_SECTOR_BYTES; + INT64 TempByteCount; + + + if((IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[2] & BIT14) && // WORD 106 valid? - BIT 14 - 1 + (!(IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[2] & BIT15)) && // WORD 106 valid? - BIT 15 - 0 + (IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[2] & BIT12)) { // WORD 106 bit 12 - Sectorsize > 256 words + // The sector size is in words 117-118. + SectorSize = (UINT32)(IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[13] + \ + (IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[14] << 16)) * 2; + } + + if ( Multiple ) { + BlockSize = SectorSize * (IdeBusInterface->IdeDevice.IdentifyData.Valid_Bits_59 & 0x0f); + } + else { + // + // Only one block of data to read + // + BlockSize = SectorSize; + } + + if (ByteCount < SectorSize) BlockSize = ByteCount; + + // Make the byte count a signed number. + TempByteCount = (INT64)ByteCount; + + // + //Select the drive + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.DeviceReg, + Device ); + + // + // Issue the Command + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.FeatureReg, + Features ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.SectorCountReg, + SectorCount ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBALowReg, + LBALow ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBAMidReg, + LBAMid ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBAHighReg, + LBAHigh ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.CommandReg, + Command ); + + for (; TempByteCount > 0; TempByteCount -= BlockSize ) { + + // + //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.ControlBlock.AlternateStatusReg, + BSY, + COMMAND_COMPLETE_TIMEOUT ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // + //Check if DRQ is set else it is an error + // + IdeReadByte( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + &Data8 ); + + // + // DRQ bit set ? + // + if ( !(Data8 & 0x08)) { + // + // Handle Error condition + // + return EFI_DEVICE_ERROR; + } + + if ( Data8 & 0x21 ) { + return EFI_DEVICE_ERROR; + } + + Status = IdeReadMultipleWord( IdeBusInterface->PciIO, + Regs.CommandBlock.DataReg, + BlockSize / 2, + TempBuffer ); + // + // Wait for DRQ to go low + // + WaitforBitClear( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + DRQ, + DRQ_CLEAR_TIMEOUT ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + ((UINT8*)TempBuffer) += BlockSize; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: AtaPioDataOut +// +// Description: Issues Read/Write Command and Read/Write the data from/to the ATA device +// with SubCommand Support. +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// VOID *Buffer, +// UINTN ByteCount, +// UINT8 Features, +// UINT32 SectorCountIn, +// UINT8 LBALow, +// UINT8 LBALowExp, +// UINT8 LBAMid, +// UINT8 LBAMidExp, +// UINT8 LBAHigh, +// UINT8 LBAHighExp, +// UINT8 Device, +// UINT8 Command, +// BOOLEAN ReadWrite, // Read/Write = 0/1 +// BOOLEAN Multiple // to determine the block size +// Output: +// *Buffer +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Check if Multiple sectors can be read/written to the ATA device. +// 2. Check for 48-bit LBA support. +// 3. Issue the command based on step 1 and step 2 results. +// 4. check for errors. +// 5. If success read/write data. +// 6. Based on step 1 results, complete the read/write sequence +// 7. If all sectors are not completed, goto step 3. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS AtaPioDataOut( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN OUT VOID *Buffer, + IN UINTN ByteCount, + IN UINT8 Features, + IN UINT32 SectorCountIn, + IN UINT8 LBALow, + IN UINT8 LBALowExp, + IN UINT8 LBAMid, + IN UINT8 LBAMidExp, + IN UINT8 LBAHigh, + IN UINT8 LBAHighExp, + IN UINT8 Device, + IN UINT8 Command, + IN BOOLEAN ReadWrite, + IN BOOLEAN Multiple ) +{ + EFI_STATUS Status; + INT32 WordCount; + UINT32 SectorCount; + UINTN Remainder; + UINT8 Data8; + IDE_DEVICE_INTERFACE *IdeDevice = &(IdeBusInterface->IdeDevice); + UINT8 BlockSize = 1; // 1 sector Default + VOID *TempBuffer; + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + INT64 LoopCount; + INT64 MaxSectorCount; + INT64 Total_Number_Of_Sectors; + UINT32 EraseCommandTimeout = 0; + UINT32 SectorSize = ATA_SECTOR_BYTES; + BOOLEAN SectorGTBytes = FALSE; + UINT64 LBA = 0; + UINT64 LBAHighDword = 0; + INT64 i; + + // + // Check if the device supports Multiple sector Read/Write + // + if ( IdeDevice->IdentifyData.Valid_Bits_59 & 0x100 ) { + BlockSize = (UINT8) IdeDevice->IdentifyData.Valid_Bits_59; + } + + // + // Error Checking + // + if ( BlockSize == 0 ) { + BlockSize = 1; + } + + if((IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[2] & BIT14) && // WORD 106 valid? - BIT 14 - 1 + (!(IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[2] & BIT15)) && // WORD 106 valid? - BIT 15 - 0 + (IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[2] & BIT12)) { // WORD 106 bit 12 - Sectorsize > 256 words + // The sector size is in words 117-118. + SectorSize = (UINT32)(IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[13] + \ + (IdeBusInterface->IdeDevice.IdentifyData.Reserved_104_126[14] << 16)) * 2; + } + // + // Disable Interrupt + // + IdeWriteByte( IdeBusInterface->PciIO, Regs.ControlBlock.DeviceControlReg, 2 ); + + if ( Check48BitCommand( Command )) { + MaxSectorCount = MAX_SECTOR_COUNT_PIO_48BIT; + // + // if 48 Bit LBA form Upper Dword + // + LBAHighDword |= LBAHighExp; + LBAHighDword = ( Shl64(( Shl64( LBAHighDword, 8)| LBAMidExp), 8)| LBALowExp); + } + else { + MaxSectorCount = MAX_SECTOR_COUNT_PIO; + } + // + // Complete LBA + // + LBA |= LBAHigh; + LBA = (( Shl64(( Shl64( LBA, 8) | LBAMid ), 8)| LBALow)| Shl64( LBAHighDword, 24 )); + + // + //Calculate the total number of Sectors to be transferred + // + Total_Number_Of_Sectors = ByteCount / SectorSize; //512 + // If the caller is requesting less bytes than one sector, we need to + // allocate space for one sector. + if (!ReadWrite && ((ByteCount < SectorSize) && (ByteCount > 0))) { + Status = pBS->AllocatePool( EfiBootServicesData, + SectorSize, + (VOID**)&TempBuffer ); + if ( EFI_ERROR( Status )) { + return EFI_OUT_OF_RESOURCES; + } + SectorGTBytes = TRUE; + Total_Number_Of_Sectors = 1; + } else { + TempBuffer = Buffer; + } + + for (; + Total_Number_Of_Sectors > 0; + Total_Number_Of_Sectors -= MaxSectorCount ) + { + if ( Total_Number_Of_Sectors > MaxSectorCount ) { + SectorCount = 0; + } else { + SectorCount = (UINT32) Total_Number_Of_Sectors; + } + + Status = IssueAtaReadWriteCommand( IdeBusInterface, + LBA, + SectorCount, + Command, + Features ); + + if ( EFI_ERROR( Status )) { + return EFI_INVALID_PARAMETER; + } + + // + //Update LBA for next loop + // + if ( SectorCount ) { + LBA += SectorCount; + LoopCount = (SectorCount / BlockSize); + LoopCount += ((SectorCount % BlockSize) > 0 ? 1 : 0); + } + else { + LBA += MaxSectorCount; + LoopCount = Div64( MaxSectorCount, BlockSize, &Remainder ); + LoopCount += (Remainder > 0 ? 1 : 0); + } + + // + //Read Data + // + for (; LoopCount > 0; LoopCount -= 1 ) { + // + //Wait for Command completion + // + Status = WaitForCmdCompletion( IdeBusInterface ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + // + //Check for DRQ + // + Status = WaitforBitSet( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + DRQ, + DRQ_TIMEOUT ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // + //Calculate # of Words to be read/written + // + + WordCount = SectorSize / 2; + + if ( ReadWrite ) { + + for ( i=0 ; i<Total_Number_Of_Sectors ;i++ ) { + + Status = IdeWriteMultipleWord( IdeBusInterface->PciIO, + Regs.CommandBlock.DataReg, + WordCount, + TempBuffer ); + ((UINT8*)TempBuffer) += SectorSize; + pBS->Stall(100); //10ms Delay after 1 sector write + } + + } else { + + for ( i=0 ; i<Total_Number_Of_Sectors ;i++ ) { + + Status = IdeReadMultipleWord( IdeBusInterface->PciIO, + Regs.CommandBlock.DataReg, + WordCount, + TempBuffer ); + (UINT8 *)TempBuffer += SectorSize; + pBS->Stall(100); //10ms Delay after 1 sector read + + } + ((UINT8*)TempBuffer) -= Mul64( Total_Number_Of_Sectors, SectorSize); + } + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // + //Check for errors. + // + IdeReadByte( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + &Data8 ); + + if ( Data8 & 0x21 ) { // ERR OR DF bit set ? + return EFI_DEVICE_ERROR; + } + +// ((UINT8*)TempBuffer) += (WordCount * 2); + + if ( SectorCount ) { + SectorCount -= (WordCount * 2) / SectorSize; + } + else { + SectorCount = (UINT32) ( MaxSectorCount - ((WordCount * 2) / SectorSize)); + } + } + } + if (SectorGTBytes) { + pBS->CopyMem( Buffer, TempBuffer, ByteCount); + pBS->FreePool( TempBuffer ); + } + + // + // Check for errors + // + Status = WaitForCmdCompletion( IdeBusInterface ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IssueAtaReadWriteCommand +// +// Description: Issues ATA Read/Write Command +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// UINT64 LBA, +// INT32 SectorCount, +// UINT8 Command +// UINT8 Features OPTIONAL +// +// Output: +// EFI_STATUS +// Modified: +// +// Referrals: AtaReadWritePio +// +// Notes: +// 1. Select the drive. +// 2. check if BSY and DRQ bits are zero. +// 3. Issue the command. +// +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IssueAtaReadWriteCommand( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN UINT64 LBA, + IN INT32 SectorCount, + IN UINT8 Command, + IN UINT8 Features ) +{ + EFI_STATUS Status; + IDE_DEVICE_INTERFACE *IdeDevice = &(IdeBusInterface->IdeDevice); + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + UINT8 Device = (IdeDevice->Device << 4); + + // + // Select the drive + // + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.DeviceReg, Device ); + + // + //Before Writing to Sector Count Reg, BSY and DRQ bit should be zero + // + Status = WaitforBitClear( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + BSY | DRQ, + DRQ_TIMEOUT ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // + //Check for DRDY + // + Status = WaitforBitSet( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + DRDY, + DRDY_TIMEOUT ); + + if ( EFI_ERROR( Status )) { + return EFI_TIMEOUT; + } + + if ( Check48BitCommand( Command )) { + // 48 Bit LBA + // Write the Upper LBA DWORD and Upper byte of Sector Count + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.SectorCountReg, + (UINT8)( SectorCount >> 8 )); + + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBALowReg, + (UINT8)Shr64( LBA, 24 )); + + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBAMidReg, + (UINT8) Shr64( LBA, 32 )); + + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBAHighReg, + (UINT8) Shr64( LBA, 40 )); + + Device = (IdeDevice->Device << 4) | 0x40; // 48Bit LBA + } + else { // 28 Bit LBA + Device = ((UINT8) ((UINT32) LBA >> 24 ) & 0x0f) | (IdeDevice->Device << 4) | 0x40; + } + + // + //Select the drive + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.DeviceReg, + Device ); + + // + //Issue command + // + if ( Features ) { + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.FeatureReg, //SubCommand + Features ); + } + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.SectorCountReg, + (UINT8) SectorCount ); + + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBALowReg, + (UINT8)LBA ); + + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBAMidReg, + (UINT8) (((UINT32)LBA >> 8) & 0xff )); + + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBAHighReg, + (UINT8) (((UINT32)LBA >> 16) & 0xff )); + + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.CommandReg, + Command ); + + // + //Wait for 400nsec for status to be available + // + pBS->Stall( 1 ); + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeNonDataCommand +// +// Description: Issues command where no data transfer takes place +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// VOID *Buffer, +// UINT32 ByteCount, +// UINT8 SectorCount, +// UINT8 LBALow, +// UINT8 LBAMid, +// UINT8 LBAHigh, +// UINT8 Device, +// UINT8 Command, +// Output: +// *Buffer +// +// Modified: +// +// Referrals: IdeSetFeatureCommand +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeNonDataCommand( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN UINT8 Features, + IN UINT8 SectorCount, + IN UINT8 LBALow, + IN UINT8 LBAMid, + IN UINT8 LBAHigh, + IN UINT8 Device, + IN UINT8 Command ) +{ + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + EFI_STATUS Status; + UINT8 Data8; + + // + //Select the drive + // + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.DeviceReg, Device ); + + // + //Wiat for DRDY to be set + // + Status = WaitforBitSet( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + DRDY, + DRDY_TIMEOUT ); + + if ( EFI_ERROR( Status )) { + return EFI_TIMEOUT; + } + + // + //Issue the Command + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.FeatureReg, + Features ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.SectorCountReg, + SectorCount ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBALowReg, + LBALow ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBAMidReg, + LBAMid ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBAHighReg, + LBAHigh ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.CommandReg, + Command ); + + // + //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.ControlBlock.AlternateStatusReg, + BSY | DRQ, + gPlatformIdeProtocol->PoweonBusyClearTimeout ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // + //Check for any errors + // + IdeReadByte( IdeBusInterface->PciIO, Regs.CommandBlock.StatusReg, &Data8 ); + + if ( Data8 & (DF | ERR)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeNonDataCommandExp +// +// Description: Issues command where no data transfer takes place +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// VOID *Buffer, +// UINT32 ByteCount, +// UINT8 SectorCount, +// UINT8 SectorCountExp, +// UINT8 LBALow, +// UINT8 LBALowExp, +// UINT8 LBAMid, +// UINT8 LBAMidExp, +// UINT8 LBAHigh, +// UINT8 LBAHighExp, +// UINT8 Device, +// UINT8 Command, +// Output: +// *Buffer +// +// Modified: +// +// Referrals: IdeSetFeatureCommand +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeNonDataCommandExp( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN UINT8 Features, + IN UINT8 SectorCount, + IN UINT8 SectorCountExp, + IN UINT8 LBALow, + IN UINT8 LBALowExp, + IN UINT8 LBAMid, + IN UINT8 LBAMidExp, + IN UINT8 LBAHigh, + IN UINT8 LBAHighExp, + IN UINT8 Device, + IN UINT8 Command ) +{ + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + EFI_STATUS Status; + UINT8 Data8; + + // + //Select the drive + // + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.DeviceReg, Device ); + + // + //Wiat for DRDY to be set + // + Status = WaitforBitSet( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + DRDY, + DRDY_TIMEOUT ); + + if ( EFI_ERROR( Status )) { + return EFI_TIMEOUT; + } + + // 48 Bit LBA + // Write the Upper LBA DWORD and Upper byte of Sector Count + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.SectorCountReg, + SectorCountExp); + + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBALowReg, + LBALowExp); + + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBAMidReg, + LBAMidExp); + + IdeWriteByte( IdeBusInterface->PciIO, Regs.CommandBlock.LBAHighReg, + LBAHighExp); + + // + //Issue the Command + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.FeatureReg, + Features ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.SectorCountReg, + SectorCount ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBALowReg, + LBALow ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBAMidReg, + LBAMid ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.LBAHighReg, + LBAHigh ); + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.CommandReg, + Command ); + + // + //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.ControlBlock.AlternateStatusReg, + BSY | DRQ, + gPlatformIdeProtocol->PoweonBusyClearTimeout ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // + //Check for any errors + // + IdeReadByte( IdeBusInterface->PciIO, Regs.CommandBlock.StatusReg, &Data8 ); + + if ( Data8 & (DF | ERR)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: AtaIdentifyCommand +// +// Description: Issues IDENTIFY DATA command (0xEC) +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// IN OUT VOID *Buffer +// +// Output: +// *Buffer +// +// Modified: +// +// Referrals: AtaPioDataIn +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AtaIdentifyCommand( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN OUT VOID *Buffer ) +{ + EFI_STATUS Status = AtaPioDataIn( + IdeBusInterface, + Buffer, + 512, + 0, + 0, + 0, + 0, + 0, + IdeBusInterface->IdeDevice.Device << 4, + IDENTIFY_COMMAND, + FALSE ); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: AtapiIdentifyCommand +// +// Description: Issues IDENTIFY PACKET DATA command (0xA1) +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// IN OUT VOID *Buffer +// +// Output: +// *Buffer +// +// Modified: +// +// Referrals: AtaPioDataIn +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS AtapiIdentifyCommand( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN OUT VOID *Buffer ) +{ + return AtaPioDataIn( + IdeBusInterface, + Buffer, + 512, // Byte Count + 0, + 0, + 0, + 0, + 0, + IdeBusInterface->IdeDevice.Device << 4, + IDENTIFY_PACKET_COMMAND, + FALSE ); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: GetIdentifyData +// +// Description: Gets Identify command data. +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: ATA/ATAPI device type should have beeen known already. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS GetIdentifyData( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN OUT VOID *Buffer ) +{ + // + //check whether it is a ATA or ATAPI device + // + if ( IdeBusInterface->IdeDevice.DeviceType == ATAPI ) { + return AtaPioDataIn( + IdeBusInterface, + Buffer, + 512, // Byte Count + 0, + 0, + 0, + 0, + 0, + IdeBusInterface->IdeDevice.Device << 4, + IDENTIFY_PACKET_COMMAND, + FALSE ); + } + else { + EFI_STATUS Status = AtaPioDataIn( + IdeBusInterface, + Buffer, + 512, + 0, + 0, + 0, + 0, + 0, + IdeBusInterface->IdeDevice.Device << 4, + IDENTIFY_COMMAND, + FALSE ); + + return Status; + } +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeSetFeatureCommand +// +// Description: Issue a ATA Non-Data Command +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: IdeNonDataCommand +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeSetFeatureCommand( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + UINT8 SubCommand, + UINT8 Mode ) +{ + return IdeNonDataCommand( + IdeBusInterface, + SubCommand, + Mode, + 0, + 0, + 0, + IdeBusInterface->IdeDevice.Device << 4, + SET_FEATURE_COMMAND ); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeSoftReset +// +// Description: Issue a Soft Reset +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: DetectIdeDevice +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeSoftReset( + IN IDE_BUS_PROTOCOL *IdeBusInterface ) +{ + UINT8 Device = IdeBusInterface->IdeDevice.Device; + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + UINT8 Data8; + + PROGRESS_CODE( DXE_IDE_RESET ); + + // + //Select the drive. Not needed. + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.DeviceReg, + Device << 4 ); + + // + //Read the status Register + // + IdeReadByte( IdeBusInterface->PciIO, Regs.CommandBlock.StatusReg, &Data8 ); + + // + //If BSY bit set, don't issue Soft reset + // + if ( Data8 & 0x80 ) { + return EFI_DEVICE_ERROR; + } + + // + //Assert SRST, disable nIEN + // + Data8 = SRST | nIEN; + IdeWriteByte( IdeBusInterface->PciIO, + Regs.ControlBlock.DeviceControlReg, + Data8 ); + pBS->Stall( 100 ); // 100 usec + + // + //Deassert SRST + // + Data8 = nIEN; + IdeWriteByte( IdeBusInterface->PciIO, + Regs.ControlBlock.DeviceControlReg, + Data8 ); + pBS->Stall( 10000 ); // 10 msec + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: WaitForCmdCompletionWithTimeOutValue +// +// Description: Waits for BSY bit to get clear +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface +// IN UINT32 TimeOutValue +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: AtaReadWritePio +// +// Notes: Wait for BSY bit to get clear. Check for any errors. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS WaitForCmdCompletionWithTimeOutValue( + IN IDE_BUS_PROTOCOL *IdeBusInterface, + IN UINT32 TimeOutvalue ) +{ + UINT8 Data8; + EFI_STATUS Status; + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + + // Read ATL_STATUS and ignore the result. Just a delay + IdeReadByte( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + &Data8 ); + + // if the Timeout Value is 0, check Busy bit to clear without Timeout Value. + // Otherwise Use the Timeout value to check the Busy bit to clear. + if ( TimeOutvalue == 0 ) { + // + //Check for BSY bit to be clear without Timout value + // + Status = WaitforBitClearWithoutTimeout( + IdeBusInterface->PciIO, + Regs.ControlBlock. + AlternateStatusReg, + BSY ); + } + else { + // + //Check for BSY bit to be clear + // + Status = WaitforBitClear( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + BSY, + TimeOutvalue ); + } + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + //Check for errors. + IdeReadByte( IdeBusInterface->PciIO, + Regs.CommandBlock.StatusReg, + &Data8 ); + + if ( Data8 & (ERR | DF)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: WaitForCmdCompletion +// +// Description: Waits for BSY bit to get clear +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: AtaReadWritePio +// +// Notes: Wait for BSY bit to get clear. Check for any errors. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS WaitForCmdCompletion( + IN IDE_BUS_PROTOCOL *IdeBusInterface ) +{ + UINT8 Data8; + EFI_STATUS Status; + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + + // + //Read ATL_STATUS and ignore the result. Just a delay + // + IdeReadByte( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + &Data8 ); + + // + //Check for BSY bit to be clear + // + Status = WaitforBitClear( IdeBusInterface->PciIO, + Regs.ControlBlock.AlternateStatusReg, + BSY, + COMMAND_COMPLETE_TIMEOUT ); + + if ( EFI_ERROR( Status )) { + return EFI_DEVICE_ERROR; + } + + // + //Check for errors. + // + IdeReadByte( IdeBusInterface->PciIO, Regs.CommandBlock.StatusReg, &Data8 ); + + if ( Data8 & (ERR | DF)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: DisableIdeInterrupt +// +// Description: Disabled Interrupt generation feature +// +// Input: +// IDE_BUS_PROTOCOL *IdeBusInterface; +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +void DisableIdeInterrupt( + IN IDE_BUS_PROTOCOL *IdeBusInterface ) +{ + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + UINT8 Data8, Flags; + + // + // Disable IEN + // + IdeWriteByte( IdeBusInterface->PciIO, Regs.ControlBlock.DeviceControlReg, 2 ); + + // + //Clear interrupt status + // + IdeReadByte( IdeBusInterface->PciIO, + Regs.BusMasterBlock.BMStatusRegister, + &Data8 ); + Flags = Data8; + // + // Preserve DMA capabilities and set Interrupt bit + // + Data8 = (Data8 & 0x60); + + if ( Flags & BM_INTERRUPT ) { + Data8 |= BM_INTERRUPT; + } + IdeWriteByte( IdeBusInterface->PciIO, + Regs.BusMasterBlock.BMStatusRegister, + Data8 ); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: CheckDriveReady +// +// Description: Check if BSY is cleared and DRDY set +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS CheckDriveReady( + IN IDE_BUS_PROTOCOL *IdeBusInterface ) +{ + IO_REGS Regs = IdeBusInterface->IdeDevice.Regs; + UINT8 Data8; + + // + //Select the drive + // + IdeWriteByte( IdeBusInterface->PciIO, + Regs.CommandBlock.DeviceReg, + IdeBusInterface->IdeDevice.Device << 4 ); + + // + //Read Alt Status + // + IdeReadByte( IdeBusInterface->PciIO, + Regs.ControlBlock.DeviceControlReg, + &Data8 ); + + if ((Data8 & 0xc0) == 0x40 ) { + return EFI_SUCCESS; + } + + return EFI_DEVICE_ERROR; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: WaitforBitSet +// +// Description: Checks for a particular Bit to be set for a given amount of time +// +// Input: +// IN EFI_PCI_IO_PROTOCOL *PciIO, +// UINT16 AlternateStatusReg, +// UINT8 BitSet, +// UINT32 TimeOut +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS WaitforBitSet( + IN EFI_PCI_IO_PROTOCOL *PciIO, + UINT16 AlternateStatusReg, + UINT8 BitSet, + UINT32 TimeOut ) +{ + UINT8 Delay; + UINT8 Data8; + + for (; TimeOut > 0; TimeOut-- ) + { + for ( Delay = 100; Delay > 0; Delay-- ) + { + IdeReadByte( PciIO, AlternateStatusReg, &Data8 ); + + if ( Data8 & BitSet ) { + return EFI_SUCCESS; + } + pBS->Stall( 10 ); // 10usec + } + } + return EFI_TIMEOUT; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: WaitforBitClear +// +// Description: Waits for the given bit to be clear +// +// Input: +// UINT16 AlternateStatus, +// UINT8 BitClear +// UINT32 BUSY_CLEAR_TIMEOUT // Millisecond +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS WaitforBitClear( + IN EFI_PCI_IO_PROTOCOL *PciIO, + UINT16 AlternateStatus, + UINT8 BitClear, + UINT32 Timeout ) +{ + UINT8 Delay; + UINT8 Data8; + + for (; Timeout > 0; Timeout-- ) + { + for ( Delay = 100; Delay > 0; Delay-- ) + { + IdeReadByte( PciIO, AlternateStatus, &Data8 ); + + if ( !(Data8 & BitClear)) { + return EFI_SUCCESS; + } + pBS->Stall( 10 ); // 10 Usec + } + } + return EFI_TIMEOUT; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: WaitforBitClearWithoutTimeout +// +// Description: Waits for the given bit to be clear +// +// Input: +// UINT16 AlternateStatus, +// UINT8 BitClear +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS WaitforBitClearWithoutTimeout( + IN EFI_PCI_IO_PROTOCOL *PciIO, + UINT16 AlternateStatus, + UINT8 BitClear ) +{ + UINT8 Data8; + + do + { + IdeReadByte( PciIO, AlternateStatus, &Data8 ); + + if ( !(Data8 & BitClear)) { + return EFI_SUCCESS; + } + pBS->Stall( 10 ); // 10 Usec + } while ( 1 ); + + return EFI_NOT_FOUND; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: ReturnMSBset +// +// Description: Returns the MOST significant Bit set. +// +// Input: +// UINT32 Data +// +// Output: +// UINT8 +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINT8 ReturnMSBset( + UINT32 Data ) +{ + UINT8 Index; + UINT8 Value = 0xFF; + + for ( Index = 0; Index < 32; Index++ ) + { + if ( Data & 1 ) { + Value = Index; + } + Data >>= 1; + } + + return Value; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeReadByte +// +// Description: Reads 1 Byte of data from the IO port +// +// Input: +// IN EFI_PCI_IO_PROTOCOL *PciIO, +// IN UINT16 Register, +// OUT UINT8 *Data8 +// +// Output: +// OUT UINT8 *Data8 +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeReadByte( + IN EFI_PCI_IO_PROTOCOL *PciIO, + IN UINT16 Register, + OUT UINT8 *Data8 ) +{ + PciIO->Io. Read( + PciIO, + EfiPciIoWidthFifoUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + Register, + 1, + Data8 ); + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeReadMultipleByte +// +// Description: Reads N Bytes of data from the IO port +// +// Input: +// IN EFI_PCI_IO_PROTOCOL *PciIO, +// IN UINT16 Register, +// IN UINT64 Count +// OUT UINT8 *Data8 +// +// Output: +// OUT UINT8 *Data8 +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeReadMultipleByte( + IN EFI_PCI_IO_PROTOCOL *PciIO, + IN UINT16 Register, + IN UINT32 Count, + OUT UINT8 *Data8 ) +{ + EFI_STATUS Status; + + Status = PciIO->Io.Read( + PciIO, + EfiPciIoWidthFifoUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + Register, + Count, + Data8 ); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeReadWord +// +// Description: Reads 1 Word of data from the IO port +// +// Input: +// IN EFI_PCI_IO_PROTOCOL *PciIO, +// IN UINT16 Register, +// OUT UINT16 *Data16 +// +// Output: +// OUT UINT16 *Data16 +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeReadWord( + IN EFI_PCI_IO_PROTOCOL *PciIO, + IN UINT16 Register, + OUT UINT16 *Data16 ) +{ + EFI_STATUS Status; + + Status = PciIO->Io.Read( + PciIO, + EfiPciIoWidthFifoUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + Register, + 1, + Data16 ); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeReadMultipleWord +// +// Description: Reads N Word of data from the IO port +// +// Input: +// IN EFI_PCI_IO_PROTOCOL *PciIO, +// IN UINT16 Register, +// IN UINT32 Count (Count in WORDS) +// OUT UINT8 *Data16 +// +// Output: +// OUT UINT16 *Data16 +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeReadMultipleWord( + IN EFI_PCI_IO_PROTOCOL *PciIO, + IN UINT16 Register, + IN UINT32 Count, + OUT UINT16 *Data16 ) +{ + EFI_STATUS Status; + UINT16 *Buffer = Data16; + BOOLEAN MemoryAllocated = FALSE; + + // + //Allocate memory only if ADDRESS is not WORD aligned + // + if ((UINTN)Data16 & 1 ) { + Status = pBS->AllocatePool( EfiBootServicesData, + Count * sizeof(UINT16), + (VOID**)&Buffer ); + + if ( EFI_ERROR( Status )) { + return EFI_OUT_OF_RESOURCES; + } + MemoryAllocated = TRUE; + } + + Status = PciIO->Io.Read( + PciIO, + EfiPciIoWidthFifoUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + Register, + Count, + Buffer ); + + if ( MemoryAllocated ) { + pBS->CopyMem( Data16, Buffer, Count * sizeof(UINT16)); + pBS->FreePool( Buffer ); + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeWriteByte +// +// Description: Writes 1 Byte of data to the IO port +// +// Input: +// IN EFI_PCI_IO_PROTOCOL *PciIO, +// IN UINT16 Register, +// OUT UINT8 Data8 +// +// Output: +// OUT UINT8 *Data8 +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeWriteByte( + IN EFI_PCI_IO_PROTOCOL *PciIO, + IN UINT16 Register, + IN UINT8 Data8 ) +{ + PciIO->Io.Write( + PciIO, + EfiPciIoWidthFifoUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + Register, + 1, + &Data8 ); + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeWriteMultipleByte +// +// Description: Writes N Bytes of data to the IO port +// +// Input: +// IN EFI_PCI_IO_PROTOCOL *PciIO, +// IN UINT16 Register, +// IN UINT32 Count (Count in BYTES) +// IN UINT8 *Data8 +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeWriteMultipleByte( + IN EFI_PCI_IO_PROTOCOL *PciIO, + IN UINT16 Register, + IN UINT32 Count, + IN UINT8 *Data8 ) +{ + EFI_STATUS Status; + + Status = PciIO->Io.Write( + PciIO, + EfiPciIoWidthFifoUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + Register, + Count, + Data8 ); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeWriteWord +// +// Description: Writes 1 word of data to the IO port +// +// Input: +// IN EFI_PCI_IO_PROTOCOL *PciIO, +// IN UINT16 Register, +// OUT UINT16 *Data16 +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeWriteWord( + IN EFI_PCI_IO_PROTOCOL *PciIO, + IN UINT16 Register, + IN UINT16 Data16 ) +{ + PciIO->Io.Write( + PciIO, + EfiPciIoWidthFifoUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + Register, + 1, + &Data16 ); + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeWriteMultipleWord +// +// Description: Writes N Words of data to the IO port +// +// Input: +// IN EFI_PCI_IO_PROTOCOL *PciIO, +// IN UINT16 Register, +// IN UINT64 Count (Count in WORDS) +// IN UINT16 *Data16 +// +// Output: +// +// Modified: +// +// Referrals: +// +// Notes: +// Count : # of WORDs to write +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeWriteMultipleWord( + IN EFI_PCI_IO_PROTOCOL *PciIO, + IN UINT16 Register, + IN UINT32 Count, + IN UINT16 *Data16 ) +{ + EFI_STATUS Status; + UINT16 *Buffer = Data16; + BOOLEAN MemoryAllocated = FALSE; + + // + // Allocate memory only if ADDRESS is not WORD aligned + // + if ((UINTN)Data16 & 1 ) { + Status = pBS->AllocatePool( EfiBootServicesData, + Count * sizeof(UINT16), + (VOID**)&Buffer ); + + if ( EFI_ERROR( Status )) { + return EFI_OUT_OF_RESOURCES; + } + MemoryAllocated = TRUE; + + pBS->CopyMem( Buffer, Data16, Count * sizeof(UINT16)); + } + + Status = PciIO->Io.Write( + PciIO, + EfiPciIoWidthFifoUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + Register, + Count, + Buffer ); + + if ( MemoryAllocated ) { + pBS->FreePool( Buffer ); + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: IdeWriteDword +// +// Description: Writes 1 Dword of data to the IO port +// +// Input: +// IN EFI_PCI_IO_PROTOCOL *PciIO, +// IN UINT16 Register, +// OUT UINT16 *Data16 +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS IdeWriteDword( + IN EFI_PCI_IO_PROTOCOL *PciIO, + IN UINT16 Register, + IN UINT32 Data32 ) +{ + PciIO->Io.Write( + PciIO, + EfiPciIoWidthFifoUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, + Register, + 1, + &Data32 ); + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: Check48BitCommand +// +// Description: Checks if the command is for 48-bit LBA +// +// Input: +// IN UINT8 Command +// +// Output: +// TRUE/FLASE +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN Check48BitCommand( + IN UINT8 Command ) +{ + if ( Command == READ_SECTORS_EXT + || Command == READ_MULTIPLE_EXT + || Command == WRITE_SECTORS_EXT + || Command == WRITE_MULTIPLE_EXT + || Command == READ_DMA_EXT + || Command == WRITE_DMA_EXT ) { + return TRUE; + } + else { + return FALSE; + } +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2010, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** |