ata.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,343 行 · 第 1/5 页

C
2,343
字号
/*++

Copyright (c) 2004 - 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.             

Module Name:

    ata.c
    
Abstract: 
    
Revision History

    2002-6: Add Atapi6 enhancement, support >120GB hard disk, including
            update - ATAIdentity() func
            update - AtaBlockIoReadBlocks() func
            update - AtaBlockIoWriteBlocks() func
            add    - AtaAtapi6Identify() func
            add    - AtaReadSectorsExt() func
            add    - AtaWriteSectorsExt() func
            add    - AtaPioDataInExt() func
            add    - AtaPioDataOutExt() func
            
--*/

#include "idebus.h"

STATIC
EFI_STATUS
AtaAtapi6Identify (
  IN  IDE_BLK_IO_DEV  *IdeDev
  );

STATIC
VOID
AtaSMARTSupport (
  IN  IDE_BLK_IO_DEV  *IdeDev
  );

EFI_STATUS
AtaReadSectorsExt (
  IN  IDE_BLK_IO_DEV  *IdeDev,
  IN  OUT VOID        *DataBuffer,
  IN  EFI_LBA         StartLba,
  IN  UINTN           NumberOfBlocks
  );

EFI_STATUS
AtaWriteSectorsExt (
  IN  IDE_BLK_IO_DEV  *IdeDev,
  IN  VOID            *DataBuffer,
  IN  EFI_LBA         StartLba,
  IN  UINTN           NumberOfBlocks
  );

EFI_STATUS
AtaPioDataInExt (
  IN  IDE_BLK_IO_DEV  *IdeDev,
  IN  OUT VOID        *Buffer,
  IN  UINT32          ByteCount,
  IN  UINT8           AtaCommand,
  IN  EFI_LBA         StartLba,
  IN  UINT16          SectorCount
  );

EFI_STATUS
AtaPioDataOutExt (
  IN  IDE_BLK_IO_DEV  *IdeDev,
  IN  VOID            *Buffer,
  IN  UINT32          ByteCount,
  IN  UINT8           AtaCommand,
  IN  EFI_LBA         StartLba,
  IN  UINT16          SectorCount
  );

EFI_STATUS
ATAIdentify (
  IN  IDE_BLK_IO_DEV  *IdeDev
  )
/*++
  Name:
        ATAIdentify


  Purpose: 
        This function is called by DiscoverIdeDevice() during its device
        identification. It sends out the ATA Identify Command to the 
        specified device. Only ATA device responses to this command. If 
        the command succeeds, it returns the Identify data structure which 
        contains information about the device. This function extracts the 
        information it needs to fill the IDE_BLK_IO_DEV data structure, 
        including device type, media block size, media capacity, and etc.


  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.


  Returns:  
        EFI_SUCCESS
          Identify ATA device successfully.

        EFI_DEVICE_ERROR
          ATA Identify Device Command failed or device is not 
          ATA device.


  Notes:
        parameter IdeDev will be updated in this function.
--*/
// TODO: function comment is missing 'Routine Description:'
// TODO: function comment is missing 'Arguments:'
// TODO:    IdeDev - add argument and description to function comment
{
  EFI_STATUS        Status;
  EFI_IDENTIFY_DATA *AtaIdentifyPointer;
  UINT32            Capacity;
  UINT8             DeviceSelect;

  //
  //  AtaIdentifyPointer is used for accommodating returned IDENTIFY data of
  //  the ATA Identify command
  //
  AtaIdentifyPointer = (EFI_IDENTIFY_DATA *) EfiLibAllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));

  //
  //  use ATA PIO Data In protocol to send ATA Identify command
  //  and receive data from device
  //
  DeviceSelect  = 0;
  DeviceSelect  = (UINT8) ((IdeDev->Device) << 4);
  Status = AtaPioDataIn (
            IdeDev,
            (VOID *) AtaIdentifyPointer,
            sizeof (EFI_IDENTIFY_DATA),
            IDENTIFY_DRIVE_CMD,
            DeviceSelect,
            0,
            0,
            0,
            0
            );
  //
  // If ATA Identify command succeeds, then according to the received
  // IDENTIFY data,
  // identify the device type ( ATA or not ).
  // If ATA device, fill the information in IdeDev.
  // If not ATA device, return IDE_DEVICE_ERROR
  //
  if (!EFI_ERROR (Status)) {

    IdeDev->pIdData = AtaIdentifyPointer;

    //
    // Print ATA Module Name
    //
    PrintAtaModuleName (IdeDev);

    //
    // bit 15 of pAtaIdentify->config is used to identify whether device is
    // ATA device or ATAPI device.
    // if 0, means ATA device; if 1, means ATAPI device.
    //
    if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) {
      //
      // Detect if support S.M.A.R.T. If yes, enable it as default
      //
      AtaSMARTSupport (IdeDev);

      //
      // Check whether this device needs 48-bit addressing (ATAPI-6 ata device)
      //
      Status = AtaAtapi6Identify (IdeDev);
      if (!EFI_ERROR (Status)) {
        //
        // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify()
        //
        return EFI_SUCCESS;
      }
      //
      // This is a hard disk <= 120GB capacity, treat it as normal hard disk
      //
      IdeDev->Type = IdeHardDisk;

      //
      // Block Media Information:
      // Media->LogicalPartition , Media->WriteCaching will be filled
      // in the DiscoverIdeDevcie() function.
      //
      IdeDev->BlkIo.Media->IoAlign        = 4;
      IdeDev->BlkIo.Media->MediaId        = 1;
      IdeDev->BlkIo.Media->RemovableMedia = FALSE;
      IdeDev->BlkIo.Media->MediaPresent   = TRUE;
      IdeDev->BlkIo.Media->ReadOnly       = FALSE;
      IdeDev->BlkIo.Media->BlockSize      = 0x200;

      //
      // Calculate device capacity
      //
      Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) |
                  AtaIdentifyPointer->AtaData.user_addressable_sectors_lo ;
      IdeDev->BlkIo.Media->LastBlock = Capacity - 1;

      return EFI_SUCCESS;

    }
  }

  gBS->FreePool (AtaIdentifyPointer);
  //
  // Make sure the pIdData will not be freed again.
  //
  IdeDev->pIdData = NULL;

  return EFI_DEVICE_ERROR;
}

