//********************************************************************** //********************************************************************** //** ** //** (C)Copyright 1985-2011, American Megatrends, Inc. ** //** ** //** All Rights Reserved. ** //** ** //** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** //** ** //** Phone: (770)-246-8600 ** //** ** //********************************************************************** //********************************************************************** //********************************************************************** // $Header: /Alaska/SOURCE/Core/Modules/Recovery/IdeRecovery.c 15 4/02/12 12:54a Srilathasc $ // // $Revision: 15 $ // // $Date: 4/02/12 12:54a $ //********************************************************************** // Revision History // ---------------- // $Log: /Alaska/SOURCE/Core/Modules/Recovery/IdeRecovery.c $ // // 15 4/02/12 12:54a Srilathasc // [TAG] EIP81405 // [Category] Bug Fix // [Symptom] Recovery mode did not work in hard disk // [RootCause] Sufficient timeout to wait for DRQ was not given after // command was written in AtaPioDataIn() // [Solution] Increase the TIMEOUT to 10 seconds after the command is // complete // // [Files] IdeRecovery.c // // 14 2/21/12 5:04a Rameshr // [TAG] EIP75596 // [Category] Bug Fix // [Severity] Minor // [Symptom] Boot to recovery mode without media in the CD drive.First // time it will fail and next time while inserting Media , still recovery // not success from CD. // [RootCause] Atapi_DetectMedia will get called and irrespective of // device status LookedForMedia flag getting updated // [Solution] LookedForMedia flag updated only when the success // detection of Media in the ODD // [Files] IdeRecovery.c // // 13 7/07/11 3:20a Lavanyap // [TAG] EIP59029 // [Category] Bug Fix // [Symptom] Recovery failed in IDE mode in VIA platform. // [RootCause] BSY/DRQ status checking was not done on the right port. // [Solution] Select the proper device before checking the device // status. // [Files] IdeRecovery.c // // 12 5/04/11 12:20p Artems // Bug fix: rollback previous check-in changes // // 11 2/14/11 4:06p Yul // [TAG] EIP38288 // [Category] Enhanced // [Description] Klocwork Issues II - Recovery // // 10 1/07/10 12:01p Robert // In Ata_ReadSectors() Change the SectorCount variable to UINT16, // removed the typecasting when setting this variable and added a // typecasting to UINT8 when call the AtaPioDataIn() // Removed previous changes for clearer functionality // // 9 1/05/10 12:13p Robert // in Ata_ReadSectors() if the need arises to call AtaPioDataIn with // SectorCount == MaxBlock, no data was ever read. A special case had to // be created to handle the case when SectorCount == MaxBlock. // Refer to EIP #33174 for more details // // 8 7/01/09 4:19p Rameshr // Coding Standard and File header updated. // // 7 3/04/09 1:32p Felixp // Address in the file header is updated. // // 6 2/26/09 5:38p Felixp // File header is updated (no code changes). // //********************************************************************** // // // Name: IdeRecovery.c // // Description: IDE Recovery Implementation // // //********************************************************************** // //---------------------------------------------------------------------- // // Name: IdeRecovery.c - PEI driver // // Description: Implements EFI_PEI_RECOVERY_BLOCK_IO_PPI for ATA and ATAPI devices. // //---------------------------------------------------------------------- // #include #include #include #include #include #include #include EFI_GUID gPeiStallPpiGuid = EFI_PEI_STALL_PPI_GUID; EFI_GUID gPeiAtaControllerPpiGuid = PEI_ATA_CONTROLLER_PPI_GUID; EFI_GUID gPeiBlockIoPpiGuid = EFI_PEI_VIRTUAL_BLOCK_IO_PPI; EFI_GUID gIdeRecoveryNativeModePpiGuid = PEI_IDE_RECOVERY_NATIVE_MODE_PPI_GUID; //---------------------------------------------------------------------- //Atapi command definitions #define EFI_MIN( a, b ) (((a) < (b)) ? (a) : (b)) #define ATAPI_SIGNATURE 0xEB14 #define CD_ROM_DEVICE 0x5 #define SK_NO_SENSE 0 #define SK_NOT_READY 2 #define SK_UNIT_ATTENTION 6 #define MAX_SENSE_KEY_COUNT 6 #pragma pack(1) typedef struct { UINT16 GeneralConfiguration_0; UINT16 Data_1_58[58]; UINT32 TotalUserAddressableSectors_60; UINT16 Data_61_255[195]; } ATA_IDENTIFY_DATA; typedef struct { UINT8 PeripheralDeviceType_0 : 5; UINT8 Reserved_0 : 3; UINT8 Data_1_95[95]; } INQUIRY_DATA; typedef struct { UINT8 Data_0_1[2]; UINT8 SenseKey_2 : 4; UINT8 Data_2 : 4; UINT8 Data_3_6[4]; UINT8 AdditionalSenseLength_7; UINT8 Data_8_11[4]; UINT8 AdditionalSenseCode_12; UINT8 AdditionalSenseCodeQualifier_13; UINT8 Data_14_17[4]; } REQUEST_SENSE_DATA; typedef struct { UINT8 LastLba0; UINT8 LastLba1; UINT8 LastLba2; UINT8 LastLba3; UINT8 BlockSize3; UINT8 BlockSize2; UINT8 BlockSize1; UINT8 BlockSize0; } READ_CAPACITY_DATA; #pragma pack() #define PACKET_CMD 0xA0 #define ATA_IDENTIFY_DEVICE_CMD 0xEC #define ATA_READ_SECTOR_CMD 0x20 #pragma pack(1) typedef struct { UINT8 OperationCode_0; UINT8 Data_1_3[3]; UINT8 AllocationLength_4; UINT8 Data_5_11[7]; } GENERIC_CMD; typedef struct { UINT8 OperationCode_0; UINT8 Data_1; UINT8 Lba0; UINT8 Lba1; UINT8 Lba2; UINT8 Lba3; UINT8 Data_6; UINT8 TransferLengthMSB; UINT8 TransferLengthLSB; UINT8 Data_9_11[3]; } READ10_CMD; typedef union { UINT16 Data16[6]; GENERIC_CMD Cmd; READ10_CMD Read10; } ATAPI_PACKET_COMMAND; #pragma pack() #define TEST_UNIT_READY 0x00 #define REQUEST_SENSE 0x03 #define INQUIRY 0x12 #define READ_CAPACITY 0x25 #define READ_10 0x28 #define DEFAULT_CTL (0x0a) // default content of device control register, disable INT #define DEFAULT_CMD (0xa0) #define MAX_ATAPI_BYTE_COUNT (0xfffe) #pragma pack(1) // IDE registers bit definitions // Err Reg #define ABRT_ERR BIT02 // Aborted Command // Device/Head Reg #define LBA_MODE BIT06 // Status Reg #define BSY BIT07 // Controller Busy #define DRDY BIT06 // Drive Ready #define DWF BIT05 // Drive Write Fault #define DRQ BIT03 // Data Request #define CORR BIT02 // Corrected Data #define ERR BIT00 // Error #pragma pack() #define STALL_1_MILLI_SECOND 1000 // stall 1 ms #define TIMEOUT 1000 // 1 second #define COMMAND_COMPLETE_TIMEOUT 10000 // 10 seconds #define LONGTIMEOUT 5000 // 5 seconds //---------------------------------------------------------------------- typedef enum { EnumerateAtapi, EnumerateAta } ENUMERATE_TYPE; typedef enum { IdeLegacy, IdeNative, IdeMaxMode } EFI_IDE_MODE; typedef enum { IdePrimary, IdeSecondary, IdeMaxChannel } EFI_IDE_CHANNEL; typedef enum { IdeMaster, IdeSlave, IdeMaxDevice } EFI_IDE_DEVICE; // IDE Registers typedef union { UINT16 Command; // when write UINT16 Status; // when read } IDE_CMD_OR_STATUS; typedef union { UINT16 Error; // when read UINT16 Feature; // when write } IDE_ERROR_OR_FEATURE; typedef union { UINT16 AltStatus; // when read UINT16 DeviceControl; // when write } IDE_AltStatus_OR_DeviceControl; // IDE registers set typedef struct { UINT16 Data; IDE_ERROR_OR_FEATURE Reg1; UINT16 SectorCount; UINT16 SectorNumber; UINT16 CylinderLsb; UINT16 CylinderMsb; UINT16 Head; IDE_CMD_OR_STATUS Reg; IDE_AltStatus_OR_DeviceControl Alt; UINT16 DriveAddress; } IDE_BASE_REGISTERS; typedef struct { UINT8 Device; BOOLEAN LookedForMedia; IDE_BASE_REGISTERS *IdeIoPortRegisters; EFI_PEI_BLOCK_IO_MEDIA MediaInfo; } IDE_RECOVERY_DEVICE_INFO; #define MAX_DEVICE_COUNT 8 typedef struct { EFI_PEI_RECOVERY_BLOCK_IO_PPI RecoveryBlkIo; BOOLEAN HaveEnumeratedDevices; UINTN DeviceCount; IDE_RECOVERY_DEVICE_INFO *DeviceInfo[MAX_DEVICE_COUNT]; } IDE_RECOVERY_BLK_IO_DEV; // IDE registers' fixed address IDE_BASE_REGISTERS PrimaryChannelLegacyIdeIoPortRegisters = { 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, 0x1f7, 0x3f6, 0x3f7 }; IDE_BASE_REGISTERS SecondaryChannelLegacyIdeIoPortRegisters = { 0x170, 0x171, 0x172, 0x173, 0x174, 0x175, 0x176, 0x177, 0x376, 0x377 }; //AtaAtapiCommonInit should only be called once BOOLEAN gHaveCalledAtaAtapiCommonInit = FALSE; BOOLEAN gIdeRecoveryNativeModeSupport = FALSE; IDE_BASE_REGISTERS PrimaryChannelNativeIdeIoPortRegisters = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 1 }; IDE_BASE_REGISTERS SecondaryChannelNativeIdeIoPortRegisters = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 1 }; IDE_BASE_REGISTERS *gNativeModePortRegsiters; UINT8 gNativeIdeCount = 0; //---------------------------------------------------------------------- // PEI Recovery Block I/O PPI EFI_STATUS AtaAtapiCommonInit ( IN EFI_PEI_SERVICES **PeiServices ); EFI_STATUS Atapi_GetNumberOfBlockDevices ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, OUT UINTN *NumberBlockDevices ); EFI_STATUS Atapi_GetBlockDeviceMediaInfo ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, IN UINTN DeviceIndex, OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo ); EFI_STATUS Atapi_ReadBlocks ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, IN UINTN DeviceIndex, IN EFI_PEI_LBA StartLba, IN UINTN BufferSize, OUT VOID *Buffer ); EFI_STATUS Ata_GetNumberOfBlockDevices ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, OUT UINTN *NumberBlockDevices ); EFI_STATUS Ata_GetBlockDeviceMediaInfo ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, IN UINTN DeviceIndex, OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo ); EFI_STATUS Ata_ReadBlocks ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, IN UINTN DeviceIndex, IN EFI_PEI_LBA StartLba, IN UINTN BufferSize, OUT VOID *Buffer ); // Private functions VOID EnumerateDevices ( IN OUT IDE_RECOVERY_BLK_IO_DEV *IdeRecoveryBlkIoDev, IN ENUMERATE_TYPE EnumerateType ); BOOLEAN Atapi_DiscoverDevice ( IN OUT IDE_RECOVERY_DEVICE_INFO *DeviceInfo ); BOOLEAN Ata_DiscoverDevice ( IN OUT IDE_RECOVERY_DEVICE_INFO *DeviceInfo ); EFI_STATUS AtapiPacketCommandIn ( IN IDE_RECOVERY_DEVICE_INFO *DeviceInfo, IN ATAPI_PACKET_COMMAND *Packet, IN UINT16 *Buffer, IN UINT32 ByteCount, IN UINTN TimeoutInMilliSeconds ); EFI_STATUS Inquiry ( IN OUT IDE_RECOVERY_DEVICE_INFO *DeviceInfo ); EFI_STATUS Atapi_DetectMedia ( IN OUT IDE_RECOVERY_DEVICE_INFO *DeviceInfo ); EFI_STATUS TestUnitReady ( IN IDE_RECOVERY_DEVICE_INFO *DeviceInfo ); EFI_STATUS RequestSense ( IN IDE_RECOVERY_DEVICE_INFO *DeviceInfo, OUT REQUEST_SENSE_DATA *SenseBuffers, OUT UINT8 *SenseCounts ); EFI_STATUS ReadCapacity ( IN OUT IDE_RECOVERY_DEVICE_INFO *DeviceInfo ); EFI_STATUS Atapi_ReadSectors ( IN IDE_RECOVERY_DEVICE_INFO *DeviceInfo, OUT VOID *Buffer, IN EFI_PEI_LBA StartLba, IN UINTN NumberOfBlocks, IN UINTN BlockSize ); EFI_STATUS AtaPioDataIn ( IN IDE_BASE_REGISTERS *IdeIoPortRegisters, OUT VOID *Buffer, IN UINT32 ByteCount, IN UINT8 SectorCount, IN UINT8 SectorNumber, IN UINT8 CylinderLsb, IN UINT8 CylinderMsb, IN UINT8 Device, IN UINT8 Command ); EFI_STATUS AtaIdentify ( IN IDE_RECOVERY_DEVICE_INFO *DeviceInfo, OUT ATA_IDENTIFY_DATA *AtaIdentifyData ); EFI_STATUS Ata_ReadSectors ( IN IDE_RECOVERY_DEVICE_INFO *DeviceInfo, OUT VOID *Buffer, IN EFI_PEI_LBA StartLba, IN UINTN NumberOfBlocks, IN UINTN BlockSize ); EFI_STATUS WaitForBitsToClear ( IN UINT16 Register, IN UINT8 Bits, IN UINTN TimeoutInMilliSeconds ); EFI_STATUS WaitForBSYClear ( IN IDE_BASE_REGISTERS *IdeIoRegisters, IN UINTN TimeoutInMilliSeconds ); EFI_STATUS DRQClear ( IN IDE_BASE_REGISTERS *IdeIoRegisters, IN UINTN TimeoutInMilliSeconds ); EFI_STATUS DRQClear2 ( IN IDE_BASE_REGISTERS *IdeIoRegisters, IN UINTN TimeoutInMilliSeconds ); EFI_STATUS DRQReadyHelper ( IN UINT16 StatusRegister, IN UINT16 ErrorRegister, IN UINTN TimeoutInMilliSeconds ); EFI_STATUS DRQReady ( IN IDE_BASE_REGISTERS *IdeIoRegisters, IN UINTN TimeoutInMilliSeconds ); EFI_STATUS DRQReady2 ( IN IDE_BASE_REGISTERS *IdeIoRegisters, IN UINTN TimeoutInMilliSeconds ); EFI_STATUS CheckErrorStatus ( IN UINT16 StatusReg ); VOID ZeroMem ( OUT VOID *Buffer, IN UINTN Size ); //---------------------------------------------------------------------- EFI_PEI_PPI_DESCRIPTOR Atapi_PpiDescriptor = { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gPeiBlockIoPpiGuid, NULL }; EFI_PEI_PPI_DESCRIPTOR Ata_PpiDescriptor = { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gPeiBlockIoPpiGuid, NULL }; static EFI_PEI_SERVICES **gPeiServices = NULL; static EFI_PEI_STALL_PPI *gStallPpi = NULL; // //---------------------------------------------------------------------- // // Procedure: Atapi_RecoveryPeimEntry // // Description: Installs EFI_PEI_RECOVERY_BLOCK_IO_PPI for ATAPI devices. // //---------------------------------------------------------------------- // EFI_STATUS Atapi_RecoveryPeimEntry( IN EFI_FFS_FILE_HEADER *FfsHeader, IN EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status = EFI_SUCCESS; IDE_RECOVERY_BLK_IO_DEV *Atapi_BlkIoDev = NULL; if ( !gPeiServices ) { gPeiServices = PeiServices; } Status = (**PeiServices).AllocatePool( PeiServices, sizeof(IDE_RECOVERY_BLK_IO_DEV), &Atapi_BlkIoDev ); if ( EFI_ERROR( Status )) { return EFI_OUT_OF_RESOURCES; } Atapi_BlkIoDev->HaveEnumeratedDevices = FALSE; Atapi_BlkIoDev->DeviceCount = 0; Atapi_BlkIoDev->RecoveryBlkIo.GetNumberOfBlockDevices = Atapi_GetNumberOfBlockDevices; Atapi_BlkIoDev->RecoveryBlkIo.GetBlockDeviceMediaInfo = Atapi_GetBlockDeviceMediaInfo; Atapi_BlkIoDev->RecoveryBlkIo.ReadBlocks = Atapi_ReadBlocks; Atapi_PpiDescriptor.Ppi = &Atapi_BlkIoDev->RecoveryBlkIo; Status = (**PeiServices).InstallPpi( PeiServices, &Atapi_PpiDescriptor ); if ( EFI_ERROR( Status )) { return EFI_OUT_OF_RESOURCES; } return EFI_SUCCESS; } // //---------------------------------------------------------------------- // // Procedure: Ata_RecoveryPeimEntry // // Description: Installs EFI_PEI_RECOVERY_BLOCK_IO_PPI for ATA devices. // //---------------------------------------------------------------------- // EFI_STATUS Ata_RecoveryPeimEntry( IN EFI_FFS_FILE_HEADER *FfsHeader, IN EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status = EFI_SUCCESS; IDE_RECOVERY_BLK_IO_DEV *Ata_BlkIoDev = NULL; if ( !gPeiServices ) { gPeiServices = PeiServices; } Status = (**PeiServices).AllocatePool( PeiServices, sizeof(IDE_RECOVERY_BLK_IO_DEV), &Ata_BlkIoDev ); if ( EFI_ERROR( Status )) { return EFI_OUT_OF_RESOURCES; } Ata_BlkIoDev->HaveEnumeratedDevices = FALSE; Ata_BlkIoDev->DeviceCount = 0; Ata_BlkIoDev->RecoveryBlkIo.GetNumberOfBlockDevices = Ata_GetNumberOfBlockDevices; Ata_BlkIoDev->RecoveryBlkIo.GetBlockDeviceMediaInfo = Ata_GetBlockDeviceMediaInfo; Ata_BlkIoDev->RecoveryBlkIo.ReadBlocks = Ata_ReadBlocks; Ata_PpiDescriptor.Ppi = &Ata_BlkIoDev->RecoveryBlkIo; Status = (**PeiServices).InstallPpi( PeiServices, &Ata_PpiDescriptor ); if ( EFI_ERROR( Status )) { return EFI_OUT_OF_RESOURCES; } return EFI_SUCCESS; } // //---------------------------------------------------------------------- // // Procedure: AtaAtapiCommonInit // // Description: Called by Atapi_RecoveryPeimEntry and Ata_RecoveryPeimEntry // functions. Initializes stuff, including // gIdeRecoveryNativeModeSupport, // PrimaryChannelNativeIdeIoPortRegisters, // SecondaryChannelNativeIdeIoPortRegisters. // //---------------------------------------------------------------------- // EFI_STATUS AtaAtapiCommonInit( IN EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status = EFI_SUCCESS; EFI_STATUS LegacyStatus = EFI_NOT_FOUND; PEI_ATA_CONTROLLER_PPI *AtaControllerPpi = NULL; PEI_IDE_RECOVERY_NATIVE_MODE_PPI *IdeRecoveryNativeModePpi = NULL; UINT8 i = 0; UINT8 Index = 0; Status = (**PeiServices).LocatePpi( PeiServices, &gPeiStallPpiGuid, 0, NULL, &gStallPpi ); if ( EFI_ERROR( Status )) { return EFI_UNSUPPORTED; } Status = (**PeiServices).LocatePpi( PeiServices, &gPeiAtaControllerPpiGuid, 0, NULL, &AtaControllerPpi ); if ( !(EFI_ERROR( Status ))) { LegacyStatus = AtaControllerPpi->EnableAtaChannel( PeiServices, AtaControllerPpi, PEI_ICH_IDE_PRIMARY | PEI_ICH_IDE_SECONDARY ); } // //Find Number of Native mode IDE ppi installed // Index = 0; do { Status = (**PeiServices).LocatePpi( PeiServices, &gIdeRecoveryNativeModePpiGuid, Index, NULL, &IdeRecoveryNativeModePpi ); if ( !(EFI_ERROR( Status ))) { Index++; gNativeIdeCount++; } } while ( Status == EFI_SUCCESS ); // //if Legacy mode init fails and if there is no native PPI return with error. // if ((gNativeIdeCount == 00) && (LegacyStatus != EFI_SUCCESS)) { return EFI_UNSUPPORTED; } Status = (**PeiServices).AllocatePool( PeiServices, sizeof(IDE_BASE_REGISTERS) * 2 * gNativeIdeCount, &gNativeModePortRegsiters ); // //Fill the base address values in gNativeModePortRegsiters // Index = 0; do { Status = (**PeiServices).LocatePpi( PeiServices, &gIdeRecoveryNativeModePpiGuid, Index, NULL, &IdeRecoveryNativeModePpi ); if ( !(EFI_ERROR( Status ))) { gIdeRecoveryNativeModeSupport = TRUE; gNativeModePortRegsiters[i].Data = PrimaryChannelNativeIdeIoPortRegisters.Data + IdeRecoveryNativeModePpi->PCMDBarAddress; gNativeModePortRegsiters[i].Reg1.Error = PrimaryChannelNativeIdeIoPortRegisters.Reg1.Error + IdeRecoveryNativeModePpi->PCMDBarAddress; gNativeModePortRegsiters[i].SectorCount = PrimaryChannelNativeIdeIoPortRegisters.SectorCount + IdeRecoveryNativeModePpi->PCMDBarAddress; gNativeModePortRegsiters[i].SectorNumber = PrimaryChannelNativeIdeIoPortRegisters.SectorNumber + IdeRecoveryNativeModePpi->PCMDBarAddress; gNativeModePortRegsiters[i].CylinderLsb = PrimaryChannelNativeIdeIoPortRegisters.CylinderLsb + IdeRecoveryNativeModePpi->PCMDBarAddress; gNativeModePortRegsiters[i].CylinderMsb = PrimaryChannelNativeIdeIoPortRegisters.CylinderMsb + IdeRecoveryNativeModePpi->PCMDBarAddress; gNativeModePortRegsiters[i].Head = PrimaryChannelNativeIdeIoPortRegisters.Head + IdeRecoveryNativeModePpi->PCMDBarAddress; gNativeModePortRegsiters[i].Reg.Command = PrimaryChannelNativeIdeIoPortRegisters.Reg.Command + IdeRecoveryNativeModePpi->PCMDBarAddress; gNativeModePortRegsiters[i].Alt.AltStatus = PrimaryChannelNativeIdeIoPortRegisters.Alt.AltStatus + IdeRecoveryNativeModePpi->PCNLBarAddress; gNativeModePortRegsiters[i].DriveAddress = PrimaryChannelNativeIdeIoPortRegisters.DriveAddress + IdeRecoveryNativeModePpi->PCNLBarAddress; gNativeModePortRegsiters[i + 1].Data = SecondaryChannelNativeIdeIoPortRegisters.Data + IdeRecoveryNativeModePpi->SCMDBarAddress; gNativeModePortRegsiters[i + 1].Reg1.Error = SecondaryChannelNativeIdeIoPortRegisters.Reg1.Error + IdeRecoveryNativeModePpi->SCMDBarAddress; gNativeModePortRegsiters[i + 1].SectorCount = SecondaryChannelNativeIdeIoPortRegisters.SectorCount + IdeRecoveryNativeModePpi->SCMDBarAddress; gNativeModePortRegsiters[i + 1].SectorNumber = SecondaryChannelNativeIdeIoPortRegisters.SectorNumber += IdeRecoveryNativeModePpi->SCMDBarAddress; gNativeModePortRegsiters[i + 1].CylinderLsb = SecondaryChannelNativeIdeIoPortRegisters.CylinderLsb + IdeRecoveryNativeModePpi->SCMDBarAddress; gNativeModePortRegsiters[i + 1].CylinderMsb = SecondaryChannelNativeIdeIoPortRegisters.CylinderMsb + IdeRecoveryNativeModePpi->SCMDBarAddress; gNativeModePortRegsiters[i + 1].Head = SecondaryChannelNativeIdeIoPortRegisters.Head + IdeRecoveryNativeModePpi->SCMDBarAddress; gNativeModePortRegsiters[i + 1].Reg.Command = SecondaryChannelNativeIdeIoPortRegisters.Reg.Command + IdeRecoveryNativeModePpi->SCMDBarAddress; gNativeModePortRegsiters[i + 1].Alt.AltStatus = SecondaryChannelNativeIdeIoPortRegisters.Alt.AltStatus + IdeRecoveryNativeModePpi->SCNLBarAddress; gNativeModePortRegsiters[i + 1].DriveAddress = SecondaryChannelNativeIdeIoPortRegisters.DriveAddress + IdeRecoveryNativeModePpi->SCNLBarAddress; i = i + 2; Index++; } } while ( Status == EFI_SUCCESS ); return EFI_SUCCESS; } // //---------------------------------------------------------------------- // // Procedure: Atapi_GetNumberOfBlockDevices // // Description: GetNumberOfBlockDevices function of // EFI_PEI_RECOVERY_BLOCK_IO_PPI. // //---------------------------------------------------------------------- // EFI_STATUS Atapi_GetNumberOfBlockDevices( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, OUT UINTN *NumberBlockDevices ) { IDE_RECOVERY_BLK_IO_DEV *Atapi_BlkIoDev = NULL; if ( This == NULL ) { return EFI_INVALID_PARAMETER; } Atapi_BlkIoDev = (IDE_RECOVERY_BLK_IO_DEV*)This; if ( !Atapi_BlkIoDev->HaveEnumeratedDevices ) { EnumerateDevices( Atapi_BlkIoDev, EnumerateAtapi ); Atapi_BlkIoDev->HaveEnumeratedDevices = TRUE; } *NumberBlockDevices = Atapi_BlkIoDev->DeviceCount; return EFI_SUCCESS; } // //---------------------------------------------------------------------- // // Procedure: Atapi_GetBlockDeviceMediaInfo // // Description: GetBlockDeviceMediaInfo function of // EFI_PEI_RECOVERY_BLOCK_IO_PPI. // //---------------------------------------------------------------------- // EFI_STATUS Atapi_GetBlockDeviceMediaInfo( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, IN UINTN DeviceIndex, OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo ) { IDE_RECOVERY_BLK_IO_DEV *Atapi_BlkIoDev = NULL; EFI_STATUS Status = EFI_SUCCESS; if ((This == NULL) || (MediaInfo == NULL)) { return EFI_INVALID_PARAMETER; } Atapi_BlkIoDev = (IDE_RECOVERY_BLK_IO_DEV*)This; if ( !Atapi_BlkIoDev->HaveEnumeratedDevices ) { EnumerateDevices( Atapi_BlkIoDev, EnumerateAtapi ); Atapi_BlkIoDev->HaveEnumeratedDevices = TRUE; } if ( DeviceIndex > (Atapi_BlkIoDev->DeviceCount - 1)) { return EFI_INVALID_PARAMETER; } if ( !Atapi_BlkIoDev->DeviceInfo[DeviceIndex]->LookedForMedia ) { Status = Atapi_DetectMedia( Atapi_BlkIoDev->DeviceInfo[DeviceIndex] ); if ( Status != EFI_SUCCESS ) { return EFI_DEVICE_ERROR; } Atapi_BlkIoDev->DeviceInfo[DeviceIndex]->LookedForMedia = TRUE; } *MediaInfo = Atapi_BlkIoDev->DeviceInfo[DeviceIndex]->MediaInfo; return EFI_SUCCESS; } // //---------------------------------------------------------------------- // // Procedure: Atapi_ReadBlocks // // Description: ReadBlocks function of EFI_PEI_RECOVERY_BLOCK_IO_PPI. // //---------------------------------------------------------------------- // EFI_STATUS Atapi_ReadBlocks( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, IN UINTN DeviceIndex, IN EFI_PEI_LBA StartLba, IN UINTN BufferSize, OUT VOID *Buffer ) { EFI_PEI_BLOCK_IO_MEDIA MediaInfo; EFI_STATUS Status = EFI_SUCCESS; UINTN NumberOfBlocks = 0; UINTN BlockSize = 0; IDE_RECOVERY_BLK_IO_DEV *Atapi_BlkIoDev = NULL; if ( This == NULL ) { return EFI_INVALID_PARAMETER; } Atapi_BlkIoDev = (IDE_RECOVERY_BLK_IO_DEV*)This; if ( Buffer == NULL ) { return EFI_INVALID_PARAMETER; } if ( BufferSize == 0 ) { return EFI_SUCCESS; } if ( !Atapi_BlkIoDev->HaveEnumeratedDevices ) { EnumerateDevices( Atapi_BlkIoDev, EnumerateAtapi ); Atapi_BlkIoDev->HaveEnumeratedDevices = TRUE; } if ( !Atapi_BlkIoDev->DeviceInfo[DeviceIndex]->LookedForMedia ) { Status = Atapi_GetBlockDeviceMediaInfo( PeiServices, This, DeviceIndex, &MediaInfo ); if ( Status != EFI_SUCCESS ) { return Status; } } else { MediaInfo = Atapi_BlkIoDev->DeviceInfo[DeviceIndex]->MediaInfo; } BlockSize = MediaInfo.BlockSize; if ((BufferSize % BlockSize) != 0 ) { return EFI_INVALID_PARAMETER; } if ( !MediaInfo.MediaPresent ) { return EFI_NO_MEDIA; } NumberOfBlocks = BufferSize / BlockSize; Status = Atapi_ReadSectors( Atapi_BlkIoDev->DeviceInfo[DeviceIndex], Buffer, StartLba, NumberOfBlocks, BlockSize ); return Status; } // //---------------------------------------------------------------------- // // Procedure: Ata_GetNumberOfBlockDevices // // Description: GetNumberOfBlockDevices function of // EFI_PEI_RECOVERY_BLOCK_IO_PPI. // //---------------------------------------------------------------------- // EFI_STATUS Ata_GetNumberOfBlockDevices( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, OUT UINTN *NumberBlockDevices ) { IDE_RECOVERY_BLK_IO_DEV *Ata_BlkIoDev = NULL; if ( This == NULL ) { return EFI_INVALID_PARAMETER; } Ata_BlkIoDev = (IDE_RECOVERY_BLK_IO_DEV*)This; if ( !Ata_BlkIoDev->HaveEnumeratedDevices ) { EnumerateDevices( Ata_BlkIoDev, EnumerateAta ); Ata_BlkIoDev->HaveEnumeratedDevices = TRUE; } *NumberBlockDevices = Ata_BlkIoDev->DeviceCount; return EFI_SUCCESS; } // //---------------------------------------------------------------------- // // Procedure: Ata_GetBlockDeviceMediaInfo // // Description: GetBlockDeviceMediaInfo function of // EFI_PEI_RECOVERY_BLOCK_IO_PPI. // //---------------------------------------------------------------------- // EFI_STATUS Ata_GetBlockDeviceMediaInfo( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, IN UINTN DeviceIndex, OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo ) { IDE_RECOVERY_BLK_IO_DEV *Ata_BlkIoDev = NULL; EFI_STATUS Status = EFI_SUCCESS; UINT8 *Buffer = NULL; UINT32 SectorOfFirstPartition = 0; UINT16 LowByte = 0, HighByte = 0, BlockSize = 0; if ((This == NULL) || (MediaInfo == NULL)) { return EFI_INVALID_PARAMETER; } Ata_BlkIoDev = (IDE_RECOVERY_BLK_IO_DEV*)This; if ( !Ata_BlkIoDev->HaveEnumeratedDevices ) { EnumerateDevices( Ata_BlkIoDev, EnumerateAta ); Ata_BlkIoDev->HaveEnumeratedDevices = TRUE; } if ( DeviceIndex > (Ata_BlkIoDev->DeviceCount - 1)) { return EFI_INVALID_PARAMETER; } if ( !Ata_BlkIoDev->DeviceInfo[DeviceIndex]->LookedForMedia ) { Ata_BlkIoDev->DeviceInfo[DeviceIndex]->LookedForMedia = TRUE; } *MediaInfo = Ata_BlkIoDev->DeviceInfo[DeviceIndex]->MediaInfo; return EFI_SUCCESS; } // //---------------------------------------------------------------------- // // Procedure: Ata_ReadBlocks // // Description: ReadBlocks function of EFI_PEI_RECOVERY_BLOCK_IO_PPI. // //---------------------------------------------------------------------- // EFI_STATUS Ata_ReadBlocks( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, IN UINTN DeviceIndex, IN EFI_PEI_LBA StartLba, IN UINTN BufferSize, OUT VOID *Buffer ) { EFI_PEI_BLOCK_IO_MEDIA MediaInfo; EFI_STATUS Status = EFI_SUCCESS; UINTN NumberOfBlocks = 0; UINTN BlockSize = 0; IDE_RECOVERY_BLK_IO_DEV *Ata_BlkIoDev = NULL; if ( This == NULL ) { return EFI_INVALID_PARAMETER; } Ata_BlkIoDev = (IDE_RECOVERY_BLK_IO_DEV*)This; if ( Buffer == NULL ) { return EFI_INVALID_PARAMETER; } if ( BufferSize == 0 ) { return EFI_SUCCESS; } if ( !Ata_BlkIoDev->HaveEnumeratedDevices ) { EnumerateDevices( Ata_BlkIoDev, EnumerateAta ); Ata_BlkIoDev->HaveEnumeratedDevices = TRUE; } if ( !Ata_BlkIoDev->DeviceInfo[DeviceIndex]->LookedForMedia ) { Status = Ata_GetBlockDeviceMediaInfo( PeiServices, This, DeviceIndex, &MediaInfo ); if ( Status != EFI_SUCCESS ) { return Status; } } else { MediaInfo = Ata_BlkIoDev->DeviceInfo[DeviceIndex]->MediaInfo; } BlockSize = MediaInfo.BlockSize; if ( BufferSize % BlockSize != 0 ) { return EFI_INVALID_PARAMETER; } if ( !MediaInfo.MediaPresent ) { return EFI_NO_MEDIA; } NumberOfBlocks = BufferSize / BlockSize; if ( StartLba > MediaInfo.LastBlock ) { return EFI_INVALID_PARAMETER; } if ((StartLba + NumberOfBlocks) > (MediaInfo.LastBlock + 1)) { return EFI_INVALID_PARAMETER; } Status = Ata_ReadSectors( Ata_BlkIoDev->DeviceInfo[DeviceIndex], Buffer, StartLba, NumberOfBlocks, BlockSize ); return Status; } // //---------------------------------------------------------------------- // // Procedure: EnumerateDevices // // Description: Enumerates Ata or Atapi devices. Called by // Ata_GetNumberOfBlockDevices or // Atapi_GetNumberOfBlockDevices. // //---------------------------------------------------------------------- // VOID EnumerateDevices( IN IDE_RECOVERY_BLK_IO_DEV *IdeRecoveryBlkIoDev, ENUMERATE_TYPE EnumerateType ) { EFI_STATUS Status = EFI_SUCCESS; UINT8 MaxModes = IdeMaxMode; EFI_IDE_MODE Mode = 0; UINT8 Channel = 0; UINT8 Device = 0; UINTN DeviceCount = 0; IDE_RECOVERY_DEVICE_INFO DeviceInfo; UINT8 NativeIdeModeCount = 0; if ( !gHaveCalledAtaAtapiCommonInit ) { AtaAtapiCommonInit( gPeiServices ); gHaveCalledAtaAtapiCommonInit = TRUE; } if ( gIdeRecoveryNativeModeSupport ) { // //Based on the number of Nativemode PPI maximum mode support is adjusted // MaxModes = IdeMaxMode + gNativeIdeCount - 1; } else { MaxModes = IdeNative; } for ( Mode = IdeLegacy; Mode < MaxModes; Mode++ ) { for ( Channel = IdePrimary; Channel < IdeMaxChannel; Channel++ ) { for ( Device = IdeMaster; Device < IdeMaxDevice; Device++ ) { DeviceInfo.Device = Device; if ( Mode == IdeLegacy ) { if ( Channel == IdePrimary ) { DeviceInfo.IdeIoPortRegisters = &PrimaryChannelLegacyIdeIoPortRegisters; } else { //IdeSecondary DeviceInfo.IdeIoPortRegisters = &SecondaryChannelLegacyIdeIoPortRegisters; } } else { //IdeNative if ( Channel == IdePrimary ) { DeviceInfo.IdeIoPortRegisters = &gNativeModePortRegsiters[NativeIdeModeCount]; } else { //IdeSecondary DeviceInfo.IdeIoPortRegisters = &gNativeModePortRegsiters[NativeIdeModeCount + 1]; } } if ( EnumerateType == EnumerateAtapi ) { if ( Atapi_DiscoverDevice( &DeviceInfo )) { Status = (**gPeiServices).AllocatePool( gPeiServices, sizeof(IDE_RECOVERY_DEVICE_INFO), &(IdeRecoveryBlkIoDev->DeviceInfo[DeviceCount])); if ( EFI_ERROR( Status )) { return; } DeviceInfo.MediaInfo.MediaPresent = FALSE; DeviceInfo.MediaInfo.LastBlock = 0; DeviceInfo.LookedForMedia = FALSE; *(IdeRecoveryBlkIoDev->DeviceInfo[DeviceCount]) = DeviceInfo; DeviceCount++; } } else { // //EnumerateAta // if ( Ata_DiscoverDevice( &DeviceInfo )) { Status = (**gPeiServices).AllocatePool( gPeiServices, sizeof(IDE_RECOVERY_DEVICE_INFO), &(IdeRecoveryBlkIoDev->DeviceInfo[DeviceCount])); if ( EFI_ERROR( Status )) { return; } DeviceInfo.MediaInfo.MediaPresent = TRUE; DeviceInfo.MediaInfo.BlockSize = 0x200; DeviceInfo.LookedForMedia = FALSE; *(IdeRecoveryBlkIoDev->DeviceInfo[DeviceCount]) = DeviceInfo; DeviceCount++; } } } } if ( Mode == IdeNative ) { // //index to the Next native mode PPI base address // NativeIdeModeCount = NativeIdeModeCount + 2; } } IdeRecoveryBlkIoDev->DeviceCount = DeviceCount; } // //---------------------------------------------------------------------- // // Procedure: Atapi_DiscoverDevice // // Description: Called by EnumerateDevices. Looks for ATAPI_SIGNATURE. // //---------------------------------------------------------------------- // BOOLEAN Atapi_DiscoverDevice( IDE_RECOVERY_DEVICE_INFO *DeviceInfo ) { EFI_STATUS Status = EFI_SUCCESS; UINT8 Device = DeviceInfo->Device; UINT16 HeadReg = DeviceInfo->IdeIoPortRegisters->Head; UINT16 StatusReg = DeviceInfo->IdeIoPortRegisters->Reg.Status; UINT16 CylinderLsb = DeviceInfo->IdeIoPortRegisters->CylinderLsb; UINT16 CylinderMsb = DeviceInfo->IdeIoPortRegisters->CylinderMsb; UINT8 StatusValue = 0; UINT8 Data8 = 0; // // Select Device // IoWrite8( HeadReg, Device << 4 ); StatusValue = IoRead8( StatusReg ); if ((StatusValue == 0x7f) || (StatusValue == 0xff)) { return FALSE; } Status = WaitForBSYClear( DeviceInfo->IdeIoPortRegisters, 31000 ); StatusValue = IoRead8( StatusReg ); if ( EFI_ERROR( Status )) { return FALSE; } Data8 = IoRead8( CylinderLsb ); if ( Data8 == (ATAPI_SIGNATURE & 0xff)) { Data8 = IoRead8( CylinderMsb ); if ( Data8 == (ATAPI_SIGNATURE >> 8)) { Status = Inquiry( DeviceInfo ); if ( !EFI_ERROR( Status )) { return TRUE; } } } return FALSE; } // //---------------------------------------------------------------------- // // Procedure: Ata_DiscoverDevice // // Description: Called by EnumerateDevices. Looks at IDENTIFY data. // //---------------------------------------------------------------------- // BOOLEAN Ata_DiscoverDevice( IDE_RECOVERY_DEVICE_INFO *DeviceInfo ) { EFI_STATUS Status = EFI_SUCCESS; UINT8 Device = DeviceInfo->Device; UINT16 HeadReg = DeviceInfo->IdeIoPortRegisters->Head; UINT16 StatusReg = DeviceInfo->IdeIoPortRegisters->Reg.Status; UINT16 CylinderLsb = DeviceInfo->IdeIoPortRegisters->CylinderLsb; UINT16 CylinderMsb = DeviceInfo->IdeIoPortRegisters->CylinderMsb; UINT8 StatusValue = 0; UINT8 Data8 = 0; ATA_IDENTIFY_DATA AtaIdentifyData; // //Select Device // IoWrite8( HeadReg, Device << 4 ); StatusValue = IoRead8( StatusReg ); if ((StatusValue == 0x7f) || (StatusValue == 0xff)) { return FALSE; } Status = WaitForBSYClear( DeviceInfo->IdeIoPortRegisters, 31000 ); StatusValue = IoRead8( StatusReg ); if ( EFI_ERROR( Status )) { return FALSE; } Data8 = IoRead8( CylinderLsb ); if ( Data8 == (ATAPI_SIGNATURE & 0xff)) { Data8 = IoRead8( CylinderMsb ); if ( Data8 == (ATAPI_SIGNATURE >> 8)) { return FALSE; } } if ( AtaIdentify( DeviceInfo, &AtaIdentifyData ) == EFI_SUCCESS ) { if ((AtaIdentifyData.GeneralConfiguration_0 & 0x8000) == 0 ) { DeviceInfo->MediaInfo.DeviceType = MaxDeviceType; DeviceInfo->MediaInfo.LastBlock = AtaIdentifyData.TotalUserAddressableSectors_60; return TRUE; } } return FALSE; } // //---------------------------------------------------------------------- // // Procedure: AtapiPacketCommandIn // // Description: Executes various ATAPI packet commands // (TEST_UNIT_READY, INQUIRY, REQUEST_SENSE, READ_CAPACITY, etc). // //---------------------------------------------------------------------- // EFI_STATUS AtapiPacketCommandIn( IN IDE_RECOVERY_DEVICE_INFO *DeviceInfo, IN ATAPI_PACKET_COMMAND *Packet, IN UINT16 *Buffer, IN UINT32 ByteCount, IN UINTN TimeoutInMilliSeconds ) { IDE_BASE_REGISTERS *IdeIoPortRegisters = DeviceInfo->IdeIoPortRegisters; UINT8 Device = DeviceInfo->Device; UINT16 StatusReg = IdeIoPortRegisters->Reg.Status; UINT16 HeadReg = IdeIoPortRegisters->Head; UINT16 CommandReg = IdeIoPortRegisters->Reg.Command; UINT16 FeatureReg = IdeIoPortRegisters->Reg1.Feature; UINT16 CylinderLsbReg = IdeIoPortRegisters->CylinderLsb; UINT16 CylinderMsbReg = IdeIoPortRegisters->CylinderMsb; UINT16 DeviceControlReg = IdeIoPortRegisters->Alt.DeviceControl; UINT16 DataReg = IdeIoPortRegisters->Data; EFI_STATUS Status = EFI_SUCCESS; UINT32 Count = 0; UINT16 *CommandIndex = NULL; UINT16 *ptrBuffer = Buffer; UINT32 Index = 0; UINT8 StatusValue = 0; UINT32 WordCount = 0; // // required transfer data in word unit. // UINT32 RequiredWordCount = 0; // // actual transfer data in word unit. // UINT32 ActualWordCount = 0; // // Select device via Device/Head Register. // DEFAULT_CMD: 0xa0 (1010,0000) // IoWrite8( HeadReg, (UINT8) ((Device << 4) | DEFAULT_CMD )); // // Set all the command parameters by fill related registers. // Before write to all the following registers, BSY and DRQ must be 0. // if ( DRQClear2( DeviceInfo->IdeIoPortRegisters, TIMEOUT ) != EFI_SUCCESS ) { return EFI_DEVICE_ERROR; } // // No OVL; No DMA // IoWrite8( FeatureReg, 0x00 ); // // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device // determine how many data should be transfered. // IoWrite8( CylinderLsbReg, (UINT8) ( MAX_ATAPI_BYTE_COUNT & 0x00ff )); IoWrite8( CylinderMsbReg, (UINT8) ( MAX_ATAPI_BYTE_COUNT >> 8 )); // // DEFAULT_CTL:0x0a (0000,1010) // Disable interrupt // IoWrite8( DeviceControlReg, DEFAULT_CTL ); // // Send Packet command to inform device // that the following data bytes are command packet. // IoWrite8( CommandReg, PACKET_CMD ); Status = DRQReady( IdeIoPortRegisters, TimeoutInMilliSeconds ); if ( Status != EFI_SUCCESS ) { return Status; } // // Send out command packet // CommandIndex = Packet->Data16; for ( Count = 0; Count < 6; Count++, CommandIndex++ ) { IoWrite16( DataReg, *CommandIndex ); gStallPpi->Stall( gPeiServices, gStallPpi, 10 ); } StatusValue = IoRead8( StatusReg ); WaitForBSYClear( IdeIoPortRegisters, LONGTIMEOUT ); StatusValue = IoRead8( StatusReg ); if ((StatusValue & ERR) == ERR ) { // // Trouble! Something's wrong here... Wait some time and return. 3 second is // supposed to be long enough for a device reset latency or error recovery // gStallPpi->Stall( gPeiServices, gStallPpi, 100000 ); return EFI_DEVICE_ERROR; } if ( Buffer == NULL || ByteCount == 0 ) { return EFI_SUCCESS; } // // call PioReadWriteData() function to get // requested transfer data form device. // ptrBuffer = Buffer; RequiredWordCount = ByteCount / 2; // // ActuralWordCount means the word count of data really transfered. // ActualWordCount = 0; Status = EFI_SUCCESS; while ((Status == EFI_SUCCESS) && (ActualWordCount < RequiredWordCount)) { // // before each data transfer stream, the host should poll DRQ bit ready, // which informs device is ready to transfer data. // if ( DRQReady2( IdeIoPortRegisters, TimeoutInMilliSeconds ) != EFI_SUCCESS ) { return CheckErrorStatus( StatusReg ); } // // read Status Register will clear interrupt // StatusValue = IoRead8( StatusReg ); // // get current data transfer size from Cylinder Registers. // WordCount = (( IoRead8( CylinderMsbReg ) << 8) | IoRead8( CylinderLsbReg )) & 0xffff; WordCount /= 2; // // perform a series data In/Out. // for ( Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++ ) { *ptrBuffer = IoRead16( DataReg ); ptrBuffer++; } if (((GENERIC_CMD*) Packet)->OperationCode_0 == REQUEST_SENSE && ActualWordCount >= 4 ) { RequiredWordCount = EFI_MIN( RequiredWordCount, (UINT32) ( 4 + (((REQUEST_SENSE_DATA*) Buffer)->AdditionalSenseLength_7 / 2)) ); } } // // After data transfer is completed, normally, DRQ bit should clear. // Status = DRQClear2( IdeIoPortRegisters, TimeoutInMilliSeconds ); if ( Status != EFI_SUCCESS ) { return EFI_DEVICE_ERROR; } // // read status register to check whether error happens. // Status = CheckErrorStatus( StatusReg ); return Status; } // //---------------------------------------------------------------------- // // Procedure: Inquiry // // Description: ATAPI packet command INQUIRY. Uses AtapiPacketCommandIn. // //---------------------------------------------------------------------- // EFI_STATUS Inquiry( IN OUT IDE_RECOVERY_DEVICE_INFO *DeviceInfo ) { ATAPI_PACKET_COMMAND Packet; EFI_STATUS Status; INQUIRY_DATA Idata; ZeroMem( &Packet, sizeof (ATAPI_PACKET_COMMAND)); Packet.Cmd.OperationCode_0 = INQUIRY; Packet.Cmd.AllocationLength_4 = sizeof (INQUIRY_DATA); Status = AtapiPacketCommandIn( DeviceInfo, &Packet, (UINT16*)(&Idata), sizeof (INQUIRY_DATA), TIMEOUT ); if ( Status != EFI_SUCCESS ) { return EFI_DEVICE_ERROR; } if ( Idata.PeripheralDeviceType_0 == CD_ROM_DEVICE ) { DeviceInfo->MediaInfo.DeviceType = IdeCDROM; DeviceInfo->MediaInfo.MediaPresent = FALSE; DeviceInfo->MediaInfo.LastBlock = 0; DeviceInfo->MediaInfo.BlockSize = 0x800; return EFI_SUCCESS; } else { return EFI_UNSUPPORTED; } } // //---------------------------------------------------------------------- // // Procedure: Atapi_DetectMedia // // Description: // -Loop: Issues ATAPI packet command TEST_UNIT_READY. // If this is not successful, then look at SENSE data. // If you get the sense data for (1) becoming ready, (2) media // changed, or (3) power on reset, then stall for some time and // continue looping with TEST_UNIT_READY and REQUEST_SENSE. // -If TEST_UNIT_READY is successful, then issue READ_CAPACITY // packet command, which should get device info. // -If TEST_UNIT_READY is not succesful or if the SENSE data // contains some other error (not one of the three listed above), // then return an error. // //---------------------------------------------------------------------- // EFI_STATUS Atapi_DetectMedia( IN OUT IDE_RECOVERY_DEVICE_INFO *DeviceInfo ) { UINTN Index = 0; REQUEST_SENSE_DATA SenseBuffers[MAX_SENSE_KEY_COUNT]; EFI_STATUS Status = EFI_SUCCESS; UINT8 SenseCounts = 0; BOOLEAN DeviceIsReady = FALSE; DeviceInfo->MediaInfo.MediaPresent = FALSE; DeviceInfo->MediaInfo.LastBlock = 0; DeviceIsReady = FALSE; for ( Index = 0; Index < 50; Index++ ) { Status = TestUnitReady( DeviceInfo ); if ( Status == EFI_SUCCESS ) { DeviceIsReady = TRUE; break; } SenseCounts = MAX_SENSE_KEY_COUNT; Status = RequestSense( DeviceInfo, SenseBuffers, &SenseCounts ); if ( SenseCounts == 0 ) { gStallPpi->Stall( gPeiServices, gStallPpi, 250000 ); continue; } if (((SenseBuffers[0].SenseKey_2 == SK_NOT_READY) && (SenseBuffers[0].AdditionalSenseCode_12 == 4) && (SenseBuffers[0].AdditionalSenseCodeQualifier_13 == 1)) // Becoming ready || ((SenseBuffers[0].SenseKey_2 == SK_UNIT_ATTENTION) && (SenseBuffers[0].AdditionalSenseCode_12 == 0x28) && (SenseBuffers[0].AdditionalSenseCodeQualifier_13 == 0)) // Media Changed || ((SenseBuffers[0].SenseKey_2 == SK_UNIT_ATTENTION) && (SenseBuffers[0].AdditionalSenseCode_12 == 0x29) && (SenseBuffers[0].AdditionalSenseCodeQualifier_13 == 0))) { // Power on Reset gStallPpi->Stall( gPeiServices, gStallPpi, 250000 ); } else { break; } } if ( DeviceIsReady ) { Status = ReadCapacity( DeviceInfo ); return Status; } return EFI_DEVICE_ERROR; } // //---------------------------------------------------------------------- // // Procedure: TestUnitReady // // Description: ATAPI command TEST_UINT_READY. Uses AtapiPacketCommandIn. // //---------------------------------------------------------------------- // EFI_STATUS TestUnitReady( IN IDE_RECOVERY_DEVICE_INFO *DeviceInfo ) { ATAPI_PACKET_COMMAND Packet; EFI_STATUS Status; ZeroMem( &Packet, sizeof (ATAPI_PACKET_COMMAND)); Packet.Cmd.OperationCode_0 = TEST_UNIT_READY; Status = AtapiPacketCommandIn( DeviceInfo, &Packet, NULL, 0, TIMEOUT ); return Status; } // //---------------------------------------------------------------------- // // Procedure: RequestSense // // Description: Send Request sense command // //---------------------------------------------------------------------- // EFI_STATUS RequestSense( IN OUT IDE_RECOVERY_DEVICE_INFO *DeviceInfo, IN REQUEST_SENSE_DATA *SenseBuffers, IN OUT UINT8 *SenseCounts ) { EFI_STATUS Status = EFI_SUCCESS; REQUEST_SENSE_DATA *Sense = SenseBuffers; ATAPI_PACKET_COMMAND Packet; ZeroMem( SenseBuffers, sizeof (REQUEST_SENSE_DATA) * (*SenseCounts)); ZeroMem( &Packet, sizeof (ATAPI_PACKET_COMMAND)); Packet.Cmd.OperationCode_0 = REQUEST_SENSE; Packet.Cmd.AllocationLength_4 = sizeof (REQUEST_SENSE_DATA); *SenseCounts = 0; while ( TRUE ) { Status = AtapiPacketCommandIn( DeviceInfo, &Packet, (UINT16*) Sense, sizeof (REQUEST_SENSE_DATA), TIMEOUT ); if ( Status != EFI_SUCCESS ) { if ( *SenseCounts == 0 ) { return EFI_DEVICE_ERROR; } else { return EFI_SUCCESS; } } (*SenseCounts)++; if ( *SenseCounts == MAX_SENSE_KEY_COUNT ) { return EFI_SUCCESS; } // // We limit MAX sense data count to 20 in order to avoid dead loop. Some // incompatible ATAPI devices don't retrive NO_SENSE when there is no media. // In this case, dead loop occurs if we don't have a gatekeeper. 20 is // supposed to be large enough for any ATAPI device. // (Actually 6, not 20). if ( Sense->SenseKey_2 != SK_NO_SENSE ) { Sense++; } else { return EFI_SUCCESS; } } } // //---------------------------------------------------------------------- // // Procedure: ReadCapacity // // Description: ATAPI packet command READ_CAPACITY. // Uses AtapiPacketCommandIn. // //---------------------------------------------------------------------- // EFI_STATUS ReadCapacity( IN OUT IDE_RECOVERY_DEVICE_INFO *DeviceInfo ) { EFI_STATUS Status; ATAPI_PACKET_COMMAND Packet; READ_CAPACITY_DATA Data; ZeroMem( &Data, sizeof (Data)); if ( DeviceInfo->MediaInfo.DeviceType == IdeCDROM ) { ZeroMem( &Packet, sizeof (ATAPI_PACKET_COMMAND)); Packet.Cmd.OperationCode_0 = READ_CAPACITY; Status = AtapiPacketCommandIn( DeviceInfo, &Packet, (UINT16*)(&Data), sizeof (READ_CAPACITY_DATA), LONGTIMEOUT ); if ( Status == EFI_SUCCESS ) { if ( DeviceInfo->MediaInfo.DeviceType == IdeCDROM ) { DeviceInfo->MediaInfo.LastBlock = (Data.LastLba0 << 24) | (Data.LastLba1 << 16) | (Data.LastLba2 << 8) | Data.LastLba3; DeviceInfo->MediaInfo.MediaPresent = TRUE; DeviceInfo->MediaInfo.BlockSize = 0x800; } return EFI_SUCCESS; } else { return EFI_DEVICE_ERROR; } } else { return EFI_UNSUPPORTED; } } // //---------------------------------------------------------------------- // // Procedure: Atapi_ReadSectors // // Description: Helper function called by Atapi_ReadBlocks. // //---------------------------------------------------------------------- // EFI_STATUS Atapi_ReadSectors( IN OUT IDE_RECOVERY_DEVICE_INFO *DeviceInfo, IN VOID *Buffer, IN EFI_PEI_LBA StartLba, IN UINTN NumberOfBlocks, IN UINTN BlockSize ) { ATAPI_PACKET_COMMAND Packet; READ10_CMD *Read10Packet = NULL; EFI_STATUS Status = EFI_SUCCESS; UINTN BlocksRemaining = 0; UINT32 Lba32 = 0; UINT32 ByteCount = 0; UINT16 SectorCount = 0; VOID *ptrBuffer = NULL; UINT16 MaxBlock = 0; ZeroMem( &Packet, sizeof (ATAPI_PACKET_COMMAND)); Read10Packet = &Packet.Read10; Lba32 = (UINT32) StartLba; ptrBuffer = Buffer; // // limit the data bytes that can be transfered by one Read(10) Command // MaxBlock = (UINT16) ( 0x10000 / BlockSize ); // // (64k bytes) // BlocksRemaining = NumberOfBlocks; Status = EFI_SUCCESS; while ( BlocksRemaining > 0 ) { if ( BlocksRemaining <= MaxBlock ) { SectorCount = (UINT16) BlocksRemaining; } else { SectorCount = MaxBlock; } Read10Packet->OperationCode_0 = READ_10; // // Lba0 ~ Lba3 specify the start logical block address of the data transfer. // Lba0 is MSB, Lba3 is LSB // Read10Packet->Lba3 = (UINT8) ( Lba32 & 0xff ); Read10Packet->Lba2 = (UINT8) ( Lba32 >> 8 ); Read10Packet->Lba1 = (UINT8) ( Lba32 >> 16 ); Read10Packet->Lba0 = (UINT8) ( Lba32 >> 24 ); // // TransferLengthMSB ~ TransferLengthLSB specify the transfer length in block unit. // Read10Packet->TransferLengthLSB = (UINT8) ( SectorCount & 0xff ); Read10Packet->TransferLengthMSB = (UINT8) ( SectorCount >> 8 ); ByteCount = (UINT32) ( SectorCount * BlockSize ); Status = AtapiPacketCommandIn( DeviceInfo, &Packet, (UINT16*) ptrBuffer, ByteCount, LONGTIMEOUT ); if ( Status != EFI_SUCCESS ) { return Status; } Lba32 += SectorCount; ptrBuffer = (UINT8*) ptrBuffer + SectorCount * BlockSize; BlocksRemaining -= SectorCount; } return Status; } // //---------------------------------------------------------------------- // // Procedure: AtaPioDataIn // // Description: Does ATA protocol Pio In with data. // //---------------------------------------------------------------------- // EFI_STATUS AtaPioDataIn( IN IDE_BASE_REGISTERS *IdeIoPortRegisters, OUT VOID *Buffer, IN UINT32 ByteCount, IN UINT8 SectorCount, IN UINT8 SectorNumber, IN UINT8 CylinderLsb, IN UINT8 CylinderMsb, IN UINT8 Device, IN UINT8 Command ) { EFI_STATUS Status = EFI_SUCCESS; UINT16 HeadReg = IdeIoPortRegisters->Head; UINT16 SectorCountReg = IdeIoPortRegisters->SectorCount; UINT16 SectorNumberReg = IdeIoPortRegisters->SectorNumber; UINT16 CylinderLsbReg = IdeIoPortRegisters->CylinderLsb; UINT16 CylinderMsbReg = IdeIoPortRegisters->CylinderMsb; UINT16 CommandReg = IdeIoPortRegisters->Reg.Command; UINT16 AltStatusRegister = IdeIoPortRegisters->Alt.AltStatus; UINT16 StatusReg = IdeIoPortRegisters->Reg.Status; UINT16 DataReg = IdeIoPortRegisters->Data; UINT32 WordCount = 0; UINT32 Increment = 0; UINT32 Index = 0; UINT16 *Buffer16 = (UINT16*)Buffer; ; IoWrite8( HeadReg, Device ); Status = WaitForBSYClear( IdeIoPortRegisters, TIMEOUT ); if ( Status != EFI_SUCCESS ) { return EFI_DEVICE_ERROR; } Status = DRQClear2( IdeIoPortRegisters, TIMEOUT ); if ( Status != EFI_SUCCESS ) { return EFI_DEVICE_ERROR; } Status = DRQClear2( IdeIoPortRegisters, TIMEOUT ); if ( Status != EFI_SUCCESS ) { return EFI_DEVICE_ERROR; } IoWrite8( SectorCountReg, SectorCount ); IoWrite8( SectorNumberReg, SectorNumber ); IoWrite8( CylinderLsbReg, CylinderLsb ); IoWrite8( CylinderMsbReg, CylinderMsb ); IoWrite8( CommandReg, Command ); IoRead8( AltStatusRegister ); Increment = 256; WordCount = 0; while ( WordCount < ByteCount / 2 ) { Status = DRQReady2( IdeIoPortRegisters, COMMAND_COMPLETE_TIMEOUT ); if ( Status != EFI_SUCCESS ) { return Status; } if ( CheckErrorStatus( StatusReg ) != EFI_SUCCESS ) { return EFI_DEVICE_ERROR; } if ((WordCount + Increment) > ByteCount / 2 ) { Increment = ByteCount / 2 - WordCount; } for ( Index = 0; Index < Increment; Index++ ) { *Buffer16++ = IoRead16( DataReg ); } WordCount += Increment; } Status = DRQClear( IdeIoPortRegisters, TIMEOUT ); if ( Status != EFI_SUCCESS ) { return CheckErrorStatus( StatusReg ); } return EFI_SUCCESS; } // //---------------------------------------------------------------------- // // Procedure: AtaIdentify // // Description: ATA Identify command. Uses AtaPioDataIn // //---------------------------------------------------------------------- // EFI_STATUS AtaIdentify( IN IDE_RECOVERY_DEVICE_INFO *DeviceInfo, OUT ATA_IDENTIFY_DATA *AtaIdentifyData ) { return AtaPioDataIn( DeviceInfo->IdeIoPortRegisters, AtaIdentifyData, sizeof (ATA_IDENTIFY_DATA), 0, 0, 0, 0, DeviceInfo->Device << 4, ATA_IDENTIFY_DEVICE_CMD ); } // //---------------------------------------------------------------------- // // Procedure: Ata_ReadSectors // // Description: Helper function called by Ata_ReadBlocks. // // Input: // IN IDE_RECOVERY_DEVICE_INFO *DeviceInfo - pointer to the device info structure // IN OUT VOID *Buffer - Pointer to a buffer that will hold the Data that is read // IN EFI_PEI_LBA StartLba - the first LBA to read // IN UINTN NumberOfBlocks - total number of blocks to read // IN UINTN BlockSize - size of the blocks to be read // // Output: // EFI_SUCCESS - Read happened correctly // OTHER - any valid error from AtaPioDataIn() // //---------------------------------------------------------------------- // EFI_STATUS Ata_ReadSectors( IN IDE_RECOVERY_DEVICE_INFO *DeviceInfo, IN OUT VOID *Buffer, IN EFI_PEI_LBA StartLba, IN UINTN NumberOfBlocks, IN UINTN BlockSize ) { EFI_STATUS Status = EFI_SUCCESS; UINTN BlocksRemaining = 0; UINT32 Lba32 = 0; UINT8 LbaLow = 0; UINT8 LbaMid = 0; UINT8 LbaHigh = 0; UINT32 ByteCount = 0; UINT16 SectorCount = 0; VOID *ptrBuffer = NULL; UINT16 MaxBlock = 0; UINT8 Dev = 0; UINT8 Device = 0; Lba32 = (UINT32) StartLba; ptrBuffer = Buffer; MaxBlock = (UINT16) ( 0x20000 / BlockSize ); BlocksRemaining = NumberOfBlocks; Status = EFI_SUCCESS; Dev = (DeviceInfo->Device << 4) | LBA_MODE; while ( BlocksRemaining > 0 ) { if ( BlocksRemaining < MaxBlock ) { SectorCount = BlocksRemaining; } else { SectorCount = MaxBlock; } LbaLow = (UINT8) ( Lba32 & 0xff ); LbaMid = (UINT8) ( Lba32 >> 8 ); LbaHigh = (UINT8) ( Lba32 >> 16 ); ByteCount = (UINT32) ( SectorCount * BlockSize ); Dev |= (Lba32 >> 24); Status = AtaPioDataIn( DeviceInfo->IdeIoPortRegisters, ptrBuffer, ByteCount, (UINT8) SectorCount, //sector count LbaLow, //sector number LbaMid, //lsb LbaHigh, //msb Dev, ATA_READ_SECTOR_CMD ); if ( Status != EFI_SUCCESS ) { return Status; } Lba32 += SectorCount; ptrBuffer = (UINT8*) ptrBuffer + SectorCount * BlockSize; BlocksRemaining -= SectorCount; } return Status; } // //---------------------------------------------------------------------- // // Procedure: WaitForBitsToClear // // Description: Helper functin used by WaitForBSYClear, DRQClear, DRQClear2. // //---------------------------------------------------------------------- // EFI_STATUS WaitForBitsToClear( UINT16 Register, UINT8 Bits, UINTN TimeoutInMilliSeconds ) { UINTN Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1; UINT8 StatusValue = 0; do { StatusValue = IoRead8( Register ); if ((StatusValue & Bits) == 0x00 ) { break; } gStallPpi->Stall( gPeiServices, gStallPpi, 250 ); Delay--; } while ( Delay ); if ( Delay == 0 ) { return EFI_TIMEOUT; } return EFI_SUCCESS; } // //---------------------------------------------------------------------- // // Procedure: WaitForBSYClear // // Description: Wait for busy bit to clear // //---------------------------------------------------------------------- // EFI_STATUS WaitForBSYClear( IN IDE_BASE_REGISTERS *IdeIoRegisters, IN UINTN TimeoutInMilliSeconds ) { return WaitForBitsToClear( IdeIoRegisters->Reg.Status, BSY, TimeoutInMilliSeconds ); } // //---------------------------------------------------------------------- // // Procedure: DRQClear // // Description: Wait for the DRQ bit clear // //---------------------------------------------------------------------- // EFI_STATUS DRQClear( IN IDE_BASE_REGISTERS *IdeIoRegisters, IN UINTN TimeoutInMilliSeconds ) { return WaitForBitsToClear( IdeIoRegisters->Reg.Status, DRQ | BSY, TimeoutInMilliSeconds ); } // //---------------------------------------------------------------------- // // Procedure: DRQClear2 // // Description: Wait for the DRQ bit clear in Alternate Status Reg // //---------------------------------------------------------------------- // EFI_STATUS DRQClear2( IN IDE_BASE_REGISTERS *IdeIoRegisters, IN UINTN TimeoutInMilliSeconds ) { return WaitForBitsToClear( IdeIoRegisters->Alt.AltStatus, DRQ | BSY, TimeoutInMilliSeconds ); } // //---------------------------------------------------------------------- // // Procedure: DRQReadyHelper // // Description: // //---------------------------------------------------------------------- // EFI_STATUS DRQReadyHelper( UINT16 StatusRegister, UINT16 ErrorRegister, IN UINTN TimeoutInMilliSeconds ) { UINTN Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1; UINT8 StatusValue = 0; UINT8 ErrValue = 0; do { // // read Status Register will clear interrupt // StatusValue = IoRead8( StatusRegister ); // // BSY==0,DRQ==1 // if ((StatusValue & (BSY | DRQ)) == DRQ ) { break; } if ((StatusValue & (BSY | ERR)) == ERR ) { ErrValue = IoRead8( ErrorRegister ); if ((ErrValue & ABRT_ERR) == ABRT_ERR ) { return EFI_ABORTED; } } gStallPpi->Stall( gPeiServices, gStallPpi, 250 ); Delay--; } while ( Delay ); if ( Delay == 0 ) { return EFI_TIMEOUT; } return EFI_SUCCESS; } // //---------------------------------------------------------------------- // // Procedure: DRQReady // // Description: Wait for the DRQ ready // //---------------------------------------------------------------------- // EFI_STATUS DRQReady( IN IDE_BASE_REGISTERS *IdeIoRegisters, IN UINTN TimeoutInMilliSeconds ) { return DRQReadyHelper( IdeIoRegisters->Reg.Status, IdeIoRegisters->Reg1.Error, TimeoutInMilliSeconds ); } // //---------------------------------------------------------------------- // // Procedure: DRQReady2 // // Description: Wait for the DRQ Ready in Alternate Status Reg // //---------------------------------------------------------------------- // EFI_STATUS DRQReady2( IN IDE_BASE_REGISTERS *IdeIoRegisters, IN UINTN TimeoutInMilliSeconds ) { return DRQReadyHelper( IdeIoRegisters->Alt.AltStatus, IdeIoRegisters->Reg1.Error, TimeoutInMilliSeconds ); } // //---------------------------------------------------------------------- // // Procedure: CheckErrorStatus // // Description: Check for the Errros. // //---------------------------------------------------------------------- // EFI_STATUS CheckErrorStatus( IN UINT16 StatusReg ) { UINT8 StatusValue = IoRead8( StatusReg ); if ((StatusValue & (ERR | DWF | CORR)) == 0 ) { return EFI_SUCCESS; } return EFI_DEVICE_ERROR; } // //---------------------------------------------------------------------- // // Procedure: ZeroMem // // Description: Clear the Memory // //---------------------------------------------------------------------- // static VOID ZeroMem( IN VOID *Buffer, IN UINTN Size ) { UINT8 *ptr; ptr = Buffer; while ( Size-- ) { *(ptr++) = 0; } } //********************************************************************** //********************************************************************** //** ** //** (C)Copyright 1985-2011, American Megatrends, Inc. ** //** ** //** All Rights Reserved. ** //** ** //** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** //** ** //** Phone: (770)-246-8600 ** //** ** //********************************************************************** //**********************************************************************