X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=IntelFrameworkModulePkg%2FBus%2FPci%2FIdeBus%2FDxe%2Fata.c;fp=IntelFrameworkModulePkg%2FBus%2FPci%2FIdeBus%2FDxe%2Fata.c;h=0000000000000000000000000000000000000000;hp=ec546bb6b24b41121e56297db0907aa815bffefa;hb=69b26c155a943267c38b0d770e8a83dfc82ef189;hpb=a0741b93e128587b8f2b033f0efcbd5b900dc904 diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c deleted file mode 100644 index ec546bb6b2..0000000000 --- a/IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c +++ /dev/null @@ -1,2624 +0,0 @@ -/** @file - Copyright (c) 2006 - 2007 Intel Corporation.
- All rights reserved. This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - - @par Revision Reference: - 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including - update - ATAIdentity() func - update - AtaBlockIoReadBlocks() func - update - AtaBlockIoWriteBlocks() func - add - AtaAtapi6Identify() func - add - AtaReadSectorsExt() func - add - AtaWriteSectorsExt() func - add - AtaPioDataInExt() func - add - AtaPioDataOutExt() func - -**/ - -#include "idebus.h" - -/** - Sends out an ATA Identify Command to the specified device. - - This function is called by DiscoverIdeDevice() during its device - identification. It sends out the ATA Identify Command to the - specified device. Only ATA device responses to this command. If - the command succeeds, it returns the Identify data structure which - contains information about the device. This function extracts the - information it needs to fill the IDE_BLK_IO_DEV data structure, - including device type, media block size, media capacity, and etc. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure,used - to record all the information of the IDE device. - - @retval EFI_SUCCESS Identify ATA device successfully. - - @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or - device is not ATA device. - - @note - parameter IdeDev will be updated in this function. - -**/ -EFI_STATUS -ATAIdentify ( - IN IDE_BLK_IO_DEV *IdeDev - ) -{ - EFI_STATUS Status; - EFI_IDENTIFY_DATA *AtaIdentifyPointer; - UINT32 Capacity; - UINT8 DeviceSelect; - - // - // AtaIdentifyPointer is used for accommodating returned IDENTIFY data of - // the ATA Identify command - // - AtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA)); - - // - // use ATA PIO Data In protocol to send ATA Identify command - // and receive data from device - // - DeviceSelect = (UINT8) ((IdeDev->Device) << 4); - Status = AtaPioDataIn ( - IdeDev, - (VOID *) AtaIdentifyPointer, - sizeof (EFI_IDENTIFY_DATA), - ATA_CMD_IDENTIFY_DRIVE, - DeviceSelect, - 0, - 0, - 0, - 0 - ); - // - // If ATA Identify command succeeds, then according to the received - // IDENTIFY data, - // identify the device type ( ATA or not ). - // If ATA device, fill the information in IdeDev. - // If not ATA device, return IDE_DEVICE_ERROR - // - if (!EFI_ERROR (Status)) { - - IdeDev->pIdData = AtaIdentifyPointer; - - // - // Print ATA Module Name - // - PrintAtaModuleName (IdeDev); - - // - // bit 15 of pAtaIdentify->config is used to identify whether device is - // ATA device or ATAPI device. - // if 0, means ATA device; if 1, means ATAPI device. - // - if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) { - // - // Detect if support S.M.A.R.T. If yes, enable it as default - // - AtaSMARTSupport (IdeDev); - - // - // Check whether this device needs 48-bit addressing (ATAPI-6 ata device) - // - Status = AtaAtapi6Identify (IdeDev); - if (!EFI_ERROR (Status)) { - // - // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify() - // - return EFI_SUCCESS; - } - // - // This is a hard disk <= 120GB capacity, treat it as normal hard disk - // - IdeDev->Type = IdeHardDisk; - - // - // Block Media Information: - // Media->LogicalPartition , Media->WriteCaching will be filled - // in the DiscoverIdeDevcie() function. - // - IdeDev->BlkIo.Media->IoAlign = 4; - IdeDev->BlkIo.Media->MediaId = 1; - IdeDev->BlkIo.Media->RemovableMedia = FALSE; - IdeDev->BlkIo.Media->MediaPresent = TRUE; - IdeDev->BlkIo.Media->ReadOnly = FALSE; - IdeDev->BlkIo.Media->BlockSize = 0x200; - - // - // Calculate device capacity - // - Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) | - AtaIdentifyPointer->AtaData.user_addressable_sectors_lo ; - IdeDev->BlkIo.Media->LastBlock = Capacity - 1; - - return EFI_SUCCESS; - - } - } - - gBS->FreePool (AtaIdentifyPointer); - // - // Make sure the pIdData will not be freed again. - // - IdeDev->pIdData = NULL; - - return EFI_DEVICE_ERROR; -} - - -/** - This function is called by ATAIdentify() to identity whether this disk - supports ATA/ATAPI6 48bit addressing, ie support >120G capacity - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @retval EFI_SUCCESS The disk specified by IdeDev is a Atapi6 supported one - and 48-bit addressing must be used - - @retval EFI_UNSUPPORTED The disk dosn't not support Atapi6 or it supports but - the capacity is below 120G, 48bit addressing is not - needed - - @note - This function must be called after DEVICE_IDENTITY command has been - successfully returned - -**/ -EFI_STATUS -AtaAtapi6Identify ( - IN IDE_BLK_IO_DEV *IdeDev - ) -{ - UINT8 Index; - EFI_LBA TmpLba; - EFI_LBA Capacity; - EFI_IDENTIFY_DATA *Atapi6IdentifyStruct; - - if (IdeDev->pIdData == NULL) { - return EFI_UNSUPPORTED; - } - - Atapi6IdentifyStruct = IdeDev->pIdData; - - if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & BIT10) == 0) { - // - // The device dosn't support 48 bit addressing - // - return EFI_UNSUPPORTED; - } - - // - // 48 bit address feature set is supported, get maximum capacity - // - Capacity = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[0]; - for (Index = 1; Index < 4; Index++) { - // - // Lower byte goes first: word[100] is the lowest word, word[103] is highest - // - TmpLba = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[Index]; - Capacity |= LShiftU64 (TmpLba, 16 * Index); - } - - if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) { - // - // Capacity exceeds 120GB. 48-bit addressing is really needed - // - IdeDev->Type = Ide48bitAddressingHardDisk; - - // - // Fill block media information:Media->LogicalPartition , - // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function. - // - IdeDev->BlkIo.Media->IoAlign = 4; - IdeDev->BlkIo.Media->MediaId = 1; - IdeDev->BlkIo.Media->RemovableMedia = FALSE; - IdeDev->BlkIo.Media->MediaPresent = TRUE; - IdeDev->BlkIo.Media->ReadOnly = FALSE; - IdeDev->BlkIo.Media->BlockSize = 0x200; - IdeDev->BlkIo.Media->LastBlock = Capacity - 1; - - return EFI_SUCCESS; - } - - return EFI_UNSUPPORTED; -} - -/** - This function is called by ATAIdentify() or ATAPIIdentify() - to print device's module name. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - -**/ -VOID -PrintAtaModuleName ( - IN IDE_BLK_IO_DEV *IdeDev - ) -{ - if (IdeDev->pIdData == NULL) { - return ; - } - - SwapStringChars (IdeDev->ModelName, IdeDev->pIdData->AtaData.ModelName, 40); - IdeDev->ModelName[40] = 0x00; -} - -/** - This function is used to send out ATA commands conforms to the - PIO Data In Protocol. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *Buffer - buffer contained data transferred from device to host. - - @param[in] ByteCount - data size in byte unit of the buffer. - - @param[in] AtaCommand - value of the Command Register - - @param[in] Head - value of the Head/Device Register - - @param[in] SectorCount - value of the Sector Count Register - - @param[in] SectorNumber - value of the Sector Number Register - - @param[in] CylinderLsb - value of the low byte of the Cylinder Register - - @param[in] CylinderMsb - value of the high byte of the Cylinder Register - - @retval EFI_SUCCESS send out the ATA command and device send required - data successfully. - - @retval EFI_DEVICE_ERROR command sent failed. - -**/ -EFI_STATUS -AtaPioDataIn ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *Buffer, - IN UINT32 ByteCount, - IN UINT8 AtaCommand, - IN UINT8 Head, - IN UINT8 SectorCount, - IN UINT8 SectorNumber, - IN UINT8 CylinderLsb, - IN UINT8 CylinderMsb - ) -{ - UINTN WordCount; - UINTN Increment; - UINT16 *Buffer16; - EFI_STATUS Status; - - Status = WaitForBSYClear (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // e0:1110,0000-- bit7 and bit5 are reserved bits. - // bit6 set means LBA mode - // - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->Head, - (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head) - ); - - // - // All ATAPI device's ATA commands can be issued regardless of the - // state of the DRDY - // - if (IdeDev->Type == IdeHardDisk) { - - Status = DRDYReady (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - } - // - // set all the command parameters - // Before write to all the following registers, BSY and DRQ must be 0. - // - Status = DRQClear2 (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - if (AtaCommand == ATA_CMD_SET_FEATURES) { - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03); - } - - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb); - - // - // send command via Command Register - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); - - Buffer16 = (UINT16 *) Buffer; - - // - // According to PIO data in protocol, host can perform a series of reads to - // the data register after each time device set DRQ ready; - // The data size of "a series of read" is command specific. - // For most ATA command, data size received from device will not exceed - // 1 sector, hence the data size for "a series of read" can be the whole data - // size of one command request. - // For ATA command such as Read Sector command, the data size of one ATA - // command request is often larger than 1 sector, according to the - // Read Sector command, the data size of "a series of read" is exactly 1 - // sector. - // Here for simplification reason, we specify the data size for - // "a series of read" to 1 sector (256 words) if data size of one ATA command - // request is larger than 256 words. - // - Increment = 256; - - // - // used to record bytes of currently transfered data - // - WordCount = 0; - - while (WordCount < ByteCount / 2) { - // - // Poll DRQ bit set, data transfer can be performed only when DRQ is ready. - // - Status = DRQReady2 (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - Status = CheckErrorStatus (IdeDev); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // Get the byte count for one series of read - // - if ((WordCount + Increment) > ByteCount / 2) { - Increment = ByteCount / 2 - WordCount; - } - - IDEReadPortWMultiple ( - IdeDev->PciIo, - IdeDev->IoPort->Data, - Increment, - Buffer16 - ); - - WordCount += Increment; - Buffer16 += Increment; - - } - - DRQClear (IdeDev, ATATIMEOUT); - - return CheckErrorStatus (IdeDev); -} - -/** - This function is used to send out ATA commands conforms to the - PIO Data Out Protocol. - - @param *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param *Buffer buffer contained data transferred from host to device. - @param ByteCount data size in byte unit of the buffer. - @param AtaCommand value of the Command Register - @param Head value of the Head/Device Register - @param SectorCount value of the Sector Count Register - @param SectorNumber value of the Sector Number Register - @param CylinderLsb value of the low byte of the Cylinder Register - @param CylinderMsb value of the high byte of the Cylinder Register - - @retval EFI_SUCCESS send out the ATA command and device received required - data successfully. - - @retval EFI_DEVICE_ERROR command sent failed. - -**/ -EFI_STATUS -AtaPioDataOut ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *Buffer, - IN UINT32 ByteCount, - IN UINT8 AtaCommand, - IN UINT8 Head, - IN UINT8 SectorCount, - IN UINT8 SectorNumber, - IN UINT8 CylinderLsb, - IN UINT8 CylinderMsb - ) -{ - UINTN WordCount; - UINTN Increment; - UINT16 *Buffer16; - EFI_STATUS Status; - - Status = WaitForBSYClear (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // select device via Head/Device register. - // Before write Head/Device register, BSY and DRQ must be 0. - // - Status = DRQClear2 (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // e0:1110,0000-- bit7 and bit5 are reserved bits. - // bit6 set means LBA mode - // - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->Head, - (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head) - ); - - Status = DRDYReady (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // set all the command parameters - // Before write to all the following registers, BSY and DRQ must be 0. - // - Status = DRQClear2 (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb); - - // - // send command via Command Register - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); - - Buffer16 = (UINT16 *) Buffer; - - // - // According to PIO data out protocol, host can perform a series of - // writes to the data register after each time device set DRQ ready; - // The data size of "a series of read" is command specific. - // For most ATA command, data size written to device will not exceed 1 sector, - // hence the data size for "a series of write" can be the data size of one - // command request. - // For ATA command such as Write Sector command, the data size of one - // ATA command request is often larger than 1 sector, according to the - // Write Sector command, the data size of "a series of read" is exactly - // 1 sector. - // Here for simplification reason, we specify the data size for - // "a series of write" to 1 sector (256 words) if data size of one ATA command - // request is larger than 256 words. - // - Increment = 256; - WordCount = 0; - - while (WordCount < ByteCount / 2) { - - // - // DRQReady2-- read Alternate Status Register to determine the DRQ bit - // data transfer can be performed only when DRQ is ready. - // - Status = DRQReady2 (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - Status = CheckErrorStatus (IdeDev); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // Check the remaining byte count is less than 512 bytes - // - if ((WordCount + Increment) > ByteCount / 2) { - Increment = ByteCount / 2 - WordCount; - } - // - // perform a series of write without check DRQ ready - // - - IDEWritePortWMultiple ( - IdeDev->PciIo, - IdeDev->IoPort->Data, - Increment, - Buffer16 - ); - WordCount += Increment; - Buffer16 += Increment; - - } - - DRQClear (IdeDev, ATATIMEOUT); - - return CheckErrorStatus (IdeDev); -} - -/** - This function is used to analyze the Status Register and print out - some debug information and if there is ERR bit set in the Status - Register, the Error Register's value is also be parsed and print out. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @retval EFI_SUCCESS No err information in the Status Register. - @retval EFI_DEVICE_ERROR Any err information in the Status Register. - -**/ -EFI_STATUS -CheckErrorStatus ( - IN IDE_BLK_IO_DEV *IdeDev - ) -{ - UINT8 StatusRegister; - UINT8 ErrorRegister; - - StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); - - DEBUG_CODE_BEGIN (); - - if (StatusRegister & ATA_STSREG_DWF) { - DEBUG ( - (EFI_D_BLKIO, - "CheckErrorStatus()-- %02x : Error : Write Fault\n", - StatusRegister) - ); - } - - if (StatusRegister & ATA_STSREG_CORR) { - DEBUG ( - (EFI_D_BLKIO, - "CheckErrorStatus()-- %02x : Error : Corrected Data\n", - StatusRegister) - ); - } - - if (StatusRegister & ATA_STSREG_ERR) { - ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); - - if (ErrorRegister & ATA_ERRREG_BBK) { - DEBUG ( - (EFI_D_BLKIO, - "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n", - ErrorRegister) - ); - } - - if (ErrorRegister & ATA_ERRREG_UNC) { - DEBUG ( - (EFI_D_BLKIO, - "CheckErrorStatus()-- %02x : Error : Uncorrectable Data\n", - ErrorRegister) - ); - } - - if (ErrorRegister & ATA_ERRREG_MC) { - DEBUG ( - (EFI_D_BLKIO, - "CheckErrorStatus()-- %02x : Error : Media Change\n", - ErrorRegister) - ); - } - - if (ErrorRegister & ATA_ERRREG_ABRT) { - DEBUG ( - (EFI_D_BLKIO, - "CheckErrorStatus()-- %02x : Error : Abort\n", - ErrorRegister) - ); - } - - if (ErrorRegister & ATA_ERRREG_TK0NF) { - DEBUG ( - (EFI_D_BLKIO, - "CheckErrorStatus()-- %02x : Error : Track 0 Not Found\n", - ErrorRegister) - ); - } - - if (ErrorRegister & ATA_ERRREG_AMNF) { - DEBUG ( - (EFI_D_BLKIO, - "CheckErrorStatus()-- %02x : Error : Address Mark Not Found\n", - ErrorRegister) - ); - } - } - - DEBUG_CODE_END (); - - if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) { - return EFI_SUCCESS; - } - - return EFI_DEVICE_ERROR; - -} - -/** - This function is called by the AtaBlkIoReadBlocks() to perform - reading from media in block unit. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *DataBuffer - A pointer to the destination buffer for the data. - - @param[in] Lba - The starting logical block address to read from - on the device media. - - @param[in] NumberOfBlocks - The number of transfer data blocks. - - @return return status is fully dependent on the return status - of AtaPioDataIn() function. - -**/ -EFI_STATUS -AtaReadSectors ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *DataBuffer, - IN EFI_LBA Lba, - IN UINTN NumberOfBlocks - ) -{ - EFI_STATUS Status; - UINTN BlocksRemaining; - UINT32 Lba32; - UINT8 Lba0; - UINT8 Lba1; - UINT8 Lba2; - UINT8 Lba3; - UINT8 AtaCommand; - UINT8 SectorCount8; - UINT16 SectorCount; - UINTN ByteCount; - VOID *Buffer; - - Buffer = DataBuffer; - - // - // Using ATA Read Sector(s) command (opcode=0x20) with PIO DATA IN protocol - // - AtaCommand = ATA_CMD_READ_SECTORS; - - - BlocksRemaining = NumberOfBlocks; - - Lba32 = (UINT32) Lba; - - Status = EFI_SUCCESS; - - while (BlocksRemaining > 0) { - - // - // in ATA-3 spec, LBA is in 28 bit width - // - Lba0 = (UINT8) Lba32; - Lba1 = (UINT8) (Lba32 >> 8); - Lba2 = (UINT8) (Lba32 >> 16); - // - // low 4 bit of Lba3 stands for LBA bit24~bit27. - // - Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f); - - if (BlocksRemaining >= 0x100) { - - // - // SectorCount8 is sent to Sector Count register, 0x00 means 256 - // sectors to be read - // - SectorCount8 = 0x00; - // - // SectorCount is used to record the number of sectors to be read - // - SectorCount = 256; - } else { - - SectorCount8 = (UINT8) BlocksRemaining; - SectorCount = (UINT16) BlocksRemaining; - } - - // - // ByteCount is the number of bytes that will be read - // - ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize); - - // - // call AtaPioDataIn() to send Read Sector Command and receive data read - // - Status = AtaPioDataIn ( - IdeDev, - Buffer, - (UINT32) ByteCount, - AtaCommand, - Lba3, - SectorCount8, - Lba0, - Lba1, - Lba2 - ); - if (EFI_ERROR (Status)) { - return Status; - } - - Lba32 += SectorCount; - Buffer = ((UINT8 *) Buffer + ByteCount); - BlocksRemaining -= SectorCount; - } - - return Status; -} - -/** - This function is called by the AtaBlkIoWriteBlocks() to perform - writing onto media in block unit. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure,used - to record all the information of the IDE device. - - @param[in] *BufferData - A pointer to the source buffer for the data. - - @param[in] Lba - The starting logical block address to write onto - the device media. - - @param[in] NumberOfBlocks - The number of transfer data blocks. - - @return return status is fully dependent on the return status - of AtaPioDataOut() function. - -**/ -EFI_STATUS -AtaWriteSectors ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *BufferData, - IN EFI_LBA Lba, - IN UINTN NumberOfBlocks - ) -{ - EFI_STATUS Status; - UINTN BlocksRemaining; - UINT32 Lba32; - UINT8 Lba0; - UINT8 Lba1; - UINT8 Lba2; - UINT8 Lba3; - UINT8 AtaCommand; - UINT8 SectorCount8; - UINT16 SectorCount; - UINTN ByteCount; - VOID *Buffer; - - Buffer = BufferData; - - // - // Using Write Sector(s) command (opcode=0x30) with PIO DATA OUT protocol - // - AtaCommand = ATA_CMD_WRITE_SECTORS; - - BlocksRemaining = NumberOfBlocks; - - Lba32 = (UINT32) Lba; - - Status = EFI_SUCCESS; - - while (BlocksRemaining > 0) { - - Lba0 = (UINT8) Lba32; - Lba1 = (UINT8) (Lba32 >> 8); - Lba2 = (UINT8) (Lba32 >> 16); - Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f); - - if (BlocksRemaining >= 0x100) { - - // - // SectorCount8 is sent to Sector Count register, 0x00 means 256 sectors - // to be written - // - SectorCount8 = 0x00; - // - // SectorCount is used to record the number of sectors to be written - // - SectorCount = 256; - } else { - - SectorCount8 = (UINT8) BlocksRemaining; - SectorCount = (UINT16) BlocksRemaining; - } - - ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize); - - Status = AtaPioDataOut ( - IdeDev, - Buffer, - (UINT32) ByteCount, - AtaCommand, - Lba3, - SectorCount8, - Lba0, - Lba1, - Lba2 - ); - if (EFI_ERROR (Status)) { - return Status; - } - - Lba32 += SectorCount; - Buffer = ((UINT8 *) Buffer + ByteCount); - BlocksRemaining -= SectorCount; - } - - return Status; -} - -/** - This function is used to implement the Soft Reset on the specified - device. But, the ATA Soft Reset mechanism is so strong a reset method - that it will force resetting on both devices connected to the - same cable. - - It is called by IdeBlkIoReset(), a interface function of Block - I/O protocol. - - This function can also be used by the ATAPI device to perform reset when - ATAPI Reset command is failed. - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @retval EFI_SUCCESS Soft reset completes successfully. - @retval EFI_DEVICE_ERROR Any step during the reset process is failed. - - @note - The registers initial values after ATA soft reset are different - to the ATA device and ATAPI device. - -**/ -EFI_STATUS -AtaSoftReset ( - IN IDE_BLK_IO_DEV *IdeDev - ) -{ - - UINT8 DeviceControl; - - DeviceControl = 0; - // - // set SRST bit to initiate soft reset - // - DeviceControl |= ATA_CTLREG_SRST; - - // - // disable Interrupt - // - DeviceControl |= BIT1; - - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); - - // - // SRST should assert for at least 5 us, we use 10 us for - // better compatibility - // - gBS->Stall (10); - - // - // Enable interrupt to support UDMA, and clear SRST bit - // - DeviceControl = 0; - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); - - // - // Wait for at least 2 ms to check BSY status, we use 10 ms - // for better compatibility - // - gBS->Stall(10000); - // - // slave device needs at most 31s to clear BSY - // - if (WaitForBSYClear (IdeDev, 31000) == EFI_TIMEOUT) { - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; -} - -/** - This function is the ATA implementation for ReadBlocks in the - Block I/O Protocol interface. - - @param[in] *IdeBlkIoDevice - Indicates the calling context. - - @param[in] MediaId - The media id that the read request is for. - - @param[in] LBA - The starting logical block address to read from - on the device. - - @param[in] BufferSize - The size of the Buffer in bytes. This must be a - multiple of the intrinsic block size of the device. - - @param[out] *Buffer - A pointer to the destination buffer for the data. - The caller is responsible for either having implicit - or explicit ownership of the memory that data is read into. - - @retval EFI_SUCCESS Read Blocks successfully. - @retval EFI_DEVICE_ERROR Read Blocks failed. - @retval EFI_NO_MEDIA There is no media in the device. - @retval EFI_MEDIA_CHANGE The MediaId is not for the current media. - - @retval EFI_BAD_BUFFER_SIZE - The BufferSize parameter is not a multiple of the - intrinsic block size of the device. - - @retval EFI_INVALID_PARAMETER - The read request contains LBAs that are not valid, - or the data buffer is not valid. - - @note - If Read Block error because of device error, this function will call - AtaSoftReset() function to reset device. - -**/ -EFI_STATUS -AtaBlkIoReadBlocks ( - IN IDE_BLK_IO_DEV *IdeBlkIoDevice, - IN UINT32 MediaId, - IN EFI_LBA LBA, - IN UINTN BufferSize, - OUT VOID *Buffer - ) -{ - EFI_BLOCK_IO_MEDIA *Media; - UINTN BlockSize; - UINTN NumberOfBlocks; - EFI_STATUS Status; - - if (Buffer == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (BufferSize == 0) { - return EFI_SUCCESS; - } - - Status = EFI_SUCCESS; - - // - // Get the intrinsic block size - // - Media = IdeBlkIoDevice->BlkIo.Media; - BlockSize = Media->BlockSize; - - NumberOfBlocks = BufferSize / BlockSize; - - if (MediaId != Media->MediaId) { - return EFI_MEDIA_CHANGED; - } - - if (BufferSize % BlockSize != 0) { - return EFI_BAD_BUFFER_SIZE; - } - - if (!(Media->MediaPresent)) { - return EFI_NO_MEDIA; - } - - if (LBA > Media->LastBlock) { - return EFI_INVALID_PARAMETER; - } - - if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { - return EFI_INVALID_PARAMETER; - } - - if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { - return EFI_INVALID_PARAMETER; - } - - Status = EFI_SUCCESS; - if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) { - // - // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism - // - if (IdeBlkIoDevice->UdmaMode.Valid) { - Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); - } else { - Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); - } - } else { - // - // For ATA-3 compatible device, use ATA-3 read block mechanism - // - if (IdeBlkIoDevice->UdmaMode.Valid) { - Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); - } else { - Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); - } - } - - if (EFI_ERROR (Status)) { - AtaSoftReset (IdeBlkIoDevice); - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; - -} - -/** - This function is the ATA implementation for WriteBlocks in the - Block I/O Protocol interface. - - @param[in] *IdeBlkIoDevice - Indicates the calling context. - - @param[in] MediaId - The media id that the write request is for. - - @param[in] LBA - The starting logical block address to write onto - the device. - - @param[in] BufferSize - The size of the Buffer in bytes. This must be a - multiple of the intrinsic block size of the device. - - @param[out] *Buffer - A pointer to the source buffer for the data. - The caller is responsible for either having implicit - or explicit ownership of the memory that data is - written from. - - @retval EFI_SUCCESS Write Blocks successfully. - @retval EFI_DEVICE_ERROR Write Blocks failed. - @retval EFI_NO_MEDIA There is no media in the device. - @retval EFI_MEDIA_CHANGE The MediaId is not for the current media. - - @retval EFI_BAD_BUFFER_SIZE - The BufferSize parameter is not a multiple of the - intrinsic block size of the device. - - @retval EFI_INVALID_PARAMETER - The write request contains LBAs that are not valid, - or the data buffer is not valid. - - @note - If Write Block error because of device error, this function will call - AtaSoftReset() function to reset device. - -**/ -EFI_STATUS -AtaBlkIoWriteBlocks ( - IN IDE_BLK_IO_DEV *IdeBlkIoDevice, - IN UINT32 MediaId, - IN EFI_LBA LBA, - IN UINTN BufferSize, - OUT VOID *Buffer - ) -{ - - EFI_BLOCK_IO_MEDIA *Media; - UINTN BlockSize; - UINTN NumberOfBlocks; - EFI_STATUS Status; - - if (Buffer == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (BufferSize == 0) { - return EFI_SUCCESS; - } - - Status = EFI_SUCCESS; - - // - // Get the intrinsic block size - // - Media = IdeBlkIoDevice->BlkIo.Media; - BlockSize = Media->BlockSize; - NumberOfBlocks = BufferSize / BlockSize; - - if (MediaId != Media->MediaId) { - return EFI_MEDIA_CHANGED; - } - - if (BufferSize % BlockSize != 0) { - return EFI_BAD_BUFFER_SIZE; - } - - if (LBA > Media->LastBlock) { - return EFI_INVALID_PARAMETER; - } - - if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { - return EFI_INVALID_PARAMETER; - } - - if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { - return EFI_INVALID_PARAMETER; - } - - Status = EFI_SUCCESS; - if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) { - // - // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism - // - if (IdeBlkIoDevice->UdmaMode.Valid) { - Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); - } else { - Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); - } - } else { - // - // For ATA-3 compatible device, use ATA-3 write block mechanism - // - if (IdeBlkIoDevice->UdmaMode.Valid) { - Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); - } else { - Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); - } - } - - if (EFI_ERROR (Status)) { - AtaSoftReset (IdeBlkIoDevice); - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; -} - -/** - This function is called by the AtaBlkIoReadBlocks() to perform - reading from media in block unit. The function has been enhanced to - support >120GB access and transfer at most 65536 blocks per command - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *DataBuffer A pointer to the destination buffer for the data. - @param[in] StartLba The starting logical block address to read from - on the device media. - @param[in] NumberOfBlocks The number of transfer data blocks. - - @return return status is fully dependent on the return status - of AtaPioDataInExt() function. - -**/ -EFI_STATUS -AtaReadSectorsExt ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *DataBuffer, - IN EFI_LBA StartLba, - IN UINTN NumberOfBlocks - ) -{ - EFI_STATUS Status; - UINTN BlocksRemaining; - EFI_LBA Lba64; - UINT8 AtaCommand; - UINT16 SectorCount; - UINT32 ByteCount; - VOID *Buffer; - - // - // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol - // - AtaCommand = ATA_CMD_READ_SECTORS_EXT; - Buffer = DataBuffer; - BlocksRemaining = NumberOfBlocks; - Lba64 = StartLba; - Status = EFI_SUCCESS; - - while (BlocksRemaining > 0) { - - if (BlocksRemaining >= 0x10000) { - // - // SectorCount is used to record the number of sectors to be read - // Max 65536 sectors can be transfered at a time. - // - SectorCount = 0xffff; - } else { - SectorCount = (UINT16) BlocksRemaining; - } - - // - // ByteCount is the number of bytes that will be read - // - ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize); - - // - // call AtaPioDataInExt() to send Read Sector Command and receive data read - // - Status = AtaPioDataInExt ( - IdeDev, - Buffer, - ByteCount, - AtaCommand, - Lba64, - SectorCount - ); - if (EFI_ERROR (Status)) { - return Status; - } - - Lba64 += SectorCount; - Buffer = ((UINT8 *) Buffer + ByteCount); - BlocksRemaining -= SectorCount; - } - - return Status; -} - -/** - This function is called by the AtaBlkIoWriteBlocks() to perform - writing onto media in block unit. The function has been enhanced to - support >120GB access and transfer at most 65536 blocks per command - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure,used - to record all the information of the IDE device. - - @param[in] *DataBuffer - A pointer to the source buffer for the data. - - @param[in] Lba - The starting logical block address to write onto - the device media. - - @param[in] NumberOfBlocks - The number of transfer data blocks. - - @return status is fully dependent on the return status - of AtaPioDataOutExt() function. - -**/ -EFI_STATUS -AtaWriteSectorsExt ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *DataBuffer, - IN EFI_LBA StartLba, - IN UINTN NumberOfBlocks - ) -{ - EFI_STATUS Status; - EFI_LBA Lba64; - UINTN BlocksRemaining; - UINT8 AtaCommand; - UINT16 SectorCount; - UINT32 ByteCount; - VOID *Buffer; - - // - // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol - // - AtaCommand = ATA_CMD_WRITE_SECTORS_EXT; - Lba64 = StartLba; - Buffer = DataBuffer; - BlocksRemaining = NumberOfBlocks; - - Status = EFI_SUCCESS; - - while (BlocksRemaining > 0) { - - if (BlocksRemaining >= 0x10000) { - // - // SectorCount is used to record the number of sectors to be written. - // Max 65536 sectors can be transfered at a time. - // - SectorCount = 0xffff; - } else { - SectorCount = (UINT16) BlocksRemaining; - } - - // - // ByteCount is the number of bytes that will be written - // - ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize); - - // - // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command - // - Status = AtaPioDataOutExt ( - IdeDev, - Buffer, - ByteCount, - AtaCommand, - Lba64, - SectorCount - ); - if (EFI_ERROR (Status)) { - return Status; - } - - Lba64 += SectorCount; - Buffer = ((UINT8 *) Buffer + ByteCount); - BlocksRemaining -= SectorCount; - } - - return Status; -} - -/** - This function is used to send out ATA commands conforms to the - PIO Data In Protocol, supporting ATA/ATAPI-6 standard - - Comparing with ATA-3 data in protocol, we have two differents here:
- 1. Do NOT wait for DRQ clear before sending command into IDE device.(the - wait will frequently fail... cause writing function return error) - - 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly - slow down writing performance by 100 times!) - - @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in,out] *Buffer buffer contained data transferred from device to host. - @param[in] ByteCount data size in byte unit of the buffer. - @param[in] AtaCommand value of the Command Register - @param[in] StartLba the start LBA of this transaction - @param[in] SectorCount the count of sectors to be transfered - - @retval EFI_SUCCESS send out the ATA command and device send required - data successfully. - - @retval EFI_DEVICE_ERROR command sent failed. - -**/ -EFI_STATUS -AtaPioDataInExt ( - IN IDE_BLK_IO_DEV *IdeDev, - IN OUT VOID *Buffer, - IN UINT32 ByteCount, - IN UINT8 AtaCommand, - IN EFI_LBA StartLba, - IN UINT16 SectorCount - ) -{ - UINT8 DevSel; - UINT8 SectorCount8; - UINT8 LbaLow; - UINT8 LbaMid; - UINT8 LbaHigh; - UINTN WordCount; - UINTN Increment; - UINT16 *Buffer16; - EFI_STATUS Status; - - Status = WaitForBSYClear (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // Select device, set bit6 as 1 to indicate LBA mode is used - // - DevSel = (UINT8) (IdeDev->Device << 4); - DevSel |= 0x40; - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->Head, - DevSel - ); - - // - // Wait for DRDY singnal asserting. ATAPI device needn't wait - // - if ( (IdeDev->Type == IdeHardDisk) || - (IdeDev->Type == Ide48bitAddressingHardDisk)) { - - Status = DRDYReady (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - } - - // - // Fill feature register if needed - // - if (AtaCommand == ATA_CMD_SET_FEATURES) { - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03); - } - - // - // Fill the sector count register, which is a two-byte FIFO. Need write twice. - // - SectorCount8 = (UINT8) (SectorCount >> 8); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); - - SectorCount8 = (UINT8) SectorCount; - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); - - // - // Fill the start LBA registers, which are also two-byte FIFO - // - LbaLow = (UINT8) RShiftU64 (StartLba, 24); - LbaMid = (UINT8) RShiftU64 (StartLba, 32); - LbaHigh = (UINT8) RShiftU64 (StartLba, 40); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); - - LbaLow = (UINT8) StartLba; - LbaMid = (UINT8) RShiftU64 (StartLba, 8); - LbaHigh = (UINT8) RShiftU64 (StartLba, 16); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); - - // - // Send command via Command Register, invoking the processing of this command - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); - - Buffer16 = (UINT16 *) Buffer; - - // - // According to PIO data in protocol, host can perform a series of reads to - // the data register after each time device set DRQ ready; - // - - // - // 256 words - // - Increment = 256; - - // - // used to record bytes of currently transfered data - // - WordCount = 0; - - while (WordCount < ByteCount / 2) { - // - // Poll DRQ bit set, data transfer can be performed only when DRQ is ready. - // - Status = DRQReady2 (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - Status = CheckErrorStatus (IdeDev); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // Get the byte count for one series of read - // - if ((WordCount + Increment) > ByteCount / 2) { - Increment = ByteCount / 2 - WordCount; - } - - IDEReadPortWMultiple ( - IdeDev->PciIo, - IdeDev->IoPort->Data, - Increment, - Buffer16 - ); - - WordCount += Increment; - Buffer16 += Increment; - - } - - return CheckErrorStatus (IdeDev); -} - -/** - This function is used to send out ATA commands conforms to the - PIO Data Out Protocol, supporting ATA/ATAPI-6 standard - - Comparing with ATA-3 data out protocol, we have two differents here:
- 1. Do NOT wait for DRQ clear before sending command into IDE device.(the - wait will frequently fail... cause writing function return error) - - 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly - slow down writing performance by 100 times!) - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *Buffer buffer contained data transferred from host to device. - @param[in] ByteCount data size in byte unit of the buffer. - @param[in] AtaCommand value of the Command Register - @param[in] StartLba the start LBA of this transaction - @param[in] SectorCount the count of sectors to be transfered - - @retval EFI_SUCCESS send out the ATA command and device receive required - data successfully. - - @retval EFI_DEVICE_ERROR command sent failed. - -**/ -EFI_STATUS -AtaPioDataOutExt ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *Buffer, - IN UINT32 ByteCount, - IN UINT8 AtaCommand, - IN EFI_LBA StartLba, - IN UINT16 SectorCount - ) -{ - UINT8 DevSel; - UINT8 SectorCount8; - UINT8 LbaLow; - UINT8 LbaMid; - UINT8 LbaHigh; - UINTN WordCount; - UINTN Increment; - UINT16 *Buffer16; - EFI_STATUS Status; - - Status = WaitForBSYClear (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // Select device. Set bit6 as 1 to indicate LBA mode is used - // - DevSel = (UINT8) (IdeDev->Device << 4); - DevSel |= 0x40; - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->Head, - DevSel - ); - - // - // Wait for DRDY singnal asserting. - // - Status = DRDYReady (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // Fill feature register if needed - // - if (AtaCommand == ATA_CMD_SET_FEATURES) { - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03); - } - - // - // Fill the sector count register, which is a two-byte FIFO. Need write twice. - // - SectorCount8 = (UINT8) (SectorCount >> 8); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); - - SectorCount8 = (UINT8) SectorCount; - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); - - // - // Fill the start LBA registers, which are also two-byte FIFO - // - LbaLow = (UINT8) RShiftU64 (StartLba, 24); - LbaMid = (UINT8) RShiftU64 (StartLba, 32); - LbaHigh = (UINT8) RShiftU64 (StartLba, 40); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); - - LbaLow = (UINT8) StartLba; - LbaMid = (UINT8) RShiftU64 (StartLba, 8); - LbaHigh = (UINT8) RShiftU64 (StartLba, 16); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); - - // - // Send command via Command Register, invoking the processing of this command - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); - - Buffer16 = (UINT16 *) Buffer; - - // - // According to PIO Data Out protocol, host can perform a series of writes to - // the data register after each time device set DRQ ready; - // - Increment = 256; - - // - // used to record bytes of currently transfered data - // - WordCount = 0; - - while (WordCount < ByteCount / 2) { - // - // Poll DRQ bit set, data transfer can be performed only when DRQ is ready. - // - Status = DRQReady2 (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - Status = CheckErrorStatus (IdeDev); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // Write data into device by one series of writing to data register - // - if ((WordCount + Increment) > ByteCount / 2) { - Increment = ByteCount / 2 - WordCount; - } - - IDEWritePortWMultiple ( - IdeDev->PciIo, - IdeDev->IoPort->Data, - Increment, - Buffer16 - ); - - WordCount += Increment; - Buffer16 += Increment; - - } - // - // while - // - - return CheckErrorStatus (IdeDev); -} - - -/** - Enable SMART of the disk if supported - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure,used - to record all the information of the IDE device. - -**/ -VOID -AtaSMARTSupport ( - IN IDE_BLK_IO_DEV *IdeDev - ) -{ - EFI_STATUS Status; - BOOLEAN SMARTSupported; - UINT8 Device; - EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer; - UINT8 DeviceSelect; - UINT8 LBAMid; - UINT8 LBAHigh; - - // - // Detect if the device supports S.M.A.R.T. - // - if ((IdeDev->pIdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) { - // - // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one) - // - return ; - } else { - if ((IdeDev->pIdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) { - // - // S.M.A.R.T is not supported by the device - // - SMARTSupported = FALSE; - } else { - SMARTSupported = TRUE; - } - } - - if (!SMARTSupported) { - // - // Report nonsupport status code - // - REPORT_STATUS_CODE ( - EFI_ERROR_CODE | EFI_ERROR_MINOR, - (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED) - ); - } else { - // - // Enable this feature - // - REPORT_STATUS_CODE ( - EFI_PROGRESS_CODE, - (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE) - ); - - Device = (UINT8) ((IdeDev->Device << 4) | 0xe0); - Status = AtaNonDataCommandIn ( - IdeDev, - ATA_CMD_SMART, - Device, - ATA_SMART_ENABLE_OPERATION, - 0, - 0, - ATA_CONSTANT_4F, - ATA_CONSTANT_C2 - ); - // - // Detect if this feature is enabled - // - TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA)); - - DeviceSelect = (UINT8) ((IdeDev->Device) << 4); - Status = AtaPioDataIn ( - IdeDev, - (VOID *) TmpAtaIdentifyPointer, - sizeof (EFI_IDENTIFY_DATA), - ATA_CMD_IDENTIFY_DRIVE, - DeviceSelect, - 0, - 0, - 0, - 0 - ); - if (EFI_ERROR (Status)) { - gBS->FreePool (TmpAtaIdentifyPointer); - return ; - } - - // - // Check if the feature is enabled - // - if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) { - // - // Read status data - // - AtaNonDataCommandIn ( - IdeDev, - ATA_CMD_SMART, - Device, - ATA_SMART_RETURN_STATUS, - 0, - 0, - ATA_CONSTANT_4F, - ATA_CONSTANT_C2 - ); - LBAMid = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb); - LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb); - - if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) { - // - // The threshold exceeded condition is not detected by the device - // - REPORT_STATUS_CODE ( - EFI_PROGRESS_CODE, - (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD) - ); - - } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) { - // - // The threshold exceeded condition is detected by the device - // - REPORT_STATUS_CODE ( - EFI_PROGRESS_CODE, - (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD) - ); - } - - } else { - // - // Report disabled status code - // - REPORT_STATUS_CODE ( - EFI_ERROR_CODE | EFI_ERROR_MINOR, - (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED) - ); - } - - gBS->FreePool (TmpAtaIdentifyPointer); - } - - return ; -} - -/** - Send ATA Ext command into device with NON_DATA protocol - - @param IdeDev Standard IDE device private data structure - @param AtaCommand The ATA command to be sent - @param Device The value in Device register - @param Feature The value in Feature register - @param SectorCount The value in SectorCount register - @param LbaAddress The LBA address in 48-bit mode - - @retval EFI_SUCCESS Reading succeed - @retval EFI_DEVICE_ERROR Error executing commands on this device - -**/ -EFI_STATUS -AtaCommandIssueExt ( - IN IDE_BLK_IO_DEV *IdeDev, - IN UINT8 AtaCommand, - IN UINT8 Device, - IN UINT16 Feature, - IN UINT16 SectorCount, - IN EFI_LBA LbaAddress - ) -{ - EFI_STATUS Status; - UINT8 SectorCount8; - UINT8 Feature8; - UINT8 LbaLow; - UINT8 LbaMid; - UINT8 LbaHigh; - - Status = WaitForBSYClear (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility) - // - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->Head, - (UINT8) ((IdeDev->Device << 4) | 0xe0) - ); - - // - // ATA commands for ATA device must be issued when DRDY is set - // - Status = DRDYReady (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // Pass parameter into device register block - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); - - // - // Fill the feature register, which is a two-byte FIFO. Need write twice. - // - Feature8 = (UINT8) (Feature >> 8); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); - - Feature8 = (UINT8) Feature; - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); - - // - // Fill the sector count register, which is a two-byte FIFO. Need write twice. - // - SectorCount8 = (UINT8) (SectorCount >> 8); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); - - SectorCount8 = (UINT8) SectorCount; - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); - - // - // Fill the start LBA registers, which are also two-byte FIFO - // - LbaLow = (UINT8) RShiftU64 (LbaAddress, 24); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); - LbaLow = (UINT8) LbaAddress; - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); - - LbaMid = (UINT8) RShiftU64 (LbaAddress, 32); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); - LbaMid = (UINT8) RShiftU64 (LbaAddress, 8); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); - - LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); - LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); - - // - // Work around for Segate 160G disk writing - // - gBS->Stall (1800); - - // - // Send command via Command Register - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); - - // - // Stall at least 400ns - // - gBS->Stall (100); - - return EFI_SUCCESS; -} - -/** - Send ATA Ext command into device with NON_DATA protocol - - @param IdeDev Standard IDE device private data structure - @param AtaCommand The ATA command to be sent - @param Device The value in Device register - @param Feature The value in Feature register - @param SectorCount The value in SectorCount register - @param LbaAddress The LBA address in 48-bit mode - - @retval EFI_SUCCESS Reading succeed - @retval EFI_DEVICE_ERROR Error executing commands on this device - -**/ -EFI_STATUS -AtaCommandIssue ( - IN IDE_BLK_IO_DEV *IdeDev, - IN UINT8 AtaCommand, - IN UINT8 Device, - IN UINT16 Feature, - IN UINT16 SectorCount, - IN EFI_LBA LbaAddress - ) -{ - EFI_STATUS Status; - UINT8 SectorCount8; - UINT8 Feature8; - UINT8 Lba0; - UINT8 Lba1; - UINT8 Lba2; - UINT8 Lba3; - - Status = WaitForBSYClear (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - // - // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility) - // - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->Head, - (UINT8) ((IdeDev->Device << 4) | 0xe0) - ); - - // - // ATA commands for ATA device must be issued when DRDY is set - // - Status = DRDYReady (IdeDev, ATATIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - - Lba0 = (UINT8) LbaAddress; - Lba1 = (UINT8) RShiftU64 (LbaAddress, 8); - Lba2 = (UINT8) RShiftU64 (LbaAddress, 16); - Lba3 = (UINT8) RShiftU64 (LbaAddress, 24); - Device = (UINT8) (Device | Lba3); - - // - // Pass parameter into device register block - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); - - // - // Fill the feature register, which is a two-byte FIFO. Need write twice. - // - Feature8 = (UINT8) Feature; - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); - - // - // Fill the sector count register, which is a two-byte FIFO. Need write twice. - // - SectorCount8 = (UINT8) SectorCount; - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); - - // - // Fill the start LBA registers, which are also two-byte FIFO - // - - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1); - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2); - - // - // Send command via Command Register - // - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); - - // - // Stall at least 400ns - // - gBS->Stall (100); - - return EFI_SUCCESS; -} - -/** - This function is called by the AtaBlkIoReadBlocks() to perform - reading from media in block unit. The function has been enhanced to - support >120GB access and transfer at most 65536 blocks per command - - @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *DataBuffer A pointer to the destination buffer for the data. - - @param[in] StartLba The starting logical block address to read from - on the device media. - - @param[in] NumberOfBlocks The number of transfer data blocks. - - @return The device status of UDMA operation. If the operation is - successful, return EFI_SUCCESS. - - TODO: EFI_UNSUPPORTED - add return value to function comment - TODO: EFI_DEVICE_ERROR - add return value to function comment - TODO: EFI_DEVICE_ERROR - add return value to function comment - TODO: EFI_DEVICE_ERROR - add return value to function comment -**/ -EFI_STATUS -AtaUdmaReadExt ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *DataBuffer, - IN EFI_LBA StartLba, - IN UINTN NumberOfBlocks - ) -{ - return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadExtOp); -} - -/** - This function is called by the AtaBlkIoReadBlocks() to perform - reading from media in block unit. The function has been enhanced to - support >120GB access and transfer at most 65536 blocks per command - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *DataBuffer A pointer to the destination buffer for the data. - @param[in] StartLba The starting logical block address to read from - on the device media. - @param[in] NumberOfBlocks The number of transfer data blocks. - - @return The device status of UDMA operation. If the operation is - successful, return EFI_SUCCESS. - - TODO: EFI_UNSUPPORTED - add return value to function comment - TODO: EFI_DEVICE_ERROR - add return value to function comment - TODO: EFI_DEVICE_ERROR - add return value to function comment - TODO: EFI_DEVICE_ERROR - add return value to function comment -**/ -EFI_STATUS -AtaUdmaRead ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *DataBuffer, - IN EFI_LBA StartLba, - IN UINTN NumberOfBlocks - ) -{ - return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadOp); -} - -/** - This function is called by the AtaBlkIoWriteBlocks() to perform - writing to media in block unit. The function has been enhanced to - support >120GB access and transfer at most 65536 blocks per command - - @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *DataBuffer A pointer to the source buffer for the data. - - @param[in] StartLba The starting logical block address to write to - on the device media. - - @param[in] NumberOfBlocks The number of transfer data blocks. - - @return The device status of UDMA operation. If the operation is - successful, return EFI_SUCCESS. - - TODO: EFI_UNSUPPORTED - add return value to function comment - TODO: EFI_DEVICE_ERROR - add return value to function comment - TODO: EFI_DEVICE_ERROR - add return value to function comment -**/ -EFI_STATUS -AtaUdmaWriteExt ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *DataBuffer, - IN EFI_LBA StartLba, - IN UINTN NumberOfBlocks - ) -{ - return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp); -} - -/** - This function is called by the AtaBlkIoWriteBlocks() to perform - writing to media in block unit. The function has been enhanced to - support >120GB access and transfer at most 65536 blocks per command - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *DataBuffer - A pointer to the source buffer for the data. - - @param[in] StartLba - The starting logical block address to write to - on the device media. - - @param[in] NumberOfBlocks - The number of transfer data blocks. - - @return The device status of UDMA operation. If the operation is - successful, return EFI_SUCCESS. - - TODO: EFI_UNSUPPORTED - add return value to function comment - TODO: EFI_DEVICE_ERROR - add return value to function comment - TODO: EFI_DEVICE_ERROR - add return value to function comment -**/ -EFI_STATUS -AtaUdmaWrite ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *DataBuffer, - IN EFI_LBA StartLba, - IN UINTN NumberOfBlocks - ) -{ - return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp); -} - -/** - Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt). - - @param[in] *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - @param[in] *DataBuffer - A pointer to the source buffer for the data. - - @param[in] StartLba - The starting logical block address to write to - on the device media. - - @param[in] NumberOfBlocks - The number of transfer data blocks. - - @param[in] UdmaOp - The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp, - AtaUdmaWriteOp, AtaUdmaWriteExOp - - @return The device status of UDMA operation. If the operation is - successful, return EFI_SUCCESS. - -**/ -EFI_STATUS -DoAtaUdma ( - IN IDE_BLK_IO_DEV *IdeDev, - IN VOID *DataBuffer, - IN EFI_LBA StartLba, - IN UINTN NumberOfBlocks, - IN ATA_UDMA_OPERATION UdmaOp - ) -{ - IDE_DMA_PRD *PrdAddr; - IDE_DMA_PRD *UsedPrdAddr; - IDE_DMA_PRD *TempPrdAddr; - UINT8 RegisterValue; - UINT8 Device; - UINT64 IoPortForBmic; - UINT64 IoPortForBmis; - UINT64 IoPortForBmid; - EFI_STATUS Status; - UINTN PrdTableNum; - UINTN ByteCount; - UINTN ByteAvailable; - UINT8 *PrdBuffer; - UINTN RemainBlockNum; - UINT8 DeviceControl; - UINT32 Count; - UINTN PageCount; - VOID *Map; - VOID *MemPage; - EFI_PHYSICAL_ADDRESS DeviceAddress; - UINTN MaxDmaCommandSectors; - EFI_PCI_IO_PROTOCOL_OPERATION PciIoProtocolOp; - UINT8 AtaCommand; - - switch (UdmaOp) { - case AtaUdmaReadOp: - MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS; - PciIoProtocolOp = EfiPciIoOperationBusMasterWrite; - AtaCommand = ATA_CMD_READ_DMA; - break; - case AtaUdmaReadExtOp: - MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS; - PciIoProtocolOp = EfiPciIoOperationBusMasterWrite; - AtaCommand = ATA_CMD_READ_DMA_EXT; - break; - case AtaUdmaWriteOp: - MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS; - PciIoProtocolOp = EfiPciIoOperationBusMasterRead; - AtaCommand = ATA_CMD_WRITE_DMA; - break; - case AtaUdmaWriteExtOp: - MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS; - PciIoProtocolOp = EfiPciIoOperationBusMasterRead; - AtaCommand = ATA_CMD_WRITE_DMA_EXT; - break; - default: - return EFI_UNSUPPORTED; - break; - } - - // - // Channel and device differential - // - Device = (UINT8) ((IdeDev->Device << 4) | 0xe0); - - // - // Enable interrupt to support UDMA and Select device - // - DeviceControl = 0; - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); - - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); - - if (IdePrimary == IdeDev->Channel) { - IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET; - IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET; - IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET; - } else { - if (IdeSecondary == IdeDev->Channel) { - IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET; - IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET; - IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET; - } else { - return EFI_UNSUPPORTED; - } - } - - RemainBlockNum = NumberOfBlocks; - while (RemainBlockNum > 0) { - - if (RemainBlockNum >= MaxDmaCommandSectors) { - // - // SectorCount is used to record the number of sectors to be read - // Max 65536 sectors can be transfered at a time. - // - NumberOfBlocks = MaxDmaCommandSectors; - RemainBlockNum -= MaxDmaCommandSectors; - } else { - NumberOfBlocks = (UINT16) RemainBlockNum; - RemainBlockNum = 0; - } - - // - // Calculate the number of PRD table to make sure the memory region - // not cross 64K boundary - // - ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; - PrdTableNum = ((ByteCount >> 16) + 1) + 1; - - // - // Build PRD table - // - PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD)); - Status = IdeDev->PciIo->AllocateBuffer ( - IdeDev->PciIo, - AllocateAnyPages, - EfiBootServicesData, - PageCount, - &MemPage, - 0 - ); - if (EFI_ERROR (Status)) { - return EFI_OUT_OF_RESOURCES; - } - ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount)); - - PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage); - // - // To make sure PRD is allocated in one 64K page - // - if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) { - UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000); - } else { - if ((UINTN) PrdAddr & 0x03) { - UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC); - } else { - UsedPrdAddr = PrdAddr; - } - } - - // - // Build the PRD table - // - Status = IdeDev->PciIo->Map ( - IdeDev->PciIo, - PciIoProtocolOp, - DataBuffer, - &ByteCount, - &DeviceAddress, - &Map - ); - if (EFI_ERROR (Status)) { - IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage); - return EFI_OUT_OF_RESOURCES; - } - PrdBuffer = (VOID *) ((UINTN) DeviceAddress); - TempPrdAddr = UsedPrdAddr; - while (TRUE) { - - ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF); - - if (ByteCount <= ByteAvailable) { - TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); - TempPrdAddr->ByteCount = (UINT16) ByteCount; - TempPrdAddr->EndOfTable = 0x8000; - break; - } - - TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); - TempPrdAddr->ByteCount = (UINT16) ByteAvailable; - - ByteCount -= ByteAvailable; - PrdBuffer += ByteAvailable; - TempPrdAddr++; - } - - // - // Set the base address to BMID register - // - IdeDev->PciIo->Io.Write ( - IdeDev->PciIo, - EfiPciIoWidthUint32, - EFI_PCI_IO_PASS_THROUGH_BAR, - IoPortForBmid, - 1, - &UsedPrdAddr - ); - - // - // Set BMIC register to identify the operation direction - // - IdeDev->PciIo->Io.Read ( - IdeDev->PciIo, - EfiPciIoWidthUint8, - EFI_PCI_IO_PASS_THROUGH_BAR, - IoPortForBmic, - 1, - &RegisterValue - ); - - if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) { - RegisterValue |= BMIC_nREAD; - } else { - RegisterValue &= ~((UINT8) BMIC_nREAD); - } - - IdeDev->PciIo->Io.Write ( - IdeDev->PciIo, - EfiPciIoWidthUint8, - EFI_PCI_IO_PASS_THROUGH_BAR, - IoPortForBmic, - 1, - &RegisterValue - ); - - // - // Read BMIS register and clear ERROR and INTR bit - // - IdeDev->PciIo->Io.Read ( - IdeDev->PciIo, - EfiPciIoWidthUint8, - EFI_PCI_IO_PASS_THROUGH_BAR, - IoPortForBmis, - 1, - &RegisterValue - ); - - RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); - - IdeDev->PciIo->Io.Write ( - IdeDev->PciIo, - EfiPciIoWidthUint8, - EFI_PCI_IO_PASS_THROUGH_BAR, - IoPortForBmis, - 1, - &RegisterValue - ); - - if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) { - Status = AtaCommandIssueExt ( - IdeDev, - AtaCommand, - Device, - 0, - (UINT16) NumberOfBlocks, - StartLba - ); - } else { - Status = AtaCommandIssue ( - IdeDev, - AtaCommand, - Device, - 0, - (UINT16) NumberOfBlocks, - StartLba - ); - } - - if (EFI_ERROR (Status)) { - IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage); - IdeDev->PciIo->Unmap (IdeDev->PciIo, Map); - return EFI_DEVICE_ERROR; - } - - // - // Set START bit of BMIC register - // - IdeDev->PciIo->Io.Read ( - IdeDev->PciIo, - EfiPciIoWidthUint8, - EFI_PCI_IO_PASS_THROUGH_BAR, - IoPortForBmic, - 1, - &RegisterValue - ); - - RegisterValue |= BMIC_START; - - IdeDev->PciIo->Io.Write ( - IdeDev->PciIo, - EfiPciIoWidthUint8, - EFI_PCI_IO_PASS_THROUGH_BAR, - IoPortForBmic, - 1, - &RegisterValue - ); - - // - // Check the INTERRUPT and ERROR bit of BMIS - // Max transfer number of sectors for one command is 65536(32Mbyte), - // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps). - // So set the variable Count to 2000, for about 2 second timeout time. - // - Count = 2000; - while (TRUE) { - - IdeDev->PciIo->Io.Read ( - IdeDev->PciIo, - EfiPciIoWidthUint8, - EFI_PCI_IO_PASS_THROUGH_BAR, - IoPortForBmis, - 1, - &RegisterValue - ); - if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) { - if ((RegisterValue & BMIS_ERROR) || (Count == 0)) { - // - // Clear START bit of BMIC register before return EFI_DEVICE_ERROR - // - IdeDev->PciIo->Io.Read ( - IdeDev->PciIo, - EfiPciIoWidthUint8, - EFI_PCI_IO_PASS_THROUGH_BAR, - IoPortForBmic, - 1, - &RegisterValue - ); - - RegisterValue &= ~((UINT8)BMIC_START); - - IdeDev->PciIo->Io.Write ( - IdeDev->PciIo, - EfiPciIoWidthUint8, - EFI_PCI_IO_PASS_THROUGH_BAR, - IoPortForBmic, - 1, - &RegisterValue - ); - IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage); - IdeDev->PciIo->Unmap (IdeDev->PciIo, Map); - return EFI_DEVICE_ERROR; - } - break; - } - - gBS->Stall (1000); - Count --; - } - - IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage); - IdeDev->PciIo->Unmap (IdeDev->PciIo, Map); - // - // Read Status Register of IDE device to clear interrupt - // - RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status); - // - // Clear START bit of BMIC register - // - IdeDev->PciIo->Io.Read ( - IdeDev->PciIo, - EfiPciIoWidthUint8, - EFI_PCI_IO_PASS_THROUGH_BAR, - IoPortForBmic, - 1, - &RegisterValue - ); - - RegisterValue &= ~((UINT8) BMIC_START); - - IdeDev->PciIo->Io.Write ( - IdeDev->PciIo, - EfiPciIoWidthUint8, - EFI_PCI_IO_PASS_THROUGH_BAR, - IoPortForBmic, - 1, - &RegisterValue - ); - - if (RegisterValue & BMIS_ERROR) { - return EFI_DEVICE_ERROR; - } - - DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; - StartLba += NumberOfBlocks; - } - - // - // Disable interrupt of Select device - // - IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl); - DeviceControl |= ATA_CTLREG_IEN_L; - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); - - return EFI_SUCCESS; -}