X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=EdkModulePkg%2FBus%2FPci%2FIdeBus%2FDxe%2Fide.c;h=4b4a8ef0a355cfe798d31b2dfba5eba993bd3f28;hp=d318fd23df98c4188be7f8ae3b85c9abd1ff97e3;hb=bc4e770c78d692a5a2641359f605d6e83c96da5d;hpb=878ddf1fc3540a715f63594ed22b6929e881afb4 diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c index d318fd23df..4b4a8ef0a3 100644 --- a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c @@ -1,50 +1,37 @@ -/*++ +/** @file + Copyright (c) 2006, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php -Copyright (c) 2006, Intel Corporation -All rights reserved. This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -Module Name: +**/ - ide.c - -Abstract: - +#include "idebus.h" -Revision History ---*/ +BOOLEAN ChannelDeviceDetected = FALSE; +BOOLEAN SlaveDeviceExist = FALSE; +UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE; +BOOLEAN MasterDeviceExist = FALSE; +UINT8 MasterDeviceType = INVALID_DEVICE_TYPE; -#include "idebus.h" +/** + TODO: Add function description + + @param PciIo TODO: add argument description + @param Port TODO: add argument description -BOOLEAN SlaveDeviceExist = FALSE; -BOOLEAN MasterDeviceExist = FALSE; + TODO: add return values +**/ UINT8 IDEReadPortB ( IN EFI_PCI_IO_PROTOCOL *PciIo, IN UINT16 Port ) -/*++ - -Routine Description: - - TODO: Add function description - -Arguments: - - PciIo - TODO: add argument description - Port - TODO: add argument description - -Returns: - - TODO: add return values - ---*/ { UINT8 Data; @@ -63,6 +50,17 @@ Returns: return Data; } +/** + Reads multiple words of data from the IDE data port. + Call the IO abstraction once to do the complete read, + not one word at a time + + @param PciIo Pointer to the EFI_PCI_IO instance + @param Port IO port to read + @param Count No. of UINT16's to read + @param Buffer Pointer to the data buffer for read + +**/ VOID IDEReadPortWMultiple ( IN EFI_PCI_IO_PROTOCOL *PciIo, @@ -70,23 +68,6 @@ IDEReadPortWMultiple ( IN UINTN Count, IN VOID *Buffer ) -/*++ - -Routine Description: - Reads multiple words of data from the IDE data port. - Call the IO abstraction once to do the complete read, - not one word at a time - - -Arguments: - PciIo - Pointer to the EFI_PCI_IO instance - Port - IO port to read - Count - No. of UINT16's to read - Buffer - Pointer to the data buffer for read - -++*/ -// TODO: function comment should end with '--*/' -// TODO: function comment is missing 'Returns:' { UINT16 *AlignedBuffer; UINT16 *WorkingBuffer; @@ -127,29 +108,22 @@ Arguments: gBS->FreePool (WorkingBuffer); } +/** + TODO: Add function description + + @param PciIo TODO: add argument description + @param Port TODO: add argument description + @param Data TODO: add argument description + + TODO: add return values + +**/ VOID IDEWritePortB ( IN EFI_PCI_IO_PROTOCOL *PciIo, IN UINT16 Port, IN UINT8 Data ) -/*++ - -Routine Description: - - TODO: Add function description - -Arguments: - - PciIo - TODO: add argument description - Port - TODO: add argument description - Data - TODO: add argument description - -Returns: - - TODO: add return values - ---*/ { // // perform 1-byte data write to register @@ -165,29 +139,22 @@ Returns: } +/** + TODO: Add function description + + @param PciIo TODO: add argument description + @param Port TODO: add argument description + @param Data TODO: add argument description + + TODO: add return values + +**/ VOID IDEWritePortW ( IN EFI_PCI_IO_PROTOCOL *PciIo, IN UINT16 Port, IN UINT16 Data ) -/*++ - -Routine Description: - - TODO: Add function description - -Arguments: - - PciIo - TODO: add argument description - Port - TODO: add argument description - Data - TODO: add argument description - -Returns: - - TODO: add return values - ---*/ { // // perform 1-word data write to register @@ -202,6 +169,17 @@ Returns: ); } +/** + Write multiple words of data to the IDE data port. + Call the IO abstraction once to do the complete read, + not one word at a time + + @param PciIo Pointer to the EFI_PCI_IO instance + @param Port IO port to read + @param Count No. of UINT16's to read + @param Buffer Pointer to the data buffer for read + +**/ VOID IDEWritePortWMultiple ( IN EFI_PCI_IO_PROTOCOL *PciIo, @@ -209,23 +187,6 @@ IDEWritePortWMultiple ( IN UINTN Count, IN VOID *Buffer ) -/*++ - -Routine Description: - Write multiple words of data to the IDE data port. - Call the IO abstraction once to do the complete read, - not one word at a time - - -Arguments: - PciIo - Pointer to the EFI_PCI_IO instance - Port - IO port to read - Count - No. of UINT16's to read - Buffer - Pointer to the data buffer for read - -++*/ -// TODO: function comment should end with '--*/' -// TODO: function comment is missing 'Returns:' { UINT16 *AlignedBuffer; UINT32 *WorkingBuffer; @@ -267,137 +228,65 @@ Arguments: gBS->FreePool (WorkingBuffer); } -BOOLEAN -BadIdeDeviceCheck ( - IN IDE_BLK_IO_DEV *IdeDev - ) -/*++ - -Routine Description: - - TODO: Add function description - -Arguments: - - IdeDev - TODO: add argument description - -Returns: - - TODO: add return values - ---*/ -{ - // - // check whether all registers return 0xff, - // if so, deem the channel is disabled. - // -#ifdef EFI_DEBUG - - if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Data) != 0xff) { - return FALSE; - } - - if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature) != 0xff) { - return FALSE; - } - - if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount) != 0xff) { - return FALSE; - } - - if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber) != 0xff) { - return FALSE; - } - - if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb) != 0xff) { - return FALSE; - } - - if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) != 0xff) { - return FALSE; - } - - if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Head) != 0xff) { - return FALSE; - } - - if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command) != 0xff) { - return FALSE; - } - - if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus) != 0xff) { - return FALSE; - } - - return TRUE; - -#else - - return FALSE; - -#endif -} - // // GetIdeRegistersBaseAddr // -EFI_STATUS -GetIdeRegistersBaseAddr ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr - ) -/*++ - -Routine Description: +/** Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode, use fixed addresses. In Native-PCI mode, get base addresses from BARs in the PCI IDE controller's Configuration Space. - - The steps to get IDE IO port registers' base addresses for each channel + + The steps to get IDE IO port registers' base addresses for each channel as follows: - 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE - controller's Configuration Space to determine the operating mode. - + 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE + controller's Configuration Space to determine the operating mode. + 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below. - ___________________________________________ - | | Command Block | Control Block | - | Channel | Registers | Registers | - |___________|_______________|_______________| - | Primary | 1F0h - 1F7h | 3F6h - 3F7h | - |___________|_______________|_______________| - | Secondary | 170h - 177h | 376h - 377h | - |___________|_______________|_______________| - - Table 1. Compatibility resource mappings - - b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs - in IDE controller's PCI Configuration Space, shown in the Table 2 below. - ___________________________________________________ - | | Command Block | Control Block | - | Channel | Registers | Registers | - |___________|___________________|___________________| - | Primary | BAR at offset 0x10| BAR at offset 0x14| - |___________|___________________|___________________| - | Secondary | BAR at offset 0x18| BAR at offset 0x1C| - |___________|___________________|___________________| - - Table 2. BARs for Register Mapping - Note: Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for - primary, 0374h for secondary. So 2 bytes extra offset should be - added to the base addresses read from BARs. - - For more details, please refer to PCI IDE Controller Specification and Intel +
+  ___________________________________________
+  |           | Command Block | Control Block |
+  |  Channel  |   Registers   |   Registers   |
+  |___________|_______________|_______________|
+  |  Primary  |  1F0h - 1F7h  |  3F6h - 3F7h  |
+  |___________|_______________|_______________|
+  | Secondary |  170h - 177h  |  376h - 377h  |
+  |___________|_______________|_______________|
+
+  Table 1. Compatibility resource mappings
+  
+ + b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs + in IDE controller's PCI Configuration Space, shown in the Table 2 below. +
+  ___________________________________________________
+  |           |   Command Block   |   Control Block   |
+  |  Channel  |     Registers     |     Registers     |
+  |___________|___________________|___________________|
+  |  Primary  | BAR at offset 0x10| BAR at offset 0x14|
+  |___________|___________________|___________________|
+  | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
+  |___________|___________________|___________________|
+
+  Table 2. BARs for Register Mapping
+  
+ @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for + primary, 0374h for secondary. So 2 bytes extra offset should be + added to the base addresses read from BARs. + + For more details, please refer to PCI IDE Controller Specification and Intel ICH4 Datasheet. - -Arguments: - PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance - IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to - receive IDE IO port registers' base addresses - -Returns: - ---*/ + + @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance + @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to + receive IDE IO port registers' base addresses + +**/ +EFI_STATUS +GetIdeRegistersBaseAddr ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr + ) // TODO: EFI_UNSUPPORTED - add return value to function comment // TODO: EFI_UNSUPPORTED - add return value to function comment // TODO: EFI_SUCCESS - add return value to function comment @@ -420,13 +309,13 @@ Returns: if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) { IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0; IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6; - IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr = + IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr = (UINT16)((PciData.Device.Bar[4] & 0x0000fff0)); } else { // // The BARs should be of IO type // - if ((PciData.Device.Bar[0] & bit0) == 0 || + if ((PciData.Device.Bar[0] & bit0) == 0 || (PciData.Device.Bar[1] & bit0) == 0) { return EFI_UNSUPPORTED; } @@ -464,24 +353,19 @@ Returns: return EFI_SUCCESS; } +/** + This function is used to requery IDE resources. The IDE controller will + probably switch between native and legacy modes during the EFI->CSM->OS + transfer. We do this everytime before an BlkIo operation to ensure its + succeess. + + @param IdeDev The BLK_IO private data which specifies the IDE device + +**/ EFI_STATUS ReassignIdeResources ( IN IDE_BLK_IO_DEV *IdeDev ) -/*++ - -Routine Description: - This function is used to requery IDE resources. The IDE controller will - probably switch between native and legacy modes during the EFI->CSM->OS - transfer. We do this everytime before an BlkIo operation to ensure its - succeess. - -Arguments: - IdeDev - The BLK_IO private data which specifies the IDE device - -++*/ -// TODO: function comment should end with '--*/' -// TODO: function comment is missing 'Returns:' // TODO: EFI_SUCCESS - add return value to function comment { EFI_STATUS Status; @@ -519,125 +403,85 @@ Arguments: return EFI_SUCCESS; } -EFI_STATUS -CheckPowerMode ( - IDE_BLK_IO_DEV *IdeDev - ) -/*++ - Routine Description: - - Read SATA registers to detect SATA disks - - Arguments: - - IdeDev - The BLK_IO private data which specifies the IDE device - -++*/ -// TODO: function comment should end with '--*/' -// TODO: function comment is missing 'Returns:' -// TODO: EFI_NOT_FOUND - add return value to function comment -// TODO: EFI_SUCCESS - add return value to function comment -// TODO: EFI_NOT_FOUND - add return value to function comment -{ - UINT8 ErrorRegister; - EFI_STATUS Status; - - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->Head, - (UINT8) ((IdeDev->Device << 4) | 0xe0) - ); - - // - // Wait 31 seconds for BSY clear. BSY should be in clear state if there exists - // a device (initial state). Normally, BSY is also in clear state if there is - // no device - // - Status = WaitForBSYClear (IdeDev, 31000); - if (EFI_ERROR (Status)) { - return EFI_NOT_FOUND; - } - - // - // select device, read error register - // - IDEWritePortB ( - IdeDev->PciIo, - IdeDev->IoPort->Head, - (UINT8) ((IdeDev->Device << 4) | 0xe0) - ); - Status = DRDYReady (IdeDev, 200); - - ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); - if ((ErrorRegister == 0x01) || (ErrorRegister == 0x81)) { - return EFI_SUCCESS; - } else { - return EFI_NOT_FOUND; - } -} - // // DiscoverIdeDevice // +/** + Detect if there is disk connected to this port + + @param IdeDev The BLK_IO private data which specifies the IDE device + +**/ EFI_STATUS DiscoverIdeDevice ( IN IDE_BLK_IO_DEV *IdeDev ) -/*++ - Routine Description: - - Detect if there is disk connected to this port - - Arguments: - - IdeDev - The BLK_IO private data which specifies the IDE device - -++*/ -// TODO: function comment should end with '--*/' -// TODO: function comment is missing 'Returns:' // TODO: EFI_NOT_FOUND - add return value to function comment // TODO: EFI_NOT_FOUND - add return value to function comment // TODO: EFI_SUCCESS - add return value to function comment { EFI_STATUS Status; - BOOLEAN SataFlag; - SataFlag = FALSE; - // - // This extra detection is for SATA disks - // - Status = CheckPowerMode (IdeDev); - if (Status == EFI_SUCCESS) { - SataFlag = TRUE; - } - // // If a channel has not been checked, check it now. Then set it to "checked" state // After this step, all devices in this channel have been checked. // - Status = DetectIDEController (IdeDev); - - if ((EFI_ERROR (Status)) && !SataFlag) { - return EFI_NOT_FOUND; - } - - // - // Device exists. test if it is an ATA device - // - Status = ATAIdentify (IdeDev); - if (EFI_ERROR (Status)) { - // - // if not ATA device, test if it is an ATAPI device - // - Status = ATAPIIdentify (IdeDev); + if (ChannelDeviceDetected == FALSE) { + Status = DetectIDEController (IdeDev); if (EFI_ERROR (Status)) { - // - // if not ATAPI device either, return error. - // return EFI_NOT_FOUND; } } + Status = EFI_NOT_FOUND; + + // + // Device exists. test if it is an ATA device. + // Prefer the result from DetectIDEController, + // if failed, try another device type to handle + // devices that not follow the spec. + // + if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) { + if (MasterDeviceType == ATA_DEVICE_TYPE) { + Status = ATAIdentify (IdeDev); + if (EFI_ERROR (Status)) { + Status = ATAPIIdentify (IdeDev); + if (!EFI_ERROR (Status)) { + MasterDeviceType = ATAPI_DEVICE_TYPE; + } + } + } else { + Status = ATAPIIdentify (IdeDev); + if (EFI_ERROR (Status)) { + Status = ATAIdentify (IdeDev); + if (!EFI_ERROR (Status)) { + MasterDeviceType = ATA_DEVICE_TYPE; + } + } + } + } + if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) { + if (SlaveDeviceType == ATA_DEVICE_TYPE) { + Status = ATAIdentify (IdeDev); + if (EFI_ERROR (Status)) { + Status = ATAPIIdentify (IdeDev); + if (!EFI_ERROR (Status)) { + SlaveDeviceType = ATAPI_DEVICE_TYPE; + } + } + } else { + Status = ATAPIIdentify (IdeDev); + if (EFI_ERROR (Status)) { + Status = ATAIdentify (IdeDev); + if (!EFI_ERROR (Status)) { + SlaveDeviceType = ATA_DEVICE_TYPE; + } + } + } + } + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } // // Init Block I/O interface // @@ -662,82 +506,71 @@ DiscoverIdeDevice ( return EFI_SUCCESS; } +/** + This interface is used to initialize all state data related to the detection of one + channel. + + @retval EFI_SUCCESS Completed Successfully. + +**/ EFI_STATUS -DetectIDEController ( - IN IDE_BLK_IO_DEV *IdeDev +InitializeIDEChannelData ( + VOID ) -/*++ - - Name: DetectIDEController - +{ + ChannelDeviceDetected = FALSE; + MasterDeviceExist = FALSE; + MasterDeviceType = 0xff; + SlaveDeviceExist = FALSE; + SlaveDeviceType = 0xff; + return EFI_SUCCESS; +} - Purpose: - This function is called by DiscoverIdeDevice(). It is used for detect - whether the IDE device exists in the specified Channel as the specified - Device Number. +/** + This function is called by DiscoverIdeDevice(). It is used for detect + whether the IDE device exists in the specified Channel as the specified + Device Number. - There is two IDE channels: one is Primary Channel, the other is - Secondary Channel.(Channel is the logical name for the physical "Cable".) - Different channel has different register group. + There is two IDE channels: one is Primary Channel, the other is + Secondary Channel.(Channel is the logical name for the physical "Cable".) + Different channel has different register group. - On each IDE channel, at most two IDE devices attach, - one is called Device 0 (Master device), the other is called Device 1 - (Slave device). The devices on the same channel co-use the same register - group, so before sending out a command for a specified device via command - register, it is a must to select the current device to accept the command - by set the device number in the Head/Device Register. - - - Parameters: - IDE_BLK_IO_DEV IN *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. + On each IDE channel, at most two IDE devices attach, + one is called Device 0 (Master device), the other is called Device 1 + (Slave device). The devices on the same channel co-use the same register + group, so before sending out a command for a specified device via command + register, it is a must to select the current device to accept the command + by set the device number in the Head/Device Register. + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. - Returns: - TRUE - successfully detects device. + @retval TRUE + successfully detects device. - FALSE - any failure during detection process will return this - value. + @retval FALSE + any failure during detection process will return this + value. + @note + TODO: EFI_SUCCESS - add return value to function comment + TODO: EFI_NOT_FOUND - add return value to function comment - Notes: ---*/ -// TODO: function comment is missing 'Routine Description:' -// TODO: function comment is missing 'Arguments:' -// TODO: IdeDev - add argument and description to function comment -// TODO: EFI_SUCCESS - add return value to function comment -// TODO: EFI_NOT_FOUND - add return value to function comment +**/ +EFI_STATUS +DetectIDEController ( + IN IDE_BLK_IO_DEV *IdeDev + ) { EFI_STATUS Status; - UINT8 ErrorReg; - UINT8 StatusReg; + UINT8 SectorCountReg; + UINT8 LBALowReg; + UINT8 LBAMidReg; + UINT8 LBAHighReg; UINT8 InitStatusReg; - EFI_STATUS DeviceStatus; - - // - // Slave device has been detected with master device. - // - if ((IdeDev->Device) == 1) { - if (SlaveDeviceExist) { - // - // If master not exists but slave exists, slave have to wait a while - // - if (!MasterDeviceExist) { - // - // if single slave can't be detected, add delay 4s here. - // - gBS->Stall (4000000); - } + UINT8 StatusReg; - return EFI_SUCCESS; - } else { - return EFI_NOT_FOUND; - } - } - // // Select slave device // @@ -754,7 +587,7 @@ DetectIDEController ( InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); // - // Select master back + // Select Master back // IDEWritePortB ( IdeDev->PciIo, @@ -762,6 +595,7 @@ DetectIDEController ( (UINT8) ((0 << 4) | 0xe0) ); gBS->Stall (100); + // // Send ATA Device Execut Diagnostic command. // This command should work no matter DRDY is ready or not @@ -769,117 +603,153 @@ DetectIDEController ( IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90); Status = WaitForBSYClear (IdeDev, 3500); - - ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); - + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status)); + return Status; + } // - // Master Error register is 0x01. D0 passed, D1 passed or not present. - // Master Error register is 0x81. D0 passed, D1 failed. Return. - // Master Error register is other value. D0 failed, D1 passed or not present.. + // Read device signature // - if (ErrorReg == 0x01) { - MasterDeviceExist = TRUE; - DeviceStatus = EFI_SUCCESS; - } else if (ErrorReg == 0x81) { - + // + // Select Master + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((0 << 4) | 0xe0) + ); + gBS->Stall (100); + SectorCountReg = IDEReadPortB ( + IdeDev->PciIo, + IdeDev->IoPort->SectorCount + ); + LBALowReg = IDEReadPortB ( + IdeDev->PciIo, + IdeDev->IoPort->SectorNumber + ); + LBAMidReg = IDEReadPortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderLsb + ); + LBAHighReg = IDEReadPortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderMsb + ); + if ((SectorCountReg == 0x1) && + (LBALowReg == 0x1) && + (LBAMidReg == 0x0) && + (LBAHighReg == 0x0)) { MasterDeviceExist = TRUE; - DeviceStatus = EFI_SUCCESS; - SlaveDeviceExist = FALSE; - - return DeviceStatus; + MasterDeviceType = ATA_DEVICE_TYPE; } else { - MasterDeviceExist = FALSE; - DeviceStatus = EFI_NOT_FOUND; + if ((LBAMidReg == 0x14) && + (LBAHighReg == 0xeb)) { + MasterDeviceExist = TRUE; + MasterDeviceType = ATAPI_DEVICE_TYPE; + } } - + // - // Master Error register is not 0x81, Go on check Slave + // For some Hard Drive, it takes some time to get + // the right signature when operating in single slave mode. + // We stall 20ms to work around this. // + if (!MasterDeviceExist) { + gBS->Stall (20000); + } // - // select slave + // Select Slave // IDEWritePortB ( IdeDev->PciIo, IdeDev->IoPort->Head, (UINT8) ((1 << 4) | 0xe0) ); - - gBS->Stall (300); - ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + gBS->Stall (100); + SectorCountReg = IDEReadPortB ( + IdeDev->PciIo, + IdeDev->IoPort->SectorCount + ); + LBALowReg = IDEReadPortB ( + IdeDev->PciIo, + IdeDev->IoPort->SectorNumber + ); + LBAMidReg = IDEReadPortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderLsb + ); + LBAHighReg = IDEReadPortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderMsb + ); + StatusReg = IDEReadPortB ( + IdeDev->PciIo, + IdeDev->IoPort->Reg.Status + ); + if ((SectorCountReg == 0x1) && + (LBALowReg == 0x1) && + (LBAMidReg == 0x0) && + (LBAHighReg == 0x0)) { + SlaveDeviceExist = TRUE; + SlaveDeviceType = ATA_DEVICE_TYPE; + } else { + if ((LBAMidReg == 0x14) && + (LBAHighReg == 0xeb)) { + SlaveDeviceExist = TRUE; + SlaveDeviceType = ATAPI_DEVICE_TYPE; + } + } // - // Slave Error register is not 0x01, D1 failed. Return. + // When single master is plugged, slave device + // will be wrongly detected. Here's the workaround + // for ATA devices by detecting DRY bit in status + // register. + // NOTE: This workaround doesn't apply to ATAPI. // - if (ErrorReg != 0x01) { + if (MasterDeviceExist && SlaveDeviceExist && + (StatusReg & DRDY) == 0 && + (InitStatusReg & DRDY) == 0 && + MasterDeviceType == SlaveDeviceType && + SlaveDeviceType != ATAPI_DEVICE_TYPE) { SlaveDeviceExist = FALSE; - return DeviceStatus; } - StatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); - // - // Most ATAPI devices don't set DRDY bit, so test with a slow but accurate - // "ATAPI TEST UNIT READY" command + // Indicate this channel has been detected // - if (((StatusReg & DRDY) == 0) && ((InitStatusReg & DRDY) == 0)) { - Status = AtapiTestUnitReady (IdeDev); + ChannelDeviceDetected = TRUE; + return EFI_SUCCESS; +} - // - // Still fail, Slave doesn't exist. - // - if (EFI_ERROR (Status)) { - SlaveDeviceExist = FALSE; - return DeviceStatus; - } - } +/** + This function is used to poll for the DRQ bit clear in the Status + Register. DRQ is cleared when the device is finished transferring data. + So this function is called after data transfer is finished. - // - // Error reg is 0x01 and DRDY is ready, - // or ATAPI test unit ready success, - // or init Slave status DRDY is ready - // Slave exists. - // - SlaveDeviceExist = TRUE; + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. - return DeviceStatus; + @param[in] TimeoutInMilliSeconds + used to designate the timeout for the DRQ clear. -} + @retval EFI_SUCCESS + DRQ bit clear within the time out. + @retval EFI_TIMEOUT + DRQ bit not clear within the time out. + + @note + Read Status Register will clear interrupt status. + +**/ EFI_STATUS DRQClear ( IN IDE_BLK_IO_DEV *IdeDev, IN UINTN TimeoutInMilliSeconds ) -/*++ - Name: DRQClear - - - Purpose: - This function is used to poll for the DRQ bit clear in the Status - Register. DRQ is cleared when the device is finished transferring data. - So this function is called after data transfer is finished. - - - Parameters: - IDE_BLK_IO_DEV IN *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. - - UINTN IN TimeoutInMilliSeconds - used to designate the timeout for the DRQ clear. - - Returns: - EFI_SUCCESS - DRQ bit clear within the time out. - - EFI_TIMEOUT - DRQ bit not clear within the time out. - - - Notes: - Read Status Register will clear interrupt status. ---*/ // TODO: function comment is missing 'Routine Description:' // TODO: function comment is missing 'Arguments:' // TODO: IdeDev - add argument and description to function comment @@ -926,41 +796,34 @@ DRQClear ( return EFI_SUCCESS; } -EFI_STATUS -DRQClear2 ( - IN IDE_BLK_IO_DEV *IdeDev, - IN UINTN TimeoutInMilliSeconds - ) -/*++ - Name: DRQClear2 +/** + This function is used to poll for the DRQ bit clear in the Alternate + Status Register. DRQ is cleared when the device is finished + transferring data. So this function is called after data transfer + is finished. + @param[in] *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. - Purpose: - This function is used to poll for the DRQ bit clear in the Alternate - Status Register. DRQ is cleared when the device is finished - transferring data. So this function is called after data transfer - is finished. + @param[in] TimeoutInMilliSeconds + used to designate the timeout for the DRQ clear. + @retval EFI_SUCCESS + DRQ bit clear within the time out. - Parameters: - IDE_BLK_IO_DEV IN *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. + @retval EFI_TIMEOUT + DRQ bit not clear within the time out. - UINTN IN TimeoutInMilliSeconds - used to designate the timeout for the DRQ clear. + @note + Read Alternate Status Register will not clear interrupt status. - Returns: - EFI_SUCCESS - DRQ bit clear within the time out. - - EFI_TIMEOUT - DRQ bit not clear within the time out. - - - Notes: - Read Alternate Status Register will not clear interrupt status. ---*/ +**/ +EFI_STATUS +DRQClear2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) // TODO: function comment is missing 'Routine Description:' // TODO: function comment is missing 'Arguments:' // TODO: IdeDev - add argument and description to function comment @@ -1007,46 +870,38 @@ DRQClear2 ( return EFI_SUCCESS; } -EFI_STATUS -DRQReady ( - IN IDE_BLK_IO_DEV *IdeDev, - IN UINTN TimeoutInMilliSeconds - ) -/*++ - Name: DRQReady - - - Purpose: - This function is used to poll for the DRQ bit set in the - Status Register. - DRQ is set when the device is ready to transfer data. So this function - is called after the command is sent to the device and before required - data is transferred. - +/** + This function is used to poll for the DRQ bit set in the + Status Register. + DRQ is set when the device is ready to transfer data. So this function + is called after the command is sent to the device and before required + data is transferred. - Parameters: - IDE_BLK_IO_DEV IN *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure,used - to record all the information of the IDE device. + @param[in] IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure,used + to record all the information of the IDE device. - UINTN IN TimeoutInMilliSeconds - used to designate the timeout for the DRQ ready. + @param[in] UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + @retval EFI_SUCCESS + DRQ bit set within the time out. - Returns: - EFI_SUCCESS - DRQ bit set within the time out. + @retval EFI_TIMEOUT + DRQ bit not set within the time out. - EFI_TIMEOUT - DRQ bit not set within the time out. - - EFI_ABORTED - DRQ bit not set caused by the command abort. + @retval EFI_ABORTED + DRQ bit not set caused by the command abort. - Notes: - Read Status Register will clear interrupt status. + @note + Read Status Register will clear interrupt status. ---*/ +**/ +EFI_STATUS +DRQReady ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) // TODO: function comment is missing 'Routine Description:' // TODO: function comment is missing 'Arguments:' // TODO: IdeDev - add argument and description to function comment @@ -1093,43 +948,37 @@ DRQReady ( return EFI_SUCCESS; } -EFI_STATUS -DRQReady2 ( - IN IDE_BLK_IO_DEV *IdeDev, - IN UINTN TimeoutInMilliSeconds - ) -/*++ - Name: DRQReady2 - +/** + This function is used to poll for the DRQ bit set in the + Alternate Status Register. DRQ is set when the device is ready to + transfer data. So this function is called after the command + is sent to the device and before required data is transferred. - Purpose: - This function is used to poll for the DRQ bit set in the - Alternate Status Register. DRQ is set when the device is ready to - transfer data. So this function is called after the command - is sent to the device and before required data is transferred. + @param[in] IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + @param[in] UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. - Parameters: - IDE_BLK_IO_DEV IN *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. + @retval EFI_SUCCESS + DRQ bit set within the time out. - UINTN IN TimeoutInMilliSeconds - used to designate the timeout for the DRQ ready. + @retval EFI_TIMEOUT + DRQ bit not set within the time out. - Returns: - EFI_SUCCESS - DRQ bit set within the time out. + @retval EFI_ABORTED + DRQ bit not set caused by the command abort. - EFI_TIMEOUT - DRQ bit not set within the time out. - - EFI_ABORTED - DRQ bit not set caused by the command abort. + @note + Read Alternate Status Register will not clear interrupt status. - Notes: - Read Alternate Status Register will not clear interrupt status. ---*/ +**/ +EFI_STATUS +DRQReady2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) // TODO: function comment is missing 'Routine Description:' // TODO: function comment is missing 'Arguments:' // TODO: IdeDev - add argument and description to function comment @@ -1176,41 +1025,33 @@ DRQReady2 ( return EFI_SUCCESS; } -EFI_STATUS -WaitForBSYClear ( - IN IDE_BLK_IO_DEV *IdeDev, - IN UINTN TimeoutInMilliSeconds - ) -/*++ - Name: - WaitForBSYClear - +/** + This function is used to poll for the BSY bit clear in the + Status Register. BSY is clear when the device is not busy. + Every command must be sent after device is not busy. - Purpose: - This function is used to poll for the BSY bit clear in the - Status Register. BSY is clear when the device is not busy. - Every command must be sent after device is not busy. + @param[in] IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + @param[in] UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. - Parameters: - IDE_BLK_IO_DEV IN *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. + @retval EFI_SUCCESS + BSY bit clear within the time out. - UINTN IN TimeoutInMilliSeconds - used to designate the timeout for the DRQ ready. + @retval EFI_TIMEOUT + BSY bit not clear within the time out. - Returns: - EFI_SUCCESS - BSY bit clear within the time out. + @note + Read Status Register will clear interrupt status. - EFI_TIMEOUT - BSY bit not clear within the time out. - - - Notes: - Read Status Register will clear interrupt status. ---*/ +**/ +EFI_STATUS +WaitForBSYClear ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) // TODO: function comment is missing 'Routine Description:' // TODO: function comment is missing 'Arguments:' // TODO: IdeDev - add argument and description to function comment @@ -1245,41 +1086,33 @@ WaitForBSYClear ( // // WaitForBSYClear2 // -EFI_STATUS -WaitForBSYClear2 ( - IN IDE_BLK_IO_DEV *IdeDev, - IN UINTN TimeoutInMilliSeconds - ) -/*++ - Name: - WaitForBSYClear2 - - - Purpose: - This function is used to poll for the BSY bit clear in the - Alternate Status Register. BSY is clear when the device is not busy. - Every command must be sent after device is not busy. - +/** + This function is used to poll for the BSY bit clear in the + Alternate Status Register. BSY is clear when the device is not busy. + Every command must be sent after device is not busy. - Parameters: - IDE_BLK_IO_DEV IN *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. + @param[in] IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. - UINTN IN TimeoutInMilliSeconds - used to designate the timeout for the DRQ ready. + @param[in] UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. - Returns: - EFI_SUCCESS - BSY bit clear within the time out. + @retval EFI_SUCCESS + BSY bit clear within the time out. - EFI_TIMEOUT - BSY bit not clear within the time out. + @retval EFI_TIMEOUT + BSY bit not clear within the time out. + @note + Read Alternate Status Register will not clear interrupt status. - Notes: - Read Alternate Status Register will not clear interrupt status. ---*/ +**/ +EFI_STATUS +WaitForBSYClear2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) // TODO: function comment is missing 'Routine Description:' // TODO: function comment is missing 'Arguments:' // TODO: IdeDev - add argument and description to function comment @@ -1311,42 +1144,34 @@ WaitForBSYClear2 ( // // DRDYReady // -EFI_STATUS -DRDYReady ( - IN IDE_BLK_IO_DEV *IdeDev, - IN UINTN DelayInMilliSeconds - ) -/*++ - Name: - DRDYReady - - - Purpose: - This function is used to poll for the DRDY bit set in the - Status Register. DRDY bit is set when the device is ready - to accept command. Most ATA commands must be sent after - DRDY set except the ATAPI Packet Command. +/** + This function is used to poll for the DRDY bit set in the + Status Register. DRDY bit is set when the device is ready + to accept command. Most ATA commands must be sent after + DRDY set except the ATAPI Packet Command. + @param[in] IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. - Parameters: - IDE_BLK_IO_DEV IN *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. + @param[in] UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. - UINTN IN TimeoutInMilliSeconds - used to designate the timeout for the DRQ ready. + @retval EFI_SUCCESS + DRDY bit set within the time out. - Returns: - EFI_SUCCESS - DRDY bit set within the time out. + @retval EFI_TIMEOUT + DRDY bit not set within the time out. - EFI_TIMEOUT - DRDY bit not set within the time out. + @note + Read Status Register will clear interrupt status. - - Notes: - Read Status Register will clear interrupt status. ---*/ +**/ +EFI_STATUS +DRDYReady ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN DelayInMilliSeconds + ) // TODO: function comment is missing 'Routine Description:' // TODO: function comment is missing 'Arguments:' // TODO: IdeDev - add argument and description to function comment @@ -1375,7 +1200,7 @@ DRDYReady ( } } - gBS->Stall (15); + gBS->Stall (30); Delay--; } while (Delay); @@ -1390,42 +1215,34 @@ DRDYReady ( // // DRDYReady2 // -EFI_STATUS -DRDYReady2 ( - IN IDE_BLK_IO_DEV *IdeDev, - IN UINTN DelayInMilliSeconds - ) -/*++ - Name: - DRDYReady2 - - - Purpose: - This function is used to poll for the DRDY bit set in the - Alternate Status Register. DRDY bit is set when the device is ready - to accept command. Most ATA commands must be sent after - DRDY set except the ATAPI Packet Command. - +/** + This function is used to poll for the DRDY bit set in the + Alternate Status Register. DRDY bit is set when the device is ready + to accept command. Most ATA commands must be sent after + DRDY set except the ATAPI Packet Command. - Parameters: - IDE_BLK_IO_DEV IN *IdeDev - pointer pointing to IDE_BLK_IO_DEV data structure, used - to record all the information of the IDE device. + @param[in] IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. - UINTN IN TimeoutInMilliSeconds - used to designate the timeout for the DRQ ready. + @param[in] UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. - Returns: - EFI_SUCCESS - DRDY bit set within the time out. + @retval EFI_SUCCESS + DRDY bit set within the time out. - EFI_TIMEOUT - DRDY bit not set within the time out. + @retval EFI_TIMEOUT + DRDY bit not set within the time out. + @note + Read Alternate Status Register will clear interrupt status. - Notes: - Read Alternate Status Register will clear interrupt status. ---*/ +**/ +EFI_STATUS +DRDYReady2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN DelayInMilliSeconds + ) // TODO: function comment is missing 'Routine Description:' // TODO: function comment is missing 'Arguments:' // TODO: IdeDev - add argument and description to function comment @@ -1469,52 +1286,34 @@ DRDYReady2 ( // // SwapStringChars // +/** + This function is a helper function used to change the char order in a + string. It is designed specially for the PrintAtaModuleName() function. + After the IDE device is detected, the IDE driver gets the device module + name by sending ATA command called ATA Identify Command or ATAPI + Identify Command to the specified IDE device. The module name returned + is a string of ASCII characters: the first character is bit8--bit15 + of the first word, the second character is bit0--bit7 of the first word + and so on. Thus the string can not be print directly before it is + preprocessed by this func to change the order of characters in + each word in the string. + + @param[in] CHAR8 IN *Destination + Indicates the destination string. + + @param[in] CHAR8 IN *Source + Indicates the source string. + + @param[in] UINT8 IN Size + the length of the string + +**/ VOID SwapStringChars ( IN CHAR8 *Destination, IN CHAR8 *Source, IN UINT32 Size ) -/*++ - Name: - SwapStringChars - - - Purpose: - This function is a helper function used to change the char order in a - string. It is designed specially for the PrintAtaModuleName() function. - After the IDE device is detected, the IDE driver gets the device module - name by sending ATA command called ATA Identify Command or ATAPI - Identify Command to the specified IDE device. The module name returned - is a string of ASCII characters: the first character is bit8--bit15 - of the first word, the second character is bit0--bit7 of the first word - and so on. Thus the string can not be print directly before it is - preprocessed by this func to change the order of characters in - each word in the string. - - - Parameters: - CHAR8 IN *Destination - Indicates the destination string. - - CHAR8 IN *Source - Indicates the source string. - - UINT8 IN Size - the length of the string - - - Returns: - none - - Notes: - ---*/ -// TODO: function comment is missing 'Routine Description:' -// TODO: function comment is missing 'Arguments:' -// TODO: Destination - add argument and description to function comment -// TODO: Source - add argument and description to function comment -// TODO: Size - add argument and description to function comment { UINT32 Index; CHAR8 Temp; @@ -1530,26 +1329,16 @@ SwapStringChars ( // // ReleaseIdeResources // +/** + Release resources of an IDE device before stopping it. + + @param[in] *IdeBlkIoDevice Standard IDE device private data structure + +**/ VOID ReleaseIdeResources ( IN IDE_BLK_IO_DEV *IdeBlkIoDevice ) -/*++ -Routing Description: - - Release resources of an IDE device before stopping it. - -Arguments: - - IdeBlkIoDevice -- Standard IDE device private data structure - - -Returns: - - NONE - ----*/ -// TODO: function comment is missing 'Routine Description:' { if (IdeBlkIoDevice == NULL) { return ; @@ -1558,7 +1347,7 @@ Returns: // // Release all the resourses occupied by the IDE_BLK_IO_DEV // - + if (IdeBlkIoDevice->SenseData != NULL) { gBS->FreePool (IdeBlkIoDevice->SenseData); IdeBlkIoDevice->SenseData = NULL; @@ -1592,6 +1381,11 @@ Returns: gBS->FreePool (IdeBlkIoDevice->DevicePath); } + if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) { + gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent); + IdeBlkIoDevice->ExitBootServiceEvent = NULL; + } + gBS->FreePool (IdeBlkIoDevice); IdeBlkIoDevice = NULL; @@ -1601,26 +1395,20 @@ Returns: // // SetDeviceTransferMode // +/** + Set the calculated Best transfer mode to a detected device + + @param[in] *IdeDev Standard IDE device private data structure + @param[in] *TransferMode The device transfer mode to be set + + @return Set transfer mode Command execute status + +**/ EFI_STATUS SetDeviceTransferMode ( IN IDE_BLK_IO_DEV *IdeDev, IN ATA_TRANSFER_MODE *TransferMode ) -/*++ -Routing Description: - - Set the calculated Best transfer mode to a detected device - -Arguments: - - IdeDev -- Standard IDE device private data structure - TransferMode -- The device transfer mode to be set - -Returns: - - Set transfer mode Command execute status - ----*/ // TODO: function comment is missing 'Routine Description:' { EFI_STATUS Status; @@ -1648,6 +1436,23 @@ Returns: return Status; } +/** + Send ATA 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 LbaLow The value in LBA_LOW register + @param LbaMiddle The value in LBA_MIDDLE register + @param LbaHigh The value in LBA_HIGH register + + @retval EFI_SUCCESS Reading succeed + @retval EFI_ABORTED Command failed + @retval EFI_DEVICE_ERROR Device status error + +**/ EFI_STATUS AtaNonDataCommandIn ( IN IDE_BLK_IO_DEV *IdeDev, @@ -1659,30 +1464,6 @@ AtaNonDataCommandIn ( IN UINT8 LbaMiddle, IN UINT8 LbaHigh ) -/*++ - -Routine Description: - - Send ATA command into device with NON_DATA protocol - -Arguments: - - IdeDev - Standard IDE device private data structure - AtaCommand - The ATA command to be sent - Device - The value in Device register - Feature - The value in Feature register - SectorCount - The value in SectorCount register - LbaLow - The value in LBA_LOW register - LbaMiddle - The value in LBA_MIDDLE register - LbaHigh - The value in LBA_HIGH register - -Returns: - - EFI_SUCCESS - Reading succeed - EFI_ABORTED - Command failed - EFI_DEVICE_ERROR - Device status error - ---*/ { EFI_STATUS Status; UINT8 StatusRegister; @@ -1726,8 +1507,14 @@ Returns: // // Wait for command completion + // For ATA_SMART_CMD, we may need more timeout to let device + // adjust internal states. // - Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (AtaCommand == ATA_SMART_CMD) { + Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT); + } else { + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + } if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } @@ -1743,6 +1530,21 @@ Returns: 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_ABORTED Command failed + @retval EFI_DEVICE_ERROR Device status error + +**/ EFI_STATUS AtaNonDataCommandInExt ( IN IDE_BLK_IO_DEV *IdeDev, @@ -1752,28 +1554,6 @@ AtaNonDataCommandInExt ( IN UINT16 SectorCount, IN EFI_LBA LbaAddress ) -/*++ - -Routine Description: - - Send ATA Ext command into device with NON_DATA protocol - -Arguments: - - IdeDev - Standard IDE device private data structure - AtaCommand - The ATA command to be sent - Device - The value in Device register - Feature - The value in Feature register - SectorCount - The value in SectorCount register - LbaAddress - The LBA address in 48-bit mode - -Returns: - - EFI_SUCCESS - Reading succeed - EFI_ABORTED - Command failed - EFI_DEVICE_ERROR - Device status error - ---*/ { EFI_STATUS Status; UINT8 StatusRegister; @@ -1872,26 +1652,20 @@ Returns: // // SetDriveParameters // +/** + Set drive parameters for devices not support PACKETS command + + @param[in] IdeDev Standard IDE device private data structure + @param[in] DriveParameters The device parameters to be set into the disk + + @return SetParameters Command execute status + +**/ EFI_STATUS SetDriveParameters ( IN IDE_BLK_IO_DEV *IdeDev, IN ATA_DRIVE_PARMS *DriveParameters ) -/*++ -Routine Description: - - Set drive parameters for devices not support PACKETS command - -Arguments: - - IdeDev -- Standard IDE device private data structure - DriveParameters -- The device parameters to be set into the disk - -Returns: - - SetParameters Command execute status - ---*/ { EFI_STATUS Status; UINT8 DeviceSelect; @@ -1902,12 +1676,11 @@ Returns: // // Send Init drive parameters // - Status = AtaPioDataIn ( + Status = AtaNonDataCommandIn ( IdeDev, - NULL, - 0, INIT_DRIVE_PARAM_CMD, (UINT8) (DeviceSelect + DriveParameters->Heads), + 0, DriveParameters->Sector, 0, 0, @@ -1917,48 +1690,135 @@ Returns: // // Send Set Multiple parameters // - Status = AtaPioDataIn ( + Status = AtaNonDataCommandIn ( IdeDev, - NULL, - 0, SET_MULTIPLE_MODE_CMD, DeviceSelect, + 0, DriveParameters->MultipleSector, 0, 0, 0 ); - return Status; } +/** + TODO: Add function description + + @param IdeDev TODO: add argument description + + @retval EFI_SUCCESS TODO: Add description for return value + +**/ EFI_STATUS EnableInterrupt ( IN IDE_BLK_IO_DEV *IdeDev ) -/*++ +{ + UINT8 DeviceControl; -Routine Description: + // + // Enable interrupt for DMA operation + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); - TODO: Add function description + return EFI_SUCCESS; +} -Arguments: +/** + Clear pending IDE interrupt before OS loader/kernel take control of the IDE device. - IdeDev - TODO: add argument description + @param[in] Event Pointer to this event + @param[in] Context Event hanlder private data -Returns: +**/ +VOID +EFIAPI +ClearInterrupt ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + UINT64 IoPortForBmis; + UINT8 RegisterValue; + IDE_BLK_IO_DEV *IdeDev; - EFI_SUCCESS - TODO: Add description for return value + // + // Get our context + // + IdeDev = (IDE_BLK_IO_DEV *) Context; ---*/ -{ - UINT8 DeviceControl; + // + // Obtain IDE IO port registers' base addresses + // + Status = ReassignIdeResources (IdeDev); + if (EFI_ERROR (Status)) { + return; + } // - // Enable interrupt for DMA operation + // Check whether interrupt is pending // - DeviceControl = 0; - IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); - return EFI_SUCCESS; + // + // Reset IDE device to force it de-assert interrupt pin + // Note: this will reset all devices on this IDE channel + // + AtaSoftReset (IdeDev); + if (EFI_ERROR (Status)) { + return; + } + + // + // Get base address of IDE Bus Master Status Regsiter + // + if (IdePrimary == IdeDev->Channel) { + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET; + } else { + if (IdeSecondary == IdeDev->Channel) { + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET; + } else { + return; + } + } + // + // 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 + ); + + // + // Select the other device on this channel to ensure this device to release the interrupt pin + // + if (IdeDev->Device == 0) { + RegisterValue = (1 << 4) | 0xe0; + } else { + RegisterValue = (0 << 4) | 0xe0; + } + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + RegisterValue + ); + }