STATIC
EFI_STATUS
AtaAtapi6Identify (
  IN  IDE_BLK_IO_DEV  *IdeDev
  )
/*++
  Name:
  
        AtaAtapi6Identify

  Purpose: 
  
        This function is called by ATAIdentify() to identity whether this disk
        supports ATA/ATAPI6 48bit addressing, ie support >120G capacity

  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.

  Returns:  
  
        EFI_SUCCESS     - The disk specified by IdeDev is a Atapi6 supported one
                          and 48-bit addressing must be used

        EFI_UNSUPPORTED - The disk dosn't not support Atapi6 or it supports but
                          the capacity is below 120G, 48bit addressing is not 
                          needed
                          
  Notes:

       This function must be called after DEVICE_IDENTITY command has been 
       successfully returned
--*/
// TODO: function comment is missing 'Routine Description:'
// TODO: function comment is missing 'Arguments:'
// TODO:    IdeDev - add argument and description to function comment
{
  UINT8             Index;
  EFI_LBA           TmpLba;
  EFI_LBA           Capacity;
  EFI_IDENTIFY_DATA *Atapi6IdentifyStruct;

  if (IdeDev->pIdData == NULL) {
    return EFI_UNSUPPORTED;
  }

  Atapi6IdentifyStruct = IdeDev->pIdData;

  if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & bit10) == 0) {
    //
    // The device dosn't support 48 bit addressing
    //
    return EFI_UNSUPPORTED;
  }

  //
  // 48 bit address feature set is supported, get maximum capacity
  //
  Capacity = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[0];
  for (Index = 1; Index < 4; Index++) {
    //
    // Lower byte goes first: word[100] is the lowest word, word[103] is highest
    //
    TmpLba = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[Index];
    Capacity |= LShiftU64 (TmpLba, 16 * Index);
  }

  if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {
    //
    // Capacity exceeds 120GB. 48-bit addressing is really needed
    //
    IdeDev->Type = Ide48bitAddressingHardDisk;

    //
    // Fill block media information:Media->LogicalPartition ,
    // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function.
    //
    IdeDev->BlkIo.Media->IoAlign        = 4;
    IdeDev->BlkIo.Media->MediaId        = 1;
    IdeDev->BlkIo.Media->RemovableMedia = FALSE;
    IdeDev->BlkIo.Media->MediaPresent   = TRUE;
    IdeDev->BlkIo.Media->ReadOnly       = FALSE;
    IdeDev->BlkIo.Media->BlockSize      = 0x200;
    IdeDev->BlkIo.Media->LastBlock      = Capacity - 1;

    return EFI_SUCCESS;
  }

  return EFI_UNSUPPORTED;
}

