Home | History | Annotate | Download | only in OpalPasswordSmm
      1 /** @file
      2   This driver is used for Opal Password Feature support at IDE mode.
      3 
      4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "OpalPasswordSmm.h"
     16 
     17 /**
     18   Write multiple words of Data to the IDE Data port.
     19   Call the IO abstraction once to do the complete read,
     20   not one word at a time
     21 
     22   @param  Port       IO port to read
     23   @param  Count      No. of UINT16's to read
     24   @param  Buffer     Pointer to the Data Buffer for read
     25 
     26 **/
     27 VOID
     28 EFIAPI
     29 IdeWritePortWMultiple (
     30   IN  UINT16                Port,
     31   IN  UINTN                 Count,
     32   IN  UINT16                *Buffer
     33   )
     34 {
     35   UINTN Index;
     36 
     37   for (Index = 0; Index < Count; Index++) {
     38     IoWrite16 (Port, Buffer[Index]);
     39   }
     40 }
     41 
     42 /**
     43   Reads multiple words of Data from the IDE Data port.
     44   Call the IO abstraction once to do the complete read,
     45   not one word at a time
     46 
     47   @param  Port     IO port to read
     48   @param  Count    Number of UINT16's to read
     49   @param  Buffer   Pointer to the Data Buffer for read
     50 
     51 **/
     52 VOID
     53 EFIAPI
     54 IdeReadPortWMultiple (
     55   IN  UINT16                Port,
     56   IN  UINTN                 Count,
     57   IN  UINT16                *Buffer
     58   )
     59 {
     60   UINTN Index;
     61 
     62   for (Index = 0; Index < Count; Index++) {
     63     Buffer[Count] = IoRead16 (Port);
     64   }
     65 }
     66 
     67 /**
     68   This function is used to analyze the Status Register and print out
     69   some debug information and if there is ERR bit set in the Status
     70   Register, the Error Register's Value is also be parsed and print out.
     71 
     72   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS Data structure.
     73 
     74 **/
     75 VOID
     76 EFIAPI
     77 DumpAllIdeRegisters (
     78   IN     EFI_IDE_REGISTERS        *IdeRegisters
     79   )
     80 {
     81   ASSERT (IdeRegisters != NULL);
     82 
     83   DEBUG_CODE_BEGIN ();
     84   if ((IoRead8 (IdeRegisters->CmdOrStatus) & ATA_STSREG_DWF) != 0) {
     85     DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Write Fault\n", IoRead8 (IdeRegisters->CmdOrStatus)));
     86   }
     87 
     88   if ((IoRead8 (IdeRegisters->CmdOrStatus) & ATA_STSREG_CORR) != 0) {
     89     DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Corrected Data\n", IoRead8 (IdeRegisters->CmdOrStatus)));
     90   }
     91 
     92   if ((IoRead8 (IdeRegisters->CmdOrStatus) & ATA_STSREG_ERR) != 0) {
     93     if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_BBK) != 0) {
     94       DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Bad Block Detected\n", IoRead8 (IdeRegisters->ErrOrFeature)));
     95     }
     96 
     97     if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_UNC) != 0) {
     98       DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Uncorrectable Data\n", IoRead8 (IdeRegisters->ErrOrFeature)));
     99     }
    100 
    101     if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_MC) != 0) {
    102       DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Media Change\n", IoRead8 (IdeRegisters->ErrOrFeature)));
    103     }
    104 
    105     if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_ABRT) != 0) {
    106       DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Abort\n", IoRead8 (IdeRegisters->ErrOrFeature)));
    107     }
    108 
    109     if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_TK0NF) != 0) {
    110       DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Track 0 Not Found\n", IoRead8 (IdeRegisters->ErrOrFeature)));
    111     }
    112 
    113     if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_AMNF) != 0) {
    114       DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Address Mark Not Found\n", IoRead8 (IdeRegisters->ErrOrFeature)));
    115     }
    116   }
    117   DEBUG_CODE_END ();
    118 }
    119 
    120 /**
    121   This function is used to analyze the Status Register and print out
    122   some debug information and if there is ERR bit set in the Status
    123   Register, the Error Register's Value is also be parsed and print out.
    124 
    125   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS Data structure.
    126 
    127   @retval EFI_SUCCESS       No err information in the Status Register.
    128   @retval EFI_DEVICE_ERROR  Any err information in the Status Register.
    129 
    130 **/
    131 EFI_STATUS
    132 EFIAPI
    133 CheckStatusRegister (
    134   IN  EFI_IDE_REGISTERS        *IdeRegisters
    135   )
    136 {
    137   EFI_STATUS      Status;
    138   UINT8           StatusRegister;
    139 
    140   ASSERT (IdeRegisters != NULL);
    141 
    142   StatusRegister = IoRead8 (IdeRegisters->CmdOrStatus);
    143 
    144   if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {
    145     Status = EFI_SUCCESS;
    146   } else {
    147     Status = EFI_DEVICE_ERROR;
    148   }
    149 
    150   return Status;
    151 }
    152 
    153 /**
    154   This function is used to poll for the DRQ bit clear in the Status
    155   Register. DRQ is cleared when the device is finished transferring Data.
    156   So this function is called after Data transfer is finished.
    157 
    158   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS Data structure.
    159   @param Timeout          The time to complete the command.
    160 
    161   @retval EFI_SUCCESS     DRQ bit clear within the time out.
    162   @retval EFI_TIMEOUT     DRQ bit not clear within the time out.
    163 
    164   @note
    165   Read Status Register will clear interrupt status.
    166 
    167 **/
    168 EFI_STATUS
    169 EFIAPI
    170 DRQClear (
    171   IN  EFI_IDE_REGISTERS         *IdeRegisters,
    172   IN  UINT64                    Timeout
    173   )
    174 {
    175   UINT32  Delay;
    176   UINT8   StatusRegister;
    177 
    178   ASSERT (IdeRegisters != NULL);
    179 
    180   Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
    181   do {
    182     StatusRegister = IoRead8 (IdeRegisters->CmdOrStatus);
    183 
    184     //
    185     // wait for BSY == 0 and DRQ == 0
    186     //
    187     if ((StatusRegister & ATA_STSREG_BSY) == 0) {
    188 
    189       if ((StatusRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {
    190         return EFI_DEVICE_ERROR;
    191       } else {
    192         return EFI_SUCCESS;
    193       }
    194     }
    195 
    196     //
    197     //  Stall for 100 microseconds.
    198     //
    199     MicroSecondDelay (100);
    200 
    201     Delay--;
    202 
    203   } while (Delay > 0);
    204 
    205     return EFI_TIMEOUT;
    206 }
    207 /**
    208   This function is used to poll for the DRQ bit clear in the Alternate
    209   Status Register. DRQ is cleared when the device is finished
    210   transferring Data. So this function is called after Data transfer
    211   is finished.
    212 
    213   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS Data structure.
    214   @param Timeout          The time to complete the command.
    215 
    216   @retval EFI_SUCCESS     DRQ bit clear within the time out.
    217 
    218   @retval EFI_TIMEOUT     DRQ bit not clear within the time out.
    219   @note   Read Alternate Status Register will not clear interrupt status.
    220 
    221 **/
    222 EFI_STATUS
    223 EFIAPI
    224 DRQClear2 (
    225   IN  EFI_IDE_REGISTERS    *IdeRegisters,
    226   IN  UINT64               Timeout
    227   )
    228 {
    229   UINT32  Delay;
    230   UINT8   AltRegister;
    231 
    232   ASSERT (IdeRegisters != NULL);
    233 
    234   Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
    235   do {
    236     AltRegister = IoRead8 (IdeRegisters->AltOrDev);
    237 
    238     //
    239     //  wait for BSY == 0 and DRQ == 0
    240     //
    241     if ((AltRegister & ATA_STSREG_BSY) == 0) {
    242       if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {
    243         return EFI_DEVICE_ERROR;
    244       } else {
    245         return EFI_SUCCESS;
    246       }
    247     }
    248 
    249     //
    250     // Stall for 100 microseconds.
    251     //
    252     MicroSecondDelay (100);
    253 
    254     Delay--;
    255 
    256   } while (Delay > 0);
    257 
    258   return EFI_TIMEOUT;
    259 }
    260 
    261 
    262 /**
    263   This function is used to poll for the DRQ bit set in the Alternate Status Register.
    264   DRQ is set when the device is ready to transfer Data. So this function is called after
    265   the command is sent to the device and before required Data is transferred.
    266 
    267   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS Data structure.
    268   @param Timeout          The time to complete the command.
    269 
    270   @retval EFI_SUCCESS     DRQ bit set within the time out.
    271   @retval EFI_TIMEOUT     DRQ bit not set within the time out.
    272   @retval EFI_ABORTED     DRQ bit not set caused by the command abort.
    273   @note  Read Alternate Status Register will not clear interrupt status.
    274 
    275 **/
    276 EFI_STATUS
    277 EFIAPI
    278 DRQReady2 (
    279   IN  EFI_IDE_REGISTERS    *IdeRegisters,
    280   IN  UINT64               Timeout
    281   )
    282 {
    283   UINT32  Delay;
    284   UINT8   AltRegister;
    285   UINT8   ErrorRegister;
    286 
    287   ASSERT (IdeRegisters != NULL);
    288 
    289   Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
    290 
    291   do {
    292     //
    293     //  Read Alternate Status Register will not clear interrupt status
    294     //
    295     AltRegister = IoRead8 (IdeRegisters->AltOrDev);
    296     //
    297     // BSY == 0 , DRQ == 1
    298     //
    299     if ((AltRegister & ATA_STSREG_BSY) == 0) {
    300       if ((AltRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
    301         ErrorRegister = IoRead8 (IdeRegisters->ErrOrFeature);
    302 
    303         if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
    304           return EFI_ABORTED;
    305         }
    306         return EFI_DEVICE_ERROR;
    307       }
    308 
    309       if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {
    310         return EFI_SUCCESS;
    311       } else {
    312         return EFI_NOT_READY;
    313       }
    314     }
    315 
    316     //
    317     // Stall for 100 microseconds.
    318     //
    319     MicroSecondDelay (100);
    320 
    321     Delay--;
    322   } while (Delay > 0);
    323 
    324   return EFI_TIMEOUT;
    325 }
    326 
    327 /**
    328   This function is used to poll for the BSY bit clear in the Status Register. BSY
    329   is clear when the device is not busy. Every command must be sent after device is not busy.
    330 
    331   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS Data structure.
    332   @param Timeout          The time to complete the command.
    333 
    334   @retval EFI_SUCCESS     BSY bit clear within the time out.
    335   @retval EFI_TIMEOUT     BSY bit not clear within the time out.
    336 
    337   @note Read Status Register will clear interrupt status.
    338 **/
    339 EFI_STATUS
    340 EFIAPI
    341 WaitForBSYClear (
    342   IN  EFI_IDE_REGISTERS    *IdeRegisters,
    343   IN  UINT64               Timeout
    344   )
    345 {
    346   UINT32  Delay;
    347   UINT8   StatusRegister;
    348 
    349   ASSERT (IdeRegisters != NULL);
    350 
    351   Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
    352   do {
    353     StatusRegister = IoRead8 (IdeRegisters->CmdOrStatus);
    354 
    355     if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {
    356       return EFI_SUCCESS;
    357     }
    358 
    359     //
    360     // Stall for 100 microseconds.
    361     //
    362     MicroSecondDelay (100);
    363 
    364     Delay--;
    365 
    366   } while (Delay > 0);
    367 
    368   return EFI_TIMEOUT;
    369 }
    370 
    371 /**
    372   Get IDE i/o port registers' base addresses by mode.
    373 
    374   In 'Compatibility' mode, use fixed addresses.
    375   In Native-PCI mode, get base addresses from BARs in the PCI IDE controller's
    376   Configuration Space.
    377 
    378   The steps to get IDE i/o port registers' base addresses for each channel
    379   as follows:
    380 
    381   1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
    382   controller's Configuration Space to determine the operating mode.
    383 
    384   2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
    385    ___________________________________________
    386   |           | Command Block | Control Block |
    387   |  Channel  |   Registers   |   Registers   |
    388   |___________|_______________|_______________|
    389   |  Primary  |  1F0h - 1F7h  |  3F6h - 3F7h  |
    390   |___________|_______________|_______________|
    391   | Secondary |  170h - 177h  |  376h - 377h  |
    392   |___________|_______________|_______________|
    393 
    394   Table 1. Compatibility resource mappings
    395 
    396   b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
    397   in IDE controller's PCI Configuration Space, shown in the Table 2 below.
    398    ___________________________________________________
    399   |           |   Command Block   |   Control Block   |
    400   |  Channel  |     Registers     |     Registers     |
    401   |___________|___________________|___________________|
    402   |  Primary  | BAR at offset 0x10| BAR at offset 0x14|
    403   |___________|___________________|___________________|
    404   | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
    405   |___________|___________________|___________________|
    406 
    407   Table 2. BARs for Register Mapping
    408 
    409   @param[in] Bus                 The bus number of ata host controller.
    410   @param[in] Device              The device number of ata host controller.
    411   @param[in] Function            The function number of ata host controller.
    412   @param[in, out] IdeRegisters   Pointer to EFI_IDE_REGISTERS which is used to
    413                                  store the IDE i/o port registers' base addresses
    414 
    415   @retval EFI_UNSUPPORTED        Return this Value when the BARs is not IO type
    416   @retval EFI_SUCCESS            Get the Base address successfully
    417   @retval Other                  Read the pci configureation Data error
    418 
    419 **/
    420 EFI_STATUS
    421 EFIAPI
    422 GetIdeRegisterIoAddr (
    423   IN     UINTN                       Bus,
    424   IN     UINTN                       Device,
    425   IN     UINTN                       Function,
    426   IN OUT EFI_IDE_REGISTERS           *IdeRegisters
    427   )
    428 {
    429   UINT16            CommandBlockBaseAddr;
    430   UINT16            ControlBlockBaseAddr;
    431   UINT8             ClassCode;
    432   UINT32            BaseAddress[4];
    433 
    434   if (IdeRegisters == NULL) {
    435     return EFI_INVALID_PARAMETER;
    436   }
    437 
    438   ClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x9));
    439   BaseAddress[0] = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x10));
    440   BaseAddress[1] = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x14));
    441   BaseAddress[2] = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x18));
    442   BaseAddress[3] = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x1C));
    443 
    444   if ((ClassCode & IDE_PRIMARY_OPERATING_MODE) == 0) {
    445     CommandBlockBaseAddr = 0x1f0;
    446     ControlBlockBaseAddr = 0x3f6;
    447   } else {
    448     //
    449     // The BARs should be of IO type
    450     //
    451     if ((BaseAddress[0] & BIT0) == 0 ||
    452         (BaseAddress[1] & BIT0) == 0) {
    453       return EFI_UNSUPPORTED;
    454     }
    455 
    456     CommandBlockBaseAddr = (UINT16) (BaseAddress[0] & 0x0000fff8);
    457     ControlBlockBaseAddr = (UINT16) ((BaseAddress[1] & 0x0000fffc) + 2);
    458   }
    459 
    460   //
    461   // Calculate IDE primary channel I/O register base address.
    462   //
    463   IdeRegisters[EfiIdePrimary].Data              = CommandBlockBaseAddr;
    464   IdeRegisters[EfiIdePrimary].ErrOrFeature      = (UINT16) (CommandBlockBaseAddr + 0x01);
    465   IdeRegisters[EfiIdePrimary].SectorCount       = (UINT16) (CommandBlockBaseAddr + 0x02);
    466   IdeRegisters[EfiIdePrimary].SectorNumber      = (UINT16) (CommandBlockBaseAddr + 0x03);
    467   IdeRegisters[EfiIdePrimary].CylinderLsb       = (UINT16) (CommandBlockBaseAddr + 0x04);
    468   IdeRegisters[EfiIdePrimary].CylinderMsb       = (UINT16) (CommandBlockBaseAddr + 0x05);
    469   IdeRegisters[EfiIdePrimary].Head              = (UINT16) (CommandBlockBaseAddr + 0x06);
    470   IdeRegisters[EfiIdePrimary].CmdOrStatus       = (UINT16) (CommandBlockBaseAddr + 0x07);
    471   IdeRegisters[EfiIdePrimary].AltOrDev          = ControlBlockBaseAddr;
    472 
    473   if ((ClassCode & IDE_SECONDARY_OPERATING_MODE) == 0) {
    474     CommandBlockBaseAddr = 0x170;
    475     ControlBlockBaseAddr = 0x376;
    476   } else {
    477     //
    478     // The BARs should be of IO type
    479     //
    480     if ((BaseAddress[2] & BIT0) == 0 ||
    481         (BaseAddress[3] & BIT0) == 0) {
    482       return EFI_UNSUPPORTED;
    483     }
    484 
    485     CommandBlockBaseAddr = (UINT16) (BaseAddress[2] & 0x0000fff8);
    486     ControlBlockBaseAddr = (UINT16) ((BaseAddress[3] & 0x0000fffc) + 2);
    487   }
    488 
    489   //
    490   // Calculate IDE secondary channel I/O register base address.
    491   //
    492   IdeRegisters[EfiIdeSecondary].Data              = CommandBlockBaseAddr;
    493   IdeRegisters[EfiIdeSecondary].ErrOrFeature      = (UINT16) (CommandBlockBaseAddr + 0x01);
    494   IdeRegisters[EfiIdeSecondary].SectorCount       = (UINT16) (CommandBlockBaseAddr + 0x02);
    495   IdeRegisters[EfiIdeSecondary].SectorNumber      = (UINT16) (CommandBlockBaseAddr + 0x03);
    496   IdeRegisters[EfiIdeSecondary].CylinderLsb       = (UINT16) (CommandBlockBaseAddr + 0x04);
    497   IdeRegisters[EfiIdeSecondary].CylinderMsb       = (UINT16) (CommandBlockBaseAddr + 0x05);
    498   IdeRegisters[EfiIdeSecondary].Head              = (UINT16) (CommandBlockBaseAddr + 0x06);
    499   IdeRegisters[EfiIdeSecondary].CmdOrStatus       = (UINT16) (CommandBlockBaseAddr + 0x07);
    500   IdeRegisters[EfiIdeSecondary].AltOrDev          = ControlBlockBaseAddr;
    501 
    502   return EFI_SUCCESS;
    503 }
    504 
    505 /**
    506   Send ATA Ext command into device with NON_DATA protocol.
    507 
    508   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS Data structure.
    509   @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK Data structure.
    510   @param Timeout          The time to complete the command.
    511 
    512   @retval  EFI_SUCCESS Reading succeed
    513   @retval  EFI_DEVICE_ERROR Error executing commands on this device.
    514 
    515 **/
    516 EFI_STATUS
    517 EFIAPI
    518 AtaIssueCommand (
    519   IN  EFI_IDE_REGISTERS         *IdeRegisters,
    520   IN  EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,
    521   IN  UINT64                    Timeout
    522   )
    523 {
    524   EFI_STATUS  Status;
    525   UINT8       DeviceHead;
    526   UINT8       AtaCommand;
    527 
    528   ASSERT (IdeRegisters != NULL);
    529   ASSERT (AtaCommandBlock != NULL);
    530 
    531   DeviceHead = AtaCommandBlock->AtaDeviceHead;
    532   AtaCommand = AtaCommandBlock->AtaCommand;
    533 
    534   Status = WaitForBSYClear (IdeRegisters, Timeout);
    535   if (EFI_ERROR (Status)) {
    536     return EFI_DEVICE_ERROR;
    537   }
    538 
    539   //
    540   // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
    541   //
    542   IoWrite8 (IdeRegisters->Head, (UINT8) (0xe0 | DeviceHead));
    543 
    544   //
    545   // set all the command parameters
    546   // Before write to all the following registers, BSY and DRQ must be 0.
    547   //
    548   Status = DRQClear2 (IdeRegisters, Timeout);
    549   if (EFI_ERROR (Status)) {
    550     return EFI_DEVICE_ERROR;
    551   }
    552 
    553   //
    554   // Fill the feature register, which is a two-byte FIFO. Need write twice.
    555   //
    556   IoWrite8 (IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeaturesExp);
    557   IoWrite8 (IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeatures);
    558 
    559   //
    560   // Fill the sector count register, which is a two-byte FIFO. Need write twice.
    561   //
    562   IoWrite8 (IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCountExp);
    563   IoWrite8 (IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCount);
    564 
    565   //
    566   // Fill the start LBA registers, which are also two-byte FIFO
    567   //
    568   IoWrite8 (IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumberExp);
    569   IoWrite8 (IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumber);
    570 
    571   IoWrite8 (IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLowExp);
    572   IoWrite8 (IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLow);
    573 
    574   IoWrite8 (IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHighExp);
    575   IoWrite8 (IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHigh);
    576 
    577   //
    578   // Send command via Command Register
    579   //
    580   IoWrite8 (IdeRegisters->CmdOrStatus, AtaCommand);
    581 
    582   //
    583   // Stall at least 400 microseconds.
    584   //
    585   MicroSecondDelay (400);
    586 
    587   return EFI_SUCCESS;
    588 }
    589 
    590 /**
    591   This function is used to send out ATA commands conforms to the PIO Data In Protocol.
    592 
    593   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS Data structure.
    594   @param Buffer           A pointer to the source Buffer for the Data.
    595   @param ByteCount        The Length of  the Data.
    596   @param Read             Flag used to determine the Data transfer direction.
    597                           Read equals 1, means Data transferred from device to host;
    598                           Read equals 0, means Data transferred from host to device.
    599   @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK Data structure.
    600   @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK Data structure.
    601   @param Timeout          The time to complete the command.
    602 
    603   @retval EFI_SUCCESS      send out the ATA command and device send required Data successfully.
    604   @retval EFI_DEVICE_ERROR command sent failed.
    605 
    606 **/
    607 EFI_STATUS
    608 EFIAPI
    609 AtaPioDataInOut (
    610   IN     EFI_IDE_REGISTERS         *IdeRegisters,
    611   IN OUT VOID                      *Buffer,
    612   IN     UINT64                    ByteCount,
    613   IN     BOOLEAN                   Read,
    614   IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,
    615   IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,
    616   IN     UINT64                    Timeout
    617   )
    618 {
    619   UINTN       WordCount;
    620   UINTN       Increment;
    621   UINT16      *Buffer16;
    622   EFI_STATUS  Status;
    623 
    624   if ((IdeRegisters == NULL) || (Buffer == NULL) || (AtaCommandBlock == NULL)) {
    625     return EFI_INVALID_PARAMETER;
    626   }
    627 
    628   //
    629   // Issue ATA command
    630   //
    631   Status = AtaIssueCommand (IdeRegisters, AtaCommandBlock, Timeout);
    632   if (EFI_ERROR (Status)) {
    633     Status = EFI_DEVICE_ERROR;
    634     goto Exit;
    635   }
    636 
    637   Buffer16 = (UINT16 *) Buffer;
    638 
    639   //
    640   // According to PIO Data in protocol, host can perform a series of reads to
    641   // the Data register after each time device set DRQ ready;
    642   // The Data Size of "a series of read" is command specific.
    643   // For most ATA command, Data Size received from device will not exceed
    644   // 1 sector, hence the Data Size for "a series of read" can be the whole Data
    645   // Size of one command request.
    646   // For ATA command such as Read Sector command, the Data Size of one ATA
    647   // command request is often larger than 1 sector, according to the
    648   // Read Sector command, the Data Size of "a series of read" is exactly 1
    649   // sector.
    650   // Here for simplification reason, we specify the Data Size for
    651   // "a series of read" to 1 sector (256 words) if Data Size of one ATA command
    652   // request is larger than 256 words.
    653   //
    654   Increment = 256;
    655 
    656   //
    657   // used to record bytes of currently transfered Data
    658   //
    659   WordCount = 0;
    660 
    661   while (WordCount < RShiftU64(ByteCount, 1)) {
    662     //
    663     // Poll DRQ bit set, Data transfer can be performed only when DRQ is ready
    664     //
    665     Status = DRQReady2 (IdeRegisters, Timeout);
    666     if (EFI_ERROR (Status)) {
    667       Status = EFI_DEVICE_ERROR;
    668       goto Exit;
    669     }
    670 
    671     //
    672     // Get the byte count for one series of read
    673     //
    674     if ((WordCount + Increment) > RShiftU64(ByteCount, 1)) {
    675       Increment = (UINTN)(RShiftU64(ByteCount, 1) - WordCount);
    676     }
    677 
    678     if (Read) {
    679       IdeReadPortWMultiple (
    680         IdeRegisters->Data,
    681         Increment,
    682         Buffer16
    683         );
    684     } else {
    685       IdeWritePortWMultiple (
    686         IdeRegisters->Data,
    687         Increment,
    688         Buffer16
    689         );
    690     }
    691 
    692     Status = CheckStatusRegister (IdeRegisters);
    693     if (EFI_ERROR (Status)) {
    694       Status = EFI_DEVICE_ERROR;
    695       goto Exit;
    696     }
    697 
    698     WordCount += Increment;
    699     Buffer16  += Increment;
    700   }
    701 
    702   Status = DRQClear (IdeRegisters, Timeout);
    703   if (EFI_ERROR (Status)) {
    704     Status = EFI_DEVICE_ERROR;
    705     goto Exit;
    706   }
    707 
    708 Exit:
    709   //
    710   // Dump All Ide registers to ATA_STATUS_BLOCK
    711   //
    712   DumpAllIdeRegisters (IdeRegisters);
    713 
    714   return Status;
    715 }
    716 
    717 /**
    718   Sends out an ATA Identify Command to the specified device.
    719 
    720   This function sends out the ATA Identify Command to the
    721   specified device. Only ATA device responses to this command. If
    722   the command succeeds, it returns the Identify Data structure which
    723   contains information about the device. This function extracts the
    724   information it needs to fill the IDE_BLK_IO_DEV Data structure,
    725   including device type, media block Size, media capacity, and etc.
    726 
    727   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS Data structure.
    728   @param Channel          The channel number of device.
    729   @param Device           The device number of device.
    730   @param Buffer           A pointer to Data Buffer which is used to contain IDENTIFY Data.
    731 
    732   @retval EFI_SUCCESS          Identify ATA device successfully.
    733   @retval EFI_DEVICE_ERROR     ATA Identify Device Command failed or device is not ATA device.
    734   @retval EFI_OUT_OF_RESOURCES Allocate memory failed.
    735 **/
    736 EFI_STATUS
    737 EFIAPI
    738 AtaIdentify (
    739   IN     EFI_IDE_REGISTERS             *IdeRegisters,
    740   IN     UINT8                         Channel,
    741   IN     UINT8                         Device,
    742   IN OUT ATA_IDENTIFY_DATA             *Buffer
    743   )
    744 {
    745   EFI_STATUS             Status;
    746   EFI_ATA_COMMAND_BLOCK  AtaCommandBlock;
    747 
    748   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
    749 
    750   AtaCommandBlock.AtaCommand    = ATA_CMD_IDENTIFY_DRIVE;
    751   AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);
    752 
    753   Status = AtaPioDataInOut (
    754              IdeRegisters,
    755              Buffer,
    756              sizeof (ATA_IDENTIFY_DATA),
    757              TRUE,
    758              &AtaCommandBlock,
    759              NULL,
    760              ATA_TIMEOUT
    761              );
    762 
    763   return Status;
    764 }
    765 
    766 
    767 
    768