VOID
PrintAtaModuleName (
  IN  IDE_BLK_IO_DEV  *IdeDev
  )
/*++
  Name:
        PrintAtaModuleName


  Purpose: 
        This function is called by ATAIdentify() or ATAPIIdentify()
        to print device's module name. 


  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.

  Returns:  
        no returns.

  Notes:
--*/
// TODO: function comment is missing 'Routine Description:'
// TODO: function comment is missing 'Arguments:'
// TODO:    IdeDev - add argument and description to function comment
{
  if (IdeDev->pIdData == NULL) {
    return ;
  }

  SwapStringChars (IdeDev->ModelName, IdeDev->pIdData->AtaData.ModelName, 40);
  IdeDev->ModelName[40] = 0x00;
}

EFI_STATUS
AtaPioDataIn (
  IN  IDE_BLK_IO_DEV  *IdeDev,
  IN  VOID            *Buffer,
  IN  UINT32          ByteCount,
  IN  UINT8           AtaCommand,
  IN  UINT8           Head,
  IN  UINT8           SectorCount,
  IN  UINT8           SectorNumber,
  IN  UINT8           CylinderLsb,
  IN  UINT8           CylinderMsb
  )
/*++
  Name:
        AtaPioDataIn


  Purpose: 
        This function is used to send out ATA commands conforms to the 
        PIO Data In Protocol.


  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.

        VOID      IN    *Buffer
          buffer contained data transferred from device to host.

        UINT32      IN    ByteCount
          data size in byte unit of the buffer.

        UINT8     IN    AtaCommand
          value of the Command Register

        UINT8     IN    Head
          value of the Head/Device Register

        UINT8     IN    SectorCount
          value of the Sector Count Register

        UINT8     IN    SectorNumber
          value of the Sector Number Register

        UINT8     IN    CylinderLsb
          value of the low byte of the Cylinder Register

        UINT8     IN    CylinderMsb
          value of the high byte of the Cylinder Register


  Returns:  
        EFI_SUCCESS
          send out the ATA command and device send required
          data successfully.

        EFI_DEVICE_ERROR
          command sent failed.
  Notes:
--*/
// TODO: function comment is missing 'Routine Description:'
// TODO: function comment is missing 'Arguments:'
// TODO:    IdeDev - add argument and description to function comment
// TODO:    Buffer - add argument and description to function comment
// TODO:    ByteCount - add argument and description to function comment
// TODO:    AtaCommand - add argument and description to function comment
// TODO:    Head - add argument and description to function comment
// TODO:    SectorCount - add argument and description to function comment
// TODO:    SectorNumber - add argument and description to function comment
// TODO:    CylinderLsb - add argument and description to function comment
// TODO:    CylinderMsb - add argument and description to function comment
{
  UINTN       WordCount;
  UINTN       Increment;
  UINT16      *Buffer16;
  EFI_STATUS  Status;

  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
  if (EFI_ERROR (Status)) {
    return EFI_DEVICE_ERROR;
  }

  //
  //  e0:1110,0000-- bit7 and bit5 are reserved bits.
  //           bit6 set means LBA mode
  //
  IDEWritePortB (
    IdeDev->PciIo,
    IdeDev->IoPort->Head,
    (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)
    );

  //
  // All ATAPI device's ATA commands can be issued regardless of the
  // state of the DRDY
  //
  if (IdeDev->Type == IdeHardDisk) {

    Status = DRDYReady (IdeDev, ATATIMEOUT);
    if (EFI_ERROR (Status)) {
      return EFI_DEVICE_ERROR;
    }
  }
  //
  // set all the command parameters
  // Before write to all the following registers, BSY and DRQ must be 0.
  //
  Status = DRQClear2 (IdeDev, ATATIMEOUT);
  if (EFI_ERROR (Status)) {
    return EFI_DEVICE_ERROR;
  }

  if (AtaCommand == SET_FEATURES_CMD) {
    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);
  }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?