mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 12:54:17 +00:00 
			
		
		
		
	In function ReadCapacity(), the following expression: MediaInfo->LastBlock = (Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0; (There is also a similar case in this function.) will involve undefined behavior in signed left shift operations. Since Data.LastLbaX is of type UINT8, and MediaInfo->LastBlock is of type UINTN. Therefore, Data.LastLbaX will be promoted to int (32 bits, signed) first, and then perform the left shift operation. According to the C11 spec, Section 6.5.7: 4 The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 * 2^E2 , reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 * 2^E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined. So if bit 7 of Data.LastLba3 is 1, (Data.LastLba3 << 24) will be out of the range within int type. The undefined behavior of the signed left shift will lead to a potential of setting the high 32 bits of MediaInfo->LastBlock to 1 during the cast from type int to type UINT64 for X64 builds. This commit will add an explicit UINT32 type cast for Data.LastLba3 to resolve this issue. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Feng Tian <feng.tian@intel.com>
		
			
				
	
	
		
			2502 lines
		
	
	
		
			76 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2502 lines
		
	
	
		
			76 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
PEIM to produce gEfiPeiVirtualBlockIoPpiGuid & gEfiPeiVirtualBlockIo2PpiGuid PPI for
 | 
						|
ATA controllers in the platform.
 | 
						|
 | 
						|
This PPI can be consumed by PEIM which produce gEfiPeiDeviceRecoveryModulePpiGuid
 | 
						|
for Atapi CD ROM device.
 | 
						|
 | 
						|
Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
 | 
						|
 | 
						|
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.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "AtapiPeim.h"
 | 
						|
 | 
						|
/**
 | 
						|
  Initializes the Atapi Block Io PPI.  
 | 
						|
  
 | 
						|
  @param[in]  FileHandle           Handle of the file being invoked.
 | 
						|
  @param[in]  PeiServices          Describes the list of possible PEI Services.
 | 
						|
 | 
						|
  @retval     EFI_SUCCESS          Operation performed successfully.
 | 
						|
  @retval     EFI_OUT_OF_RESOURCES Not enough memory to allocate.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
AtapiPeimEntry (
 | 
						|
  IN EFI_PEI_FILE_HANDLE        FileHandle,
 | 
						|
  IN CONST EFI_PEI_SERVICES     **PeiServices
 | 
						|
  )
 | 
						|
{
 | 
						|
  PEI_ATA_CONTROLLER_PPI  *AtaControllerPpi;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  ATAPI_BLK_IO_DEV        *AtapiBlkIoDev;
 | 
						|
 | 
						|
  Status = PeiServicesRegisterForShadow (FileHandle);
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = PeiServicesLocatePpi (
 | 
						|
              &gPeiAtaControllerPpiGuid,
 | 
						|
              0,
 | 
						|
              NULL,
 | 
						|
              (VOID **) &AtaControllerPpi
 | 
						|
              );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  AtapiBlkIoDev = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*AtapiBlkIoDev)));
 | 
						|
  if (AtapiBlkIoDev == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  AtapiBlkIoDev->Signature        = ATAPI_BLK_IO_DEV_SIGNATURE;
 | 
						|
  AtapiBlkIoDev->AtaControllerPpi = AtaControllerPpi;
 | 
						|
 | 
						|
  //
 | 
						|
  // atapi device enumeration and build private data
 | 
						|
  //
 | 
						|
  AtapiEnumerateDevices (AtapiBlkIoDev);
 | 
						|
 | 
						|
  AtapiBlkIoDev->AtapiBlkIo.GetNumberOfBlockDevices = AtapiGetNumberOfBlockDevices;
 | 
						|
  AtapiBlkIoDev->AtapiBlkIo.GetBlockDeviceMediaInfo = AtapiGetBlockDeviceMediaInfo;
 | 
						|
  AtapiBlkIoDev->AtapiBlkIo.ReadBlocks              = AtapiReadBlocks;
 | 
						|
  AtapiBlkIoDev->AtapiBlkIo2.Revision                = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;
 | 
						|
  AtapiBlkIoDev->AtapiBlkIo2.GetNumberOfBlockDevices = AtapiGetNumberOfBlockDevices2;
 | 
						|
  AtapiBlkIoDev->AtapiBlkIo2.GetBlockDeviceMediaInfo = AtapiGetBlockDeviceMediaInfo2;
 | 
						|
  AtapiBlkIoDev->AtapiBlkIo2.ReadBlocks              = AtapiReadBlocks2;
 | 
						|
 | 
						|
  AtapiBlkIoDev->PpiDescriptor.Flags                = EFI_PEI_PPI_DESCRIPTOR_PPI;
 | 
						|
  AtapiBlkIoDev->PpiDescriptor.Guid                 = &gEfiPeiVirtualBlockIoPpiGuid;
 | 
						|
  AtapiBlkIoDev->PpiDescriptor.Ppi                  = &AtapiBlkIoDev->AtapiBlkIo;
 | 
						|
 | 
						|
  AtapiBlkIoDev->PpiDescriptor2.Flags                = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
 | 
						|
  AtapiBlkIoDev->PpiDescriptor2.Guid                 = &gEfiPeiVirtualBlockIo2PpiGuid;
 | 
						|
  AtapiBlkIoDev->PpiDescriptor2.Ppi                  = &AtapiBlkIoDev->AtapiBlkIo2;
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "Atatpi Device Count is %d\n", AtapiBlkIoDev->DeviceCount));
 | 
						|
  if (AtapiBlkIoDev->DeviceCount != 0) {
 | 
						|
    Status = PeiServicesInstallPpi (&AtapiBlkIoDev->PpiDescriptor);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Gets the count of block I/O devices that one specific block driver detects.
 | 
						|
 | 
						|
  This function is used for getting the count of block I/O devices that one 
 | 
						|
  specific block driver detects.  To the PEI ATAPI driver, it returns the number
 | 
						|
  of all the detected ATAPI devices it detects during the enumeration process. 
 | 
						|
  To the PEI legacy floppy driver, it returns the number of all the legacy 
 | 
						|
  devices it finds during its enumeration process. If no device is detected, 
 | 
						|
  then the function will return zero.  
 | 
						|
  
 | 
						|
  @param[in]  PeiServices          General-purpose services that are available 
 | 
						|
                                   to every PEIM.
 | 
						|
  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI 
 | 
						|
                                   instance.
 | 
						|
  @param[out] NumberBlockDevices   The number of block I/O devices discovered.
 | 
						|
 | 
						|
  @retval     EFI_SUCCESS          Operation performed successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
AtapiGetNumberOfBlockDevices (
 | 
						|
  IN   EFI_PEI_SERVICES                  **PeiServices,
 | 
						|
  IN   EFI_PEI_RECOVERY_BLOCK_IO_PPI   *This,
 | 
						|
  OUT  UINTN                             *NumberBlockDevices
 | 
						|
  )
 | 
						|
{
 | 
						|
  ATAPI_BLK_IO_DEV  *AtapiBlkIoDev;
 | 
						|
 | 
						|
  AtapiBlkIoDev = NULL;
 | 
						|
 | 
						|
  AtapiBlkIoDev       = PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS (This);
 | 
						|
 | 
						|
  *NumberBlockDevices = AtapiBlkIoDev->DeviceCount;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Gets a block device's media information.
 | 
						|
 | 
						|
  This function will provide the caller with the specified block device's media 
 | 
						|
  information. If the media changes, calling this function will update the media 
 | 
						|
  information accordingly.
 | 
						|
 | 
						|
  @param[in]  PeiServices   General-purpose services that are available to every
 | 
						|
                            PEIM
 | 
						|
  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
 | 
						|
  @param[in]  DeviceIndex   Specifies the block device to which the function wants 
 | 
						|
                            to talk. Because the driver that implements Block I/O 
 | 
						|
                            PPIs will manage multiple block devices, the PPIs that 
 | 
						|
                            want to talk to a single device must specify the 
 | 
						|
                            device index that was assigned during the enumeration
 | 
						|
                            process. This index is a number from one to 
 | 
						|
                            NumberBlockDevices.
 | 
						|
  @param[out] MediaInfo     The media information of the specified block media.  
 | 
						|
                            The caller is responsible for the ownership of this 
 | 
						|
                            data structure.
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS           Media information about the specified block device 
 | 
						|
                                was obtained successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      Cannot get the media information due to a hardware 
 | 
						|
                                error.
 | 
						|
  @retval Others                Other failure occurs.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
AtapiGetBlockDeviceMediaInfo (
 | 
						|
  IN   EFI_PEI_SERVICES                     **PeiServices,
 | 
						|
  IN   EFI_PEI_RECOVERY_BLOCK_IO_PPI        *This,
 | 
						|
  IN   UINTN                                DeviceIndex,
 | 
						|
  OUT  EFI_PEI_BLOCK_IO_MEDIA               *MediaInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN             DeviceCount;
 | 
						|
  ATAPI_BLK_IO_DEV  *AtapiBlkIoDev;
 | 
						|
  EFI_STATUS        Status;
 | 
						|
  UINTN             Index;
 | 
						|
 | 
						|
  AtapiBlkIoDev = NULL;
 | 
						|
 | 
						|
  if (This == NULL || MediaInfo == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS (This);
 | 
						|
 | 
						|
  DeviceCount   = AtapiBlkIoDev->DeviceCount;
 | 
						|
 | 
						|
  //
 | 
						|
  // DeviceIndex is a value from 1 to NumberBlockDevices.
 | 
						|
  //
 | 
						|
  if ((DeviceIndex < 1) || (DeviceIndex > DeviceCount) || (DeviceIndex > MAX_IDE_DEVICES)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Index = DeviceIndex - 1;
 | 
						|
 | 
						|
  //
 | 
						|
  // probe media and retrieve latest media information
 | 
						|
  //
 | 
						|
  DEBUG ((EFI_D_INFO, "Atatpi GetInfo DevicePosition is %d\n", AtapiBlkIoDev->DeviceInfo[Index].DevicePosition));  
 | 
						|
  DEBUG ((EFI_D_INFO, "Atatpi GetInfo DeviceType is   %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.DeviceType));
 | 
						|
  DEBUG ((EFI_D_INFO, "Atatpi GetInfo MediaPresent is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.MediaPresent));
 | 
						|
  DEBUG ((EFI_D_INFO, "Atatpi GetInfo BlockSize is  0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.BlockSize));
 | 
						|
  DEBUG ((EFI_D_INFO, "Atatpi GetInfo LastBlock is  0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.LastBlock));
 | 
						|
 | 
						|
  Status = DetectMedia (
 | 
						|
             AtapiBlkIoDev,
 | 
						|
             AtapiBlkIoDev->DeviceInfo[Index].DevicePosition,
 | 
						|
             &AtapiBlkIoDev->DeviceInfo[Index].MediaInfo,
 | 
						|
             &AtapiBlkIoDev->DeviceInfo[Index].MediaInfo2
 | 
						|
             );
 | 
						|
  if (Status != EFI_SUCCESS) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "Atatpi GetInfo DevicePosition is %d\n", AtapiBlkIoDev->DeviceInfo[Index].DevicePosition));
 | 
						|
  DEBUG ((EFI_D_INFO, "Atatpi GetInfo DeviceType is   %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.DeviceType));
 | 
						|
  DEBUG ((EFI_D_INFO, "Atatpi GetInfo MediaPresent is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.MediaPresent));
 | 
						|
  DEBUG ((EFI_D_INFO, "Atatpi GetInfo BlockSize is  0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.BlockSize));
 | 
						|
  DEBUG ((EFI_D_INFO, "Atatpi GetInfo LastBlock is  0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.LastBlock));
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Get media info from AtapiBlkIoDev
 | 
						|
  //
 | 
						|
  CopyMem (MediaInfo, &AtapiBlkIoDev->DeviceInfo[Index].MediaInfo, sizeof(EFI_PEI_BLOCK_IO_MEDIA));
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Reads the requested number of blocks from the specified block device.
 | 
						|
 | 
						|
  The function reads the requested number of blocks from the device. All the 
 | 
						|
  blocks are read, or an error is returned. If there is no media in the device,
 | 
						|
  the function returns EFI_NO_MEDIA.
 | 
						|
 | 
						|
  @param[in]  PeiServices   General-purpose services that are available to 
 | 
						|
                            every PEIM.
 | 
						|
  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
 | 
						|
  @param[in]  DeviceIndex   Specifies the block device to which the function wants 
 | 
						|
                            to talk. Because the driver that implements Block I/O 
 | 
						|
                            PPIs will manage multiple block devices, the PPIs that 
 | 
						|
                            want to talk to a single device must specify the device 
 | 
						|
                            index that was assigned during the enumeration process. 
 | 
						|
                            This index is a number from one to NumberBlockDevices.
 | 
						|
  @param[in]  StartLBA      The starting logical block address (LBA) to read from
 | 
						|
                            on the device
 | 
						|
  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be
 | 
						|
                            a multiple of the intrinsic block size of the device.
 | 
						|
  @param[out] Buffer        A pointer to the destination buffer for the data.
 | 
						|
                            The caller is responsible for the ownership of the 
 | 
						|
                            buffer.
 | 
						|
                         
 | 
						|
  @retval EFI_SUCCESS             The data was read correctly from the device.
 | 
						|
  @retval EFI_DEVICE_ERROR        The device reported an error while attempting 
 | 
						|
                                  to perform the read operation.
 | 
						|
  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not 
 | 
						|
                                  valid, or the buffer is not properly aligned.
 | 
						|
  @retval EFI_NO_MEDIA            There is no media in the device.
 | 
						|
  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
 | 
						|
                                  the intrinsic block size of the device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
AtapiReadBlocks (
 | 
						|
  IN   EFI_PEI_SERVICES                  **PeiServices,
 | 
						|
  IN   EFI_PEI_RECOVERY_BLOCK_IO_PPI     *This,
 | 
						|
  IN   UINTN                             DeviceIndex,
 | 
						|
  IN   EFI_PEI_LBA                       StartLBA,
 | 
						|
  IN   UINTN                             BufferSize,
 | 
						|
  OUT  VOID                              *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
 | 
						|
  EFI_PEI_BLOCK_IO_MEDIA  MediaInfo;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  UINTN                   NumberOfBlocks;
 | 
						|
  UINTN                   BlockSize;
 | 
						|
  ATAPI_BLK_IO_DEV        *AtapiBlkIoDev;
 | 
						|
 | 
						|
  AtapiBlkIoDev = NULL;
 | 
						|
 | 
						|
  if (This == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS (This);
 | 
						|
 | 
						|
  if (Buffer == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (BufferSize == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = AtapiGetBlockDeviceMediaInfo (
 | 
						|
            PeiServices,
 | 
						|
            This,
 | 
						|
            DeviceIndex,
 | 
						|
            &MediaInfo
 | 
						|
            );
 | 
						|
  if (Status != EFI_SUCCESS) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!MediaInfo.MediaPresent) {
 | 
						|
    return EFI_NO_MEDIA;
 | 
						|
  }
 | 
						|
 | 
						|
  BlockSize = MediaInfo.BlockSize;
 | 
						|
 | 
						|
  if (BufferSize % BlockSize != 0) {
 | 
						|
    return EFI_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  NumberOfBlocks = BufferSize / BlockSize;
 | 
						|
 | 
						|
  if ((StartLBA + NumberOfBlocks - 1) > AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].MediaInfo2.LastBlock) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = ReadSectors (
 | 
						|
            AtapiBlkIoDev,
 | 
						|
            AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].DevicePosition,
 | 
						|
            Buffer,
 | 
						|
            StartLBA,
 | 
						|
            NumberOfBlocks,
 | 
						|
            BlockSize
 | 
						|
            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Gets the count of block I/O devices that one specific block driver detects.
 | 
						|
 | 
						|
  This function is used for getting the count of block I/O devices that one
 | 
						|
  specific block driver detects.  To the PEI ATAPI driver, it returns the number
 | 
						|
  of all the detected ATAPI devices it detects during the enumeration process.
 | 
						|
  To the PEI legacy floppy driver, it returns the number of all the legacy
 | 
						|
  devices it finds during its enumeration process. If no device is detected,
 | 
						|
  then the function will return zero.
 | 
						|
 | 
						|
  @param[in]  PeiServices          General-purpose services that are available
 | 
						|
                                   to every PEIM.
 | 
						|
  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
 | 
						|
                                   instance.
 | 
						|
  @param[out] NumberBlockDevices   The number of block I/O devices discovered.
 | 
						|
 | 
						|
  @retval     EFI_SUCCESS          Operation performed successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
AtapiGetNumberOfBlockDevices2 (
 | 
						|
  IN   EFI_PEI_SERVICES                  **PeiServices,
 | 
						|
  IN   EFI_PEI_RECOVERY_BLOCK_IO2_PPI    *This,
 | 
						|
  OUT  UINTN                             *NumberBlockDevices
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS        Status;
 | 
						|
  ATAPI_BLK_IO_DEV  *AtapiBlkIoDev;
 | 
						|
 | 
						|
  AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO2_THIS (This);
 | 
						|
 | 
						|
  Status = AtapiGetNumberOfBlockDevices (
 | 
						|
             PeiServices,
 | 
						|
             &AtapiBlkIoDev->AtapiBlkIo,
 | 
						|
             NumberBlockDevices
 | 
						|
             );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Gets a block device's media information.
 | 
						|
 | 
						|
  This function will provide the caller with the specified block device's media
 | 
						|
  information. If the media changes, calling this function will update the media
 | 
						|
  information accordingly.
 | 
						|
 | 
						|
  @param[in]  PeiServices   General-purpose services that are available to every
 | 
						|
                            PEIM
 | 
						|
  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
 | 
						|
  @param[in]  DeviceIndex   Specifies the block device to which the function wants
 | 
						|
                            to talk. Because the driver that implements Block I/O
 | 
						|
                            PPIs will manage multiple block devices, the PPIs that
 | 
						|
                            want to talk to a single device must specify the
 | 
						|
                            device index that was assigned during the enumeration
 | 
						|
                            process. This index is a number from one to
 | 
						|
                            NumberBlockDevices.
 | 
						|
  @param[out] MediaInfo     The media information of the specified block media.
 | 
						|
                            The caller is responsible for the ownership of this
 | 
						|
                            data structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Media information about the specified block device
 | 
						|
                                was obtained successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      Cannot get the media information due to a hardware
 | 
						|
                                error.
 | 
						|
  @retval Others                Other failure occurs.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
AtapiGetBlockDeviceMediaInfo2 (
 | 
						|
  IN   EFI_PEI_SERVICES                     **PeiServices,
 | 
						|
  IN   EFI_PEI_RECOVERY_BLOCK_IO2_PPI       *This,
 | 
						|
  IN   UINTN                                DeviceIndex,
 | 
						|
  OUT  EFI_PEI_BLOCK_IO2_MEDIA              *MediaInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  ATAPI_BLK_IO_DEV           *AtapiBlkIoDev;
 | 
						|
  EFI_STATUS                 Status;
 | 
						|
  EFI_PEI_BLOCK_IO_MEDIA     Media;
 | 
						|
 | 
						|
  AtapiBlkIoDev = NULL;
 | 
						|
 | 
						|
  if (This == NULL || MediaInfo == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO2_THIS (This);
 | 
						|
 | 
						|
  Status = AtapiGetBlockDeviceMediaInfo (
 | 
						|
             PeiServices,
 | 
						|
             &AtapiBlkIoDev->AtapiBlkIo,
 | 
						|
             DeviceIndex,
 | 
						|
             &Media
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get media info from AtapiBlkIoDev
 | 
						|
  //
 | 
						|
  CopyMem (MediaInfo, &AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].MediaInfo2, sizeof(EFI_PEI_BLOCK_IO2_MEDIA));
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Reads the requested number of blocks from the specified block device.
 | 
						|
 | 
						|
  The function reads the requested number of blocks from the device. All the
 | 
						|
  blocks are read, or an error is returned. If there is no media in the device,
 | 
						|
  the function returns EFI_NO_MEDIA.
 | 
						|
 | 
						|
  @param[in]  PeiServices   General-purpose services that are available to
 | 
						|
                            every PEIM.
 | 
						|
  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
 | 
						|
  @param[in]  DeviceIndex   Specifies the block device to which the function wants
 | 
						|
                            to talk. Because the driver that implements Block I/O
 | 
						|
                            PPIs will manage multiple block devices, the PPIs that
 | 
						|
                            want to talk to a single device must specify the device
 | 
						|
                            index that was assigned during the enumeration process.
 | 
						|
                            This index is a number from one to NumberBlockDevices.
 | 
						|
  @param[in]  StartLBA      The starting logical block address (LBA) to read from
 | 
						|
                            on the device
 | 
						|
  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be
 | 
						|
                            a multiple of the intrinsic block size of the device.
 | 
						|
  @param[out] Buffer        A pointer to the destination buffer for the data.
 | 
						|
                            The caller is responsible for the ownership of the
 | 
						|
                            buffer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             The data was read correctly from the device.
 | 
						|
  @retval EFI_DEVICE_ERROR        The device reported an error while attempting
 | 
						|
                                  to perform the read operation.
 | 
						|
  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not
 | 
						|
                                  valid, or the buffer is not properly aligned.
 | 
						|
  @retval EFI_NO_MEDIA            There is no media in the device.
 | 
						|
  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
 | 
						|
                                  the intrinsic block size of the device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
AtapiReadBlocks2 (
 | 
						|
  IN   EFI_PEI_SERVICES                  **PeiServices,
 | 
						|
  IN   EFI_PEI_RECOVERY_BLOCK_IO2_PPI    *This,
 | 
						|
  IN   UINTN                             DeviceIndex,
 | 
						|
  IN   EFI_PEI_LBA                       StartLBA,
 | 
						|
  IN   UINTN                             BufferSize,
 | 
						|
  OUT  VOID                              *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  ATAPI_BLK_IO_DEV    *AtapiBlkIoDev;
 | 
						|
 | 
						|
  AtapiBlkIoDev = NULL;
 | 
						|
 | 
						|
  if (This == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO2_THIS (This);
 | 
						|
 | 
						|
  Status = AtapiReadBlocks (
 | 
						|
             PeiServices,
 | 
						|
             &AtapiBlkIoDev->AtapiBlkIo,
 | 
						|
             DeviceIndex,
 | 
						|
             StartLBA,
 | 
						|
             BufferSize,
 | 
						|
             Buffer
 | 
						|
             );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Enumerate Atapi devices.
 | 
						|
 | 
						|
  This function is used to enumerate Atatpi device in Ide channel.
 | 
						|
 | 
						|
  @param[in]  AtapiBlkIoDev  A pointer to atapi block IO device
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
AtapiEnumerateDevices (
 | 
						|
  IN  ATAPI_BLK_IO_DEV  *AtapiBlkIoDev
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                   Index1;
 | 
						|
  UINT8                   Index2;
 | 
						|
  UINTN                   DevicePosition;
 | 
						|
  EFI_PEI_BLOCK_IO_MEDIA  MediaInfo;
 | 
						|
  EFI_PEI_BLOCK_IO2_MEDIA MediaInfo2;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  UINTN                   DeviceCount;
 | 
						|
  UINT16                  CommandBlockBaseAddr;
 | 
						|
  UINT16                  ControlBlockBaseAddr;
 | 
						|
  UINT32                  IdeEnabledNumber;
 | 
						|
  IDE_REGS_BASE_ADDR      IdeRegsBaseAddr[MAX_IDE_CHANNELS];
 | 
						|
 | 
						|
  DeviceCount = 0;
 | 
						|
  DevicePosition = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // Scan IDE bus for ATAPI devices
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // Enable Sata and IDE controller.
 | 
						|
  //
 | 
						|
  AtapiBlkIoDev->AtaControllerPpi->EnableAtaChannel (
 | 
						|
                                  (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(),
 | 
						|
                                  AtapiBlkIoDev->AtaControllerPpi,
 | 
						|
                                  PEI_ICH_IDE_PRIMARY | PEI_ICH_IDE_SECONDARY
 | 
						|
                                  );
 | 
						|
 | 
						|
  //
 | 
						|
  // Allow SATA Devices to spin-up. This is needed if 
 | 
						|
  // SEC and PEI phase is too short, for example Release Build.
 | 
						|
  //
 | 
						|
  DEBUG ((EFI_D_INFO, "Delay for %d seconds for SATA devices to spin-up\n", PcdGet16 (PcdSataSpinUpDelayInSecForRecoveryPath)));
 | 
						|
  MicroSecondDelay (PcdGet16 (PcdSataSpinUpDelayInSecForRecoveryPath) * 1000 * 1000); //
 | 
						|
 | 
						|
  //
 | 
						|
  // Get four channels (primary or secondary Pata, Sata Channel) Command and Control Regs Base address.
 | 
						|
  //
 | 
						|
  IdeEnabledNumber = AtapiBlkIoDev->AtaControllerPpi->GetIdeRegsBaseAddr (
 | 
						|
                                                      (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(),
 | 
						|
                                                      AtapiBlkIoDev->AtaControllerPpi,
 | 
						|
                                                      IdeRegsBaseAddr
 | 
						|
                                                      );
 | 
						|
 | 
						|
  //
 | 
						|
  // Using Command and Control Regs Base Address to fill other registers.
 | 
						|
  //
 | 
						|
  for (Index1 = 0; Index1 < IdeEnabledNumber; Index1 ++) { 
 | 
						|
    CommandBlockBaseAddr               = IdeRegsBaseAddr[Index1].CommandBlockBaseAddr;
 | 
						|
    AtapiBlkIoDev->IdeIoPortReg[Index1].Data         = CommandBlockBaseAddr;
 | 
						|
    AtapiBlkIoDev->IdeIoPortReg[Index1].Reg1.Feature = (UINT16) (CommandBlockBaseAddr + 0x1);
 | 
						|
    AtapiBlkIoDev->IdeIoPortReg[Index1].SectorCount  = (UINT16) (CommandBlockBaseAddr + 0x2);
 | 
						|
    AtapiBlkIoDev->IdeIoPortReg[Index1].SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x3);
 | 
						|
    AtapiBlkIoDev->IdeIoPortReg[Index1].CylinderLsb  = (UINT16) (CommandBlockBaseAddr + 0x4);
 | 
						|
    AtapiBlkIoDev->IdeIoPortReg[Index1].CylinderMsb  = (UINT16) (CommandBlockBaseAddr + 0x5);
 | 
						|
    AtapiBlkIoDev->IdeIoPortReg[Index1].Head         = (UINT16) (CommandBlockBaseAddr + 0x6);
 | 
						|
    AtapiBlkIoDev->IdeIoPortReg[Index1].Reg.Command  = (UINT16) (CommandBlockBaseAddr + 0x7);
 | 
						|
 | 
						|
    ControlBlockBaseAddr                = IdeRegsBaseAddr[Index1].ControlBlockBaseAddr;
 | 
						|
    AtapiBlkIoDev->IdeIoPortReg[Index1].Alt.DeviceControl = ControlBlockBaseAddr;
 | 
						|
    AtapiBlkIoDev->IdeIoPortReg[Index1].DriveAddress      = (UINT16) (ControlBlockBaseAddr + 0x1);
 | 
						|
    
 | 
						|
    //
 | 
						|
    // Scan IDE bus for ATAPI devices IDE or Sata device
 | 
						|
    //
 | 
						|
    for (Index2 = IdeMaster; Index2 < IdeMaxDevice; Index2++) {
 | 
						|
      //
 | 
						|
      // Pata & Sata, Primary & Secondary channel, Master & Slave device
 | 
						|
      //
 | 
						|
      DevicePosition = Index1 * 2 + Index2;
 | 
						|
 | 
						|
      if (DiscoverAtapiDevice (AtapiBlkIoDev, DevicePosition, &MediaInfo, &MediaInfo2)) {
 | 
						|
        //
 | 
						|
        // ATAPI Device at DevicePosition is found.
 | 
						|
        //
 | 
						|
        AtapiBlkIoDev->DeviceInfo[DeviceCount].DevicePosition = DevicePosition;
 | 
						|
        //
 | 
						|
        // Retrieve Media Info
 | 
						|
        //
 | 
						|
        Status  = DetectMedia (AtapiBlkIoDev, DevicePosition, &MediaInfo, &MediaInfo2);
 | 
						|
        CopyMem (&(AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo), &MediaInfo, sizeof (MediaInfo));
 | 
						|
        CopyMem (&(AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2), &MediaInfo2, sizeof (MediaInfo2));
 | 
						|
 | 
						|
        DEBUG ((EFI_D_INFO, "Atatpi Device Position is %d\n", DevicePosition));
 | 
						|
        DEBUG ((EFI_D_INFO, "Atatpi DeviceType is   %d\n", MediaInfo.DeviceType));
 | 
						|
        DEBUG ((EFI_D_INFO, "Atatpi MediaPresent is %d\n", MediaInfo.MediaPresent));
 | 
						|
        DEBUG ((EFI_D_INFO, "Atatpi BlockSize is  0x%x\n", MediaInfo.BlockSize));
 | 
						|
 | 
						|
        if (EFI_ERROR (Status)) {
 | 
						|
          AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo.MediaPresent = FALSE;
 | 
						|
          AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo.LastBlock    = 0;
 | 
						|
          AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2.MediaPresent = FALSE;
 | 
						|
          AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2.LastBlock    = 0;
 | 
						|
        }
 | 
						|
        DeviceCount += 1;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  AtapiBlkIoDev->DeviceCount = DeviceCount;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Detect Atapi devices.
 | 
						|
  
 | 
						|
  @param[in]  AtapiBlkIoDev   A pointer to atapi block IO device.
 | 
						|
  @param[in]  DevicePosition  An integer to signify device position.
 | 
						|
  @param[out] MediaInfo       The media information of the specified block media.
 | 
						|
  @param[out] MediaInfo2      The media information 2 of the specified block media.
 | 
						|
 | 
						|
  @retval TRUE                Atapi device exists in specified position.
 | 
						|
  @retval FALSE               Atapi device does not exist in specified position.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
DiscoverAtapiDevice (
 | 
						|
  IN  ATAPI_BLK_IO_DEV              *AtapiBlkIoDev,
 | 
						|
  IN  UINTN                         DevicePosition,
 | 
						|
  OUT EFI_PEI_BLOCK_IO_MEDIA        *MediaInfo,
 | 
						|
  OUT EFI_PEI_BLOCK_IO2_MEDIA       *MediaInfo2
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if (!DetectIDEController (AtapiBlkIoDev, DevicePosition)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // test if it is an ATAPI device (only supported device)
 | 
						|
  //
 | 
						|
  if (ATAPIIdentify (AtapiBlkIoDev, DevicePosition) == EFI_SUCCESS) {
 | 
						|
 | 
						|
    Status = Inquiry (AtapiBlkIoDev, DevicePosition, MediaInfo, MediaInfo2);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check power mode of Atapi devices.
 | 
						|
  
 | 
						|
  @param[in]  AtapiBlkIoDev   A pointer to atapi block IO device.
 | 
						|
  @param[in]  DevicePosition  An integer to signify device position.
 | 
						|
  @param[in]  AtaCommand      The Ata Command passed in.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS         The Atapi device support power mode.
 | 
						|
  @retval EFI_NOT_FOUND       The Atapi device not found.
 | 
						|
  @retval EFI_TIMEOUT         Atapi command transaction is time out.
 | 
						|
  @retval EFI_ABORTED         Atapi command abort.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CheckPowerMode (
 | 
						|
  IN  ATAPI_BLK_IO_DEV    *AtapiBlkIoDev,
 | 
						|
  IN  UINTN               DevicePosition,
 | 
						|
  IN  UINT8               AtaCommand
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8       Channel;
 | 
						|
  UINT8       Device;
 | 
						|
  UINT16      StatusRegister;
 | 
						|
  UINT16      HeadRegister;
 | 
						|
  UINT16      CommandRegister;
 | 
						|
  UINT16      ErrorRegister;
 | 
						|
  UINT16      SectorCountRegister;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT8       StatusValue;
 | 
						|
  UINT8       ErrorValue;
 | 
						|
  UINT8       SectorCountValue;
 | 
						|
 | 
						|
  Channel             = (UINT8) (DevicePosition / 2);
 | 
						|
  Device              = (UINT8) (DevicePosition % 2);
 | 
						|
 | 
						|
  ASSERT (Channel < MAX_IDE_CHANNELS);
 | 
						|
 | 
						|
  StatusRegister      = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Status;
 | 
						|
  HeadRegister        = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;
 | 
						|
  CommandRegister     = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;
 | 
						|
  ErrorRegister       = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg1.Error;
 | 
						|
  SectorCountRegister = AtapiBlkIoDev->IdeIoPortReg[Channel].SectorCount;
 | 
						|
 | 
						|
  //
 | 
						|
  // select device
 | 
						|
  //
 | 
						|
  IoWrite8 (HeadRegister, (UINT8) ((Device << 4) | 0xe0));
 | 
						|
 | 
						|
  //
 | 
						|
  // refresh the SectorCount register
 | 
						|
  //
 | 
						|
  SectorCountValue = 0x55;
 | 
						|
  IoWrite8 (SectorCountRegister, SectorCountValue);
 | 
						|
 | 
						|
  //
 | 
						|
  // select device
 | 
						|
  //
 | 
						|
  IoWrite8 (HeadRegister, (UINT8) ((Device << 4) | 0xe0));
 | 
						|
 | 
						|
  Status = DRDYReady (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 100);
 | 
						|
 | 
						|
  //
 | 
						|
  // select device
 | 
						|
  //
 | 
						|
  IoWrite8 (HeadRegister, (UINT8) ((Device << 4) | 0xe0));
 | 
						|
  //
 | 
						|
  // send 'check power' commandd via Command Register
 | 
						|
  //
 | 
						|
  IoWrite8 (CommandRegister, AtaCommand);
 | 
						|
 | 
						|
  Status = WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 3000);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_TIMEOUT;
 | 
						|
  }
 | 
						|
 | 
						|
  StatusValue = IoRead8 (StatusRegister);
 | 
						|
 | 
						|
  //
 | 
						|
  // command returned status is DRDY, indicating device supports the command,
 | 
						|
  // so device is present.
 | 
						|
  //
 | 
						|
  if ((StatusValue & ATA_STSREG_DRDY) == ATA_STSREG_DRDY) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  SectorCountValue = IoRead8 (SectorCountRegister);
 | 
						|
 | 
						|
  //
 | 
						|
  // command returned status is ERR & ABRT_ERR, indicating device does not support
 | 
						|
  // the command, so device is present.
 | 
						|
  //
 | 
						|
  if ((StatusValue & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
 | 
						|
    ErrorValue = IoRead8 (ErrorRegister);
 | 
						|
    if ((ErrorValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
 | 
						|
      return EFI_ABORTED;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // According to spec, no other error code is valid
 | 
						|
      //
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ((SectorCountValue == 0x00) || (SectorCountValue == 0x80) || (SectorCountValue == 0xff)) {
 | 
						|
    //
 | 
						|
    // Write SectorCount 0x55 but return valid state value. Maybe no device
 | 
						|
    // exists or some slow kind of ATAPI device exists.
 | 
						|
    //
 | 
						|
    IoWrite8 (HeadRegister, (UINT8) ((Device << 4) | 0xe0));
 | 
						|
 | 
						|
    //
 | 
						|
    // write 0x55 and 0xaa to SectorCounter register,
 | 
						|
    // if the data could be written into the register,
 | 
						|
    // indicating the device is present, otherwise the device is not present.
 | 
						|
    //
 | 
						|
    SectorCountValue = 0x55;
 | 
						|
    IoWrite8 (SectorCountRegister, SectorCountValue);
 | 
						|
    MicroSecondDelay (10000);
 | 
						|
 | 
						|
    SectorCountValue = IoRead8 (SectorCountRegister);
 | 
						|
    if (SectorCountValue != 0x55) {
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Send a "ATAPI TEST UNIT READY" command ... slow but accurate
 | 
						|
    //
 | 
						|
    Status = TestUnitReady (AtapiBlkIoDev, DevicePosition);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Detect if an IDE controller exists in specified position.
 | 
						|
  
 | 
						|
  @param[in]  AtapiBlkIoDev   A pointer to atapi block IO device.
 | 
						|
  @param[in]  DevicePosition  An integer to signify device position.
 | 
						|
 | 
						|
  @retval TRUE         The Atapi device exists.
 | 
						|
  @retval FALSE        The Atapi device does not present.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
DetectIDEController (
 | 
						|
  IN  ATAPI_BLK_IO_DEV   *AtapiBlkIoDev,
 | 
						|
  IN  UINTN              DevicePosition
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8       Channel;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT8       AtaCommand;
 | 
						|
 | 
						|
  Channel           = (UINT8) (DevicePosition / 2);
 | 
						|
 | 
						|
  ASSERT (Channel < MAX_IDE_CHANNELS);
 | 
						|
  //
 | 
						|
  //  Wait 31 seconds for BSY clear
 | 
						|
  //
 | 
						|
  Status = WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 31000);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Send 'check power' command for IDE device
 | 
						|
  //
 | 
						|
  AtaCommand  = 0xE5;
 | 
						|
  Status      = CheckPowerMode (AtapiBlkIoDev, DevicePosition, AtaCommand);
 | 
						|
  if ((Status == EFI_ABORTED) || (Status == EFI_SUCCESS)) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Wait specified time interval to poll for BSY bit clear in the Status Register.
 | 
						|
  
 | 
						|
  @param[in]  AtapiBlkIoDev          A pointer to atapi block IO device.
 | 
						|
  @param[in]  IdeIoRegisters         A pointer to IDE IO registers.
 | 
						|
  @param[in]  TimeoutInMilliSeconds  Time specified in milliseconds.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        BSY bit is cleared in the specified time interval.
 | 
						|
  @retval EFI_TIMEOUT        BSY bit is not cleared in the specified time interval.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
WaitForBSYClear (
 | 
						|
  IN  ATAPI_BLK_IO_DEV    *AtapiBlkIoDev,
 | 
						|
  IN  IDE_BASE_REGISTERS  *IdeIoRegisters,
 | 
						|
  IN  UINTN               TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Delay;
 | 
						|
  UINT16  StatusRegister;
 | 
						|
  UINT8   StatusValue;
 | 
						|
 | 
						|
  StatusValue     = 0;
 | 
						|
 | 
						|
  StatusRegister  = IdeIoRegisters->Reg.Status;
 | 
						|
 | 
						|
  Delay           = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;
 | 
						|
  do {
 | 
						|
    StatusValue = IoRead8 (StatusRegister);
 | 
						|
    if ((StatusValue & ATA_STSREG_BSY) == 0x00) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    MicroSecondDelay (250);
 | 
						|
 | 
						|
    Delay--;
 | 
						|
 | 
						|
  } while (Delay != 0);
 | 
						|
 | 
						|
  if (Delay == 0) {
 | 
						|
    return EFI_TIMEOUT;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Wait specified time interval to poll for DRDY bit set in the Status register.
 | 
						|
  
 | 
						|
  @param[in]  AtapiBlkIoDev          A pointer to atapi block IO device.
 | 
						|
  @param[in]  IdeIoRegisters         A pointer to IDE IO registers.
 | 
						|
  @param[in]  TimeoutInMilliSeconds  Time specified in milliseconds.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        DRDY bit is set in the specified time interval.
 | 
						|
  @retval EFI_TIMEOUT        DRDY bit is not set in the specified time interval.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
DRDYReady (
 | 
						|
  IN  ATAPI_BLK_IO_DEV    *AtapiBlkIoDev,
 | 
						|
  IN  IDE_BASE_REGISTERS  *IdeIoRegisters,
 | 
						|
  IN  UINTN               TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Delay;
 | 
						|
  UINT16  StatusRegister;
 | 
						|
  UINT8   StatusValue;
 | 
						|
  UINT8   ErrValue;
 | 
						|
 | 
						|
  StatusValue     = 0;
 | 
						|
 | 
						|
  StatusRegister  = IdeIoRegisters->Reg.Status;
 | 
						|
 | 
						|
  Delay           = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;
 | 
						|
  do {
 | 
						|
    StatusValue = IoRead8 (StatusRegister);
 | 
						|
    //
 | 
						|
    //  BSY == 0 , DRDY == 1
 | 
						|
    //
 | 
						|
    if ((StatusValue & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  if ((StatusValue & (ATA_STSREG_ERR | ATA_STSREG_BSY)) == ATA_STSREG_ERR) {
 | 
						|
    ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);
 | 
						|
    if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
 | 
						|
    return EFI_ABORTED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
    MicroSecondDelay (250);
 | 
						|
 | 
						|
    Delay--;
 | 
						|
 | 
						|
  } while (Delay != 0);
 | 
						|
 | 
						|
  if (Delay == 0) {
 | 
						|
    return EFI_TIMEOUT;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Wait specified time interval to poll for DRQ bit clear in the Status Register.
 | 
						|
  
 | 
						|
  @param[in]  AtapiBlkIoDev          A pointer to atapi block IO device.
 | 
						|
  @param[in]  IdeIoRegisters         A pointer to IDE IO registers.
 | 
						|
  @param[in]  TimeoutInMilliSeconds  Time specified in milliseconds.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        DRQ bit is cleared in the specified time interval.
 | 
						|
  @retval EFI_TIMEOUT        DRQ bit is not cleared in the specified time interval.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
DRQClear (
 | 
						|
  IN  ATAPI_BLK_IO_DEV    *AtapiBlkIoDev,
 | 
						|
  IN  IDE_BASE_REGISTERS  *IdeIoRegisters,
 | 
						|
  IN  UINTN               TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Delay;
 | 
						|
  UINT16  StatusRegister;
 | 
						|
  UINT8   StatusValue;
 | 
						|
  UINT8   ErrValue;
 | 
						|
 | 
						|
  StatusValue     = 0;
 | 
						|
 | 
						|
  StatusRegister  = IdeIoRegisters->Reg.Status;
 | 
						|
 | 
						|
  Delay           = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;
 | 
						|
  do {
 | 
						|
 | 
						|
    StatusValue = IoRead8 (StatusRegister);
 | 
						|
 | 
						|
    //
 | 
						|
    // wait for BSY == 0 and DRQ == 0
 | 
						|
    //
 | 
						|
    if ((StatusValue & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  if ((StatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
 | 
						|
    ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);
 | 
						|
    if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
 | 
						|
    return EFI_ABORTED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
    MicroSecondDelay (250);
 | 
						|
 | 
						|
    Delay--;
 | 
						|
  } while (Delay != 0);
 | 
						|
 | 
						|
  if (Delay == 0) {
 | 
						|
    return EFI_TIMEOUT;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Wait specified time interval to poll for DRQ bit clear in the Alternate Status Register.
 | 
						|
  
 | 
						|
  @param[in]  AtapiBlkIoDev          A pointer to atapi block IO device.
 | 
						|
  @param[in]  IdeIoRegisters         A pointer to IDE IO registers.
 | 
						|
  @param[in]  TimeoutInMilliSeconds  Time specified in milliseconds.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        DRQ bit is cleared in the specified time interval.
 | 
						|
  @retval EFI_TIMEOUT        DRQ bit is not cleared in the specified time interval.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
DRQClear2 (
 | 
						|
  IN  ATAPI_BLK_IO_DEV    *AtapiBlkIoDev,
 | 
						|
  IN  IDE_BASE_REGISTERS  *IdeIoRegisters,
 | 
						|
  IN  UINTN               TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Delay;
 | 
						|
  UINT16  AltStatusRegister;
 | 
						|
  UINT8   AltStatusValue;
 | 
						|
  UINT8   ErrValue;
 | 
						|
 | 
						|
  AltStatusValue    = 0;
 | 
						|
 | 
						|
  AltStatusRegister = IdeIoRegisters->Alt.AltStatus;
 | 
						|
 | 
						|
  Delay             = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;
 | 
						|
  do {
 | 
						|
 | 
						|
    AltStatusValue = IoRead8 (AltStatusRegister);
 | 
						|
 | 
						|
    //
 | 
						|
    // wait for BSY == 0 and DRQ == 0
 | 
						|
    //
 | 
						|
    if ((AltStatusValue & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  if ((AltStatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
 | 
						|
    ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);
 | 
						|
    if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
 | 
						|
    return EFI_ABORTED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
    MicroSecondDelay (250);
 | 
						|
 | 
						|
    Delay--;
 | 
						|
  } while (Delay != 0);
 | 
						|
 | 
						|
  if (Delay == 0) {
 | 
						|
    return EFI_TIMEOUT;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Wait specified time interval to poll for DRQ bit set in the Status Register.
 | 
						|
 | 
						|
  @param[in]  AtapiBlkIoDev          A pointer to atapi block IO device.
 | 
						|
  @param[in]  IdeIoRegisters         A pointer to IDE IO registers.
 | 
						|
  @param[in]  TimeoutInMilliSeconds  Time specified in milliseconds.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        DRQ bit is set in the specified time interval.
 | 
						|
  @retval EFI_TIMEOUT        DRQ bit is not set in the specified time interval.
 | 
						|
  @retval EFI_ABORTED        Operation Aborted.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
DRQReady (
 | 
						|
  IN  ATAPI_BLK_IO_DEV    *AtapiBlkIoDev,
 | 
						|
  IN  IDE_BASE_REGISTERS  *IdeIoRegisters,
 | 
						|
  IN  UINTN               TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Delay;
 | 
						|
  UINT16  StatusRegister;
 | 
						|
  UINT8   StatusValue;
 | 
						|
  UINT8   ErrValue;
 | 
						|
 | 
						|
  StatusValue     = 0;
 | 
						|
  ErrValue        = 0;
 | 
						|
 | 
						|
  StatusRegister  = IdeIoRegisters->Reg.Status;
 | 
						|
 | 
						|
  Delay           = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;
 | 
						|
  do {
 | 
						|
    //
 | 
						|
    //  read Status Register will clear interrupt
 | 
						|
    //
 | 
						|
    StatusValue = IoRead8 (StatusRegister);
 | 
						|
 | 
						|
    //
 | 
						|
    //  BSY==0,DRQ==1
 | 
						|
    //
 | 
						|
    if ((StatusValue & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((StatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
 | 
						|
 | 
						|
      ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);
 | 
						|
      if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
 | 
						|
        return EFI_ABORTED;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    MicroSecondDelay (250);
 | 
						|
 | 
						|
    Delay--;
 | 
						|
  } while (Delay != 0);
 | 
						|
 | 
						|
  if (Delay == 0) {
 | 
						|
    return EFI_TIMEOUT;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Wait specified time interval to poll for DRQ bit set in the Alternate Status Register.
 | 
						|
 | 
						|
  @param[in]  AtapiBlkIoDev          A pointer to atapi block IO device.
 | 
						|
  @param[in]  IdeIoRegisters         A pointer to IDE IO registers.
 | 
						|
  @param[in]  TimeoutInMilliSeconds  Time specified in milliseconds.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        DRQ bit is set in the specified time interval.
 | 
						|
  @retval EFI_TIMEOUT        DRQ bit is not set in the specified time interval.
 | 
						|
  @retval EFI_ABORTED        Operation Aborted.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
DRQReady2 (
 | 
						|
  IN  ATAPI_BLK_IO_DEV    *AtapiBlkIoDev,
 | 
						|
  IN  IDE_BASE_REGISTERS  *IdeIoRegisters,
 | 
						|
  IN  UINTN               TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Delay;
 | 
						|
  UINT16  AltStatusRegister;
 | 
						|
  UINT8   AltStatusValue;
 | 
						|
  UINT8   ErrValue;
 | 
						|
 | 
						|
  AltStatusValue    = 0;
 | 
						|
 | 
						|
  AltStatusRegister = IdeIoRegisters->Alt.AltStatus;
 | 
						|
 | 
						|
  Delay             = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;
 | 
						|
  do {
 | 
						|
 | 
						|
    AltStatusValue = IoRead8 (AltStatusRegister);
 | 
						|
 | 
						|
    //
 | 
						|
    //  BSY==0,DRQ==1
 | 
						|
    //
 | 
						|
    if ((AltStatusValue & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((AltStatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
 | 
						|
 | 
						|
      ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);
 | 
						|
      if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
 | 
						|
        return EFI_ABORTED;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    MicroSecondDelay (250);
 | 
						|
 | 
						|
    Delay--;
 | 
						|
  } while (Delay != 0);
 | 
						|
 | 
						|
  if (Delay == 0) {
 | 
						|
    return EFI_TIMEOUT;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if there is an error in Status Register.
 | 
						|
 | 
						|
  @param[in]  AtapiBlkIoDev     A pointer to atapi block IO device.
 | 
						|
  @param[in]  StatusReg         The address to IDE IO registers.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        Operation success.
 | 
						|
  @retval EFI_DEVICE_ERROR   Device error.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CheckErrorStatus (
 | 
						|
  IN  ATAPI_BLK_IO_DEV    *AtapiBlkIoDev,
 | 
						|
  IN  UINT16              StatusReg
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8 StatusValue;
 | 
						|
 | 
						|
  StatusValue = IoRead8 (StatusReg);
 | 
						|
 | 
						|
  if ((StatusValue & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {
 | 
						|
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_DEVICE_ERROR;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Idendify Atapi devices.
 | 
						|
 | 
						|
  @param[in]  AtapiBlkIoDev     A pointer to atapi block IO device.
 | 
						|
  @param[in]  DevicePosition    An integer to signify device position.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        Identify successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR   Device cannot be identified successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ATAPIIdentify (
 | 
						|
  IN  ATAPI_BLK_IO_DEV        *AtapiBlkIoDev,
 | 
						|
  IN  UINTN                   DevicePosition
 | 
						|
  )
 | 
						|
{
 | 
						|
  ATAPI_IDENTIFY_DATA  AtapiIdentifyData;
 | 
						|
  UINT8                Channel;
 | 
						|
  UINT8                Device;
 | 
						|
  UINT16               StatusReg;
 | 
						|
  UINT16               HeadReg;
 | 
						|
  UINT16               CommandReg;
 | 
						|
  UINT16               DataReg;
 | 
						|
  UINT16               SectorCountReg;
 | 
						|
  UINT16               SectorNumberReg;
 | 
						|
  UINT16               CylinderLsbReg;
 | 
						|
  UINT16               CylinderMsbReg;
 | 
						|
 | 
						|
  UINT32               WordCount;
 | 
						|
  UINT32               Increment;
 | 
						|
  UINT32               Index;
 | 
						|
  UINT32               ByteCount;
 | 
						|
  UINT16               *Buffer16;
 | 
						|
 | 
						|
  EFI_STATUS           Status;
 | 
						|
 | 
						|
  ByteCount       = sizeof (AtapiIdentifyData);
 | 
						|
  Buffer16        = (UINT16 *) &AtapiIdentifyData;
 | 
						|
 | 
						|
  Channel         = (UINT8) (DevicePosition / 2);
 | 
						|
  Device          = (UINT8) (DevicePosition % 2);
 | 
						|
 | 
						|
  ASSERT (Channel < MAX_IDE_CHANNELS);
 | 
						|
 | 
						|
  StatusReg       = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Status;
 | 
						|
  HeadReg         = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;
 | 
						|
  CommandReg      = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;
 | 
						|
  DataReg         = AtapiBlkIoDev->IdeIoPortReg[Channel].Data;
 | 
						|
  SectorCountReg  = AtapiBlkIoDev->IdeIoPortReg[Channel].SectorCount;
 | 
						|
  SectorNumberReg = AtapiBlkIoDev->IdeIoPortReg[Channel].SectorNumber;
 | 
						|
  CylinderLsbReg  = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderLsb;
 | 
						|
  CylinderMsbReg  = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderMsb;
 | 
						|
 | 
						|
  //
 | 
						|
  // Send ATAPI Identify Command to get IDENTIFY data.
 | 
						|
  //
 | 
						|
  if (WaitForBSYClear (
 | 
						|
        AtapiBlkIoDev,
 | 
						|
        &(AtapiBlkIoDev->IdeIoPortReg[Channel]),
 | 
						|
        ATATIMEOUT
 | 
						|
        ) != EFI_SUCCESS) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // select device via Head/Device register.
 | 
						|
  // Before write Head/Device register, BSY and DRQ must be 0.
 | 
						|
  //
 | 
						|
  if (DRQClear2 (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), ATATIMEOUT) != EFI_SUCCESS) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  //  e0:1110,0000-- bit7 and bit5 are reserved bits.
 | 
						|
  //           bit6 set means LBA mode
 | 
						|
  //
 | 
						|
  IoWrite8 (HeadReg, (UINT8) ((Device << 4) | 0xe0));
 | 
						|
 | 
						|
  //
 | 
						|
  // set all the command parameters
 | 
						|
  // Before write to all the following registers, BSY and DRQ must be 0.
 | 
						|
  //
 | 
						|
  if (DRQClear2 (
 | 
						|
        AtapiBlkIoDev,
 | 
						|
        &(AtapiBlkIoDev->IdeIoPortReg[Channel]),
 | 
						|
        ATATIMEOUT
 | 
						|
        ) != EFI_SUCCESS) {
 | 
						|
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  IoWrite8 (SectorCountReg, 0);
 | 
						|
  IoWrite8 (SectorNumberReg, 0);
 | 
						|
  IoWrite8 (CylinderLsbReg, 0);
 | 
						|
  IoWrite8 (CylinderMsbReg, 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // send command via Command Register
 | 
						|
  //
 | 
						|
  IoWrite8 (CommandReg, ATA_CMD_IDENTIFY_DEVICE);
 | 
						|
 | 
						|
  //
 | 
						|
  // According to PIO data in protocol, host can perform a series of reads to the
 | 
						|
  // data register after each time device set DRQ ready;
 | 
						|
  // The data size of "a series of read" is command specific.
 | 
						|
  // For most ATA command, data size received from device will not exceed 1 sector,
 | 
						|
  // hense the data size for "a series of read" can be the whole data size of one command request.
 | 
						|
  // For ATA command such as Read Sector command, whole data size of one ATA command request is often larger
 | 
						|
  // than 1 sector, according to the Read Sector command, the data size of "a series of read" is exactly
 | 
						|
  // 1 sector.
 | 
						|
  // Here for simplification reason, we specify the data size for "a series of read" to
 | 
						|
  // 1 sector (256 words) if whole data size of one ATA commmand request is larger than 256 words.
 | 
						|
  //
 | 
						|
  Increment = 256;
 | 
						|
  //
 | 
						|
  // 256 words
 | 
						|
  //
 | 
						|
  WordCount = 0;
 | 
						|
  //
 | 
						|
  // WordCount is used to record bytes of currently transfered data
 | 
						|
  //
 | 
						|
  while (WordCount < ByteCount / 2) {
 | 
						|
    //
 | 
						|
    // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.
 | 
						|
    //
 | 
						|
    Status = DRQReady2 (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), ATATIMEOUT);
 | 
						|
    if (Status != EFI_SUCCESS) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    if (CheckErrorStatus (AtapiBlkIoDev, StatusReg) != EFI_SUCCESS) {
 | 
						|
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Get the byte count for one series of read
 | 
						|
    //
 | 
						|
    if ((WordCount + Increment) > ByteCount / 2) {
 | 
						|
      Increment = ByteCount / 2 - WordCount;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // perform a series of read without check DRQ ready
 | 
						|
    //
 | 
						|
    for (Index = 0; Index < Increment; Index++) {
 | 
						|
      *Buffer16++ = IoRead16 (DataReg);
 | 
						|
    }
 | 
						|
 | 
						|
    WordCount += Increment;
 | 
						|
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // while
 | 
						|
  //
 | 
						|
  if (DRQClear (
 | 
						|
        AtapiBlkIoDev,
 | 
						|
        &(AtapiBlkIoDev->IdeIoPortReg[Channel]),
 | 
						|
        ATATIMEOUT
 | 
						|
        ) != EFI_SUCCESS) {
 | 
						|
    return CheckErrorStatus (AtapiBlkIoDev, StatusReg);
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Sends out ATAPI Test Unit Ready Packet Command to the specified device
 | 
						|
  to find out whether device is accessible.
 | 
						|
 | 
						|
  @param[in]  AtapiBlkIoDev     A pointer to atapi block IO device.
 | 
						|
  @param[in]  DevicePosition    An integer to signify device position.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        TestUnit command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR   Device cannot be executed TestUnit command successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
TestUnitReady (
 | 
						|
  IN  ATAPI_BLK_IO_DEV    *AtapiBlkIoDev,
 | 
						|
  IN  UINTN               DevicePosition
 | 
						|
  )
 | 
						|
{
 | 
						|
  ATAPI_PACKET_COMMAND  Packet;
 | 
						|
  EFI_STATUS            Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // fill command packet
 | 
						|
  //
 | 
						|
  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
 | 
						|
  Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;
 | 
						|
 | 
						|
  //
 | 
						|
  // send command packet
 | 
						|
  //
 | 
						|
  Status = AtapiPacketCommandIn (AtapiBlkIoDev, DevicePosition, &Packet, NULL, 0, ATAPITIMEOUT);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Send out ATAPI commands conforms to the Packet Command with PIO Data In Protocol.
 | 
						|
  
 | 
						|
  @param[in]  AtapiBlkIoDev         A pointer to atapi block IO device.
 | 
						|
  @param[in]  DevicePosition        An integer to signify device position.
 | 
						|
  @param[in]  Packet                A pointer to ATAPI command packet.
 | 
						|
  @param[in]  Buffer                Buffer to contain requested transfer data from device.
 | 
						|
  @param[in]  ByteCount             Requested transfer data length.
 | 
						|
  @param[in]  TimeoutInMilliSeconds Time out value, in unit of milliseconds.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        Command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR   Device cannot be executed command successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AtapiPacketCommandIn (
 | 
						|
  IN  ATAPI_BLK_IO_DEV      *AtapiBlkIoDev,
 | 
						|
  IN  UINTN                 DevicePosition,
 | 
						|
  IN  ATAPI_PACKET_COMMAND  *Packet,
 | 
						|
  IN  UINT16                *Buffer,
 | 
						|
  IN  UINT32                ByteCount,
 | 
						|
  IN  UINTN                 TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8       Channel;
 | 
						|
  UINT8       Device;
 | 
						|
  UINT16      StatusReg;
 | 
						|
  UINT16      HeadReg;
 | 
						|
  UINT16      CommandReg;
 | 
						|
  UINT16      FeatureReg;
 | 
						|
  UINT16      CylinderLsbReg;
 | 
						|
  UINT16      CylinderMsbReg;
 | 
						|
  UINT16      DeviceControlReg;
 | 
						|
  UINT16      DataReg;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT32      Count;
 | 
						|
  UINT16      *CommandIndex;
 | 
						|
  UINT16      *PtrBuffer;
 | 
						|
  UINT32      Index;
 | 
						|
  UINT8       StatusValue;
 | 
						|
  UINT32      WordCount;
 | 
						|
 | 
						|
  //
 | 
						|
  // required transfer data in word unit.
 | 
						|
  //
 | 
						|
  UINT32      RequiredWordCount;
 | 
						|
 | 
						|
  //
 | 
						|
  // actual transfer data in word unit.
 | 
						|
  //
 | 
						|
  UINT32      ActualWordCount;
 | 
						|
 | 
						|
  Channel           = (UINT8) (DevicePosition / 2);
 | 
						|
  Device            = (UINT8) (DevicePosition % 2);
 | 
						|
 | 
						|
  ASSERT (Channel < MAX_IDE_CHANNELS);
 | 
						|
 | 
						|
  StatusReg         = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Status;
 | 
						|
  HeadReg           = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;
 | 
						|
  CommandReg        = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;
 | 
						|
  FeatureReg        = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg1.Feature;
 | 
						|
  CylinderLsbReg    = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderLsb;
 | 
						|
  CylinderMsbReg    = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderMsb;
 | 
						|
  DeviceControlReg  = AtapiBlkIoDev->IdeIoPortReg[Channel].Alt.DeviceControl;
 | 
						|
  DataReg           = AtapiBlkIoDev->IdeIoPortReg[Channel].Data;
 | 
						|
 | 
						|
  //
 | 
						|
  // Set all the command parameters by fill related registers.
 | 
						|
  // Before write to all the following registers, BSY and DRQ must be 0.
 | 
						|
  //
 | 
						|
  if (DRQClear2 (
 | 
						|
        AtapiBlkIoDev,
 | 
						|
        &(AtapiBlkIoDev->IdeIoPortReg[Channel]),
 | 
						|
        ATATIMEOUT
 | 
						|
        ) != EFI_SUCCESS) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Select device via Device/Head Register.
 | 
						|
  // DEFAULT_CMD: 0xa0 (1010,0000)
 | 
						|
  //
 | 
						|
  IoWrite8 (HeadReg, (UINT8) ((Device << 4) | ATA_DEFAULT_CMD));
 | 
						|
 | 
						|
  //
 | 
						|
  // No OVL; No DMA
 | 
						|
  //
 | 
						|
  IoWrite8 (FeatureReg, 0x00);
 | 
						|
 | 
						|
  //
 | 
						|
  // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
 | 
						|
  // determine how many data should be transfered.
 | 
						|
  //
 | 
						|
  IoWrite8 (CylinderLsbReg, (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff));
 | 
						|
  IoWrite8 (CylinderMsbReg, (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8));
 | 
						|
 | 
						|
  //
 | 
						|
  //  DEFAULT_CTL:0x0a (0000,1010)
 | 
						|
  //  Disable interrupt
 | 
						|
  //
 | 
						|
  IoWrite8 (DeviceControlReg, ATA_DEFAULT_CTL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Send Packet command to inform device
 | 
						|
  // that the following data bytes are command packet.
 | 
						|
  //
 | 
						|
  IoWrite8 (CommandReg, ATA_CMD_PACKET);
 | 
						|
 | 
						|
  Status = DRQReady (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), TimeoutInMilliSeconds);
 | 
						|
  if (Status != EFI_SUCCESS) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Send out command packet
 | 
						|
  //
 | 
						|
  CommandIndex = Packet->Data16;
 | 
						|
  for (Count = 0; Count < 6; Count++, CommandIndex++) {
 | 
						|
    IoWrite16 (DataReg, *CommandIndex);
 | 
						|
    MicroSecondDelay (10);
 | 
						|
  }
 | 
						|
 | 
						|
  StatusValue = IoRead8 (StatusReg);
 | 
						|
  if ((StatusValue & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
 | 
						|
    //
 | 
						|
    // Trouble! Something's wrong here... Wait some time and return. 3 second is
 | 
						|
    // supposed to be long enough for a device reset latency or error recovery
 | 
						|
    //
 | 
						|
    MicroSecondDelay (3000000);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Buffer == NULL || ByteCount == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // call PioReadWriteData() function to get
 | 
						|
  // requested transfer data form device.
 | 
						|
  //
 | 
						|
  PtrBuffer         = Buffer;
 | 
						|
  RequiredWordCount = ByteCount / 2;
 | 
						|
  //
 | 
						|
  // ActuralWordCount means the word count of data really transfered.
 | 
						|
  //
 | 
						|
  ActualWordCount = 0;
 | 
						|
 | 
						|
  Status          = EFI_SUCCESS;
 | 
						|
  while ((Status == EFI_SUCCESS) && (ActualWordCount < RequiredWordCount)) {
 | 
						|
    //
 | 
						|
    // before each data transfer stream, the host should poll DRQ bit ready,
 | 
						|
    // which informs device is ready to transfer data.
 | 
						|
    //
 | 
						|
    if (DRQReady2 (
 | 
						|
          AtapiBlkIoDev,
 | 
						|
          &(AtapiBlkIoDev->IdeIoPortReg[Channel]),
 | 
						|
          TimeoutInMilliSeconds
 | 
						|
          ) != EFI_SUCCESS) {
 | 
						|
      return CheckErrorStatus (AtapiBlkIoDev, StatusReg);
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // read Status Register will clear interrupt
 | 
						|
    //
 | 
						|
    StatusValue = IoRead8 (StatusReg);
 | 
						|
 | 
						|
    //
 | 
						|
    // get current data transfer size from Cylinder Registers.
 | 
						|
    //
 | 
						|
    WordCount = IoRead8 (CylinderMsbReg) << 8;
 | 
						|
    WordCount = WordCount | IoRead8 (CylinderLsbReg);
 | 
						|
    WordCount = WordCount & 0xffff;
 | 
						|
    WordCount /= 2;
 | 
						|
 | 
						|
    //
 | 
						|
    // perform a series data In/Out.
 | 
						|
    //
 | 
						|
    for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {
 | 
						|
 | 
						|
      *PtrBuffer = IoRead16 (DataReg);
 | 
						|
 | 
						|
      PtrBuffer++;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    if (((ATAPI_REQUEST_SENSE_CMD *) Packet)->opcode == ATA_CMD_REQUEST_SENSE && ActualWordCount >= 4) {
 | 
						|
      RequiredWordCount = MIN (
 | 
						|
                            RequiredWordCount,
 | 
						|
                            (UINT32) (4 + (((ATAPI_REQUEST_SENSE_DATA *) Buffer)->addnl_sense_length / 2))
 | 
						|
                            );
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // After data transfer is completed, normally, DRQ bit should clear.
 | 
						|
  //
 | 
						|
  Status = DRQClear2 (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), TimeoutInMilliSeconds);
 | 
						|
  if (Status != EFI_SUCCESS) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // read status register to check whether error happens.
 | 
						|
  //
 | 
						|
  Status = CheckErrorStatus (AtapiBlkIoDev, StatusReg);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Sends out ATAPI Inquiry Packet Command to the specified device.
 | 
						|
  This command will return INQUIRY data of the device.
 | 
						|
 | 
						|
  @param[in]  AtapiBlkIoDev   A pointer to atapi block IO device.
 | 
						|
  @param[in]  DevicePosition  An integer to signify device position.
 | 
						|
  @param[out] MediaInfo       The media information of the specified block media.
 | 
						|
  @param[out] MediaInfo2      The media information 2 of the specified block media.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        Command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR   Device cannot be executed command successfully.
 | 
						|
  @retval EFI_UNSUPPORTED    Unsupported device type.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Inquiry (
 | 
						|
  IN  ATAPI_BLK_IO_DEV              *AtapiBlkIoDev,
 | 
						|
  IN  UINTN                         DevicePosition,
 | 
						|
  OUT EFI_PEI_BLOCK_IO_MEDIA        *MediaInfo,
 | 
						|
  OUT EFI_PEI_BLOCK_IO2_MEDIA       *MediaInfo2
 | 
						|
  )
 | 
						|
{
 | 
						|
  ATAPI_PACKET_COMMAND        Packet;
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  ATAPI_INQUIRY_DATA          Idata;
 | 
						|
 | 
						|
  //
 | 
						|
  // prepare command packet for the ATAPI Inquiry Packet Command.
 | 
						|
  //
 | 
						|
  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
 | 
						|
  ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA));
 | 
						|
 | 
						|
  Packet.Inquiry.opcode             = ATA_CMD_INQUIRY;
 | 
						|
  Packet.Inquiry.page_code          = 0;
 | 
						|
  Packet.Inquiry.allocation_length  = (UINT8) sizeof (ATAPI_INQUIRY_DATA);
 | 
						|
 | 
						|
  //
 | 
						|
  // Send command packet and get requested Inquiry data.
 | 
						|
  //
 | 
						|
  Status = AtapiPacketCommandIn (
 | 
						|
            AtapiBlkIoDev,
 | 
						|
            DevicePosition,
 | 
						|
            &Packet,
 | 
						|
            (UINT16 *) (&Idata),
 | 
						|
            sizeof (ATAPI_INQUIRY_DATA),
 | 
						|
            ATAPITIMEOUT
 | 
						|
            //50
 | 
						|
            );
 | 
						|
 | 
						|
  if (Status != EFI_SUCCESS) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Identify device type via INQUIRY data.
 | 
						|
  //
 | 
						|
  switch (Idata.peripheral_type & 0x1f) {
 | 
						|
  case 0x00:
 | 
						|
    //
 | 
						|
    // Magnetic Disk
 | 
						|
    //
 | 
						|
    MediaInfo->DeviceType   = IdeLS120;
 | 
						|
    MediaInfo->MediaPresent = FALSE;
 | 
						|
    MediaInfo->LastBlock    = 0;
 | 
						|
    MediaInfo->BlockSize    = 0x200;
 | 
						|
    MediaInfo2->InterfaceType  = MSG_ATAPI_DP;
 | 
						|
    MediaInfo2->RemovableMedia = TRUE;
 | 
						|
    MediaInfo2->MediaPresent   = FALSE;
 | 
						|
    MediaInfo2->ReadOnly       = FALSE;
 | 
						|
    MediaInfo2->BlockSize      = 0x200;
 | 
						|
    MediaInfo2->LastBlock      = 0;
 | 
						|
    break;
 | 
						|
 | 
						|
  case 0x05:
 | 
						|
    //
 | 
						|
    // CD-ROM
 | 
						|
    //
 | 
						|
    MediaInfo->DeviceType   = IdeCDROM;
 | 
						|
    MediaInfo->MediaPresent = FALSE;
 | 
						|
    MediaInfo->LastBlock    = 0;
 | 
						|
    MediaInfo->BlockSize    = 0x800;
 | 
						|
    MediaInfo2->InterfaceType  = MSG_ATAPI_DP;
 | 
						|
    MediaInfo2->RemovableMedia = TRUE;
 | 
						|
    MediaInfo2->MediaPresent   = FALSE;
 | 
						|
    MediaInfo2->ReadOnly       = TRUE;
 | 
						|
    MediaInfo2->BlockSize      = 0x200;
 | 
						|
    MediaInfo2->LastBlock      = 0;
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**  
 | 
						|
  Used before read/write blocks from/to ATAPI device media. 
 | 
						|
  Since ATAPI device media is removable, it is necessary to detect
 | 
						|
  whether media is present and get current present media's information.
 | 
						|
 | 
						|
  @param[in]  AtapiBlkIoDev     A pointer to atapi block IO device.
 | 
						|
  @param[in]  DevicePosition    An integer to signify device position.
 | 
						|
  @param[in, out] MediaInfo     The media information of the specified block media.
 | 
						|
  @param[in, out] MediaInfo2    The media information 2 of the specified block media.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      Some device errors happen.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Can not allocate required resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
DetectMedia (
 | 
						|
  IN  ATAPI_BLK_IO_DEV              *AtapiBlkIoDev,
 | 
						|
  IN  UINTN                         DevicePosition,
 | 
						|
  IN OUT EFI_PEI_BLOCK_IO_MEDIA     *MediaInfo,
 | 
						|
  IN OUT EFI_PEI_BLOCK_IO2_MEDIA    *MediaInfo2
 | 
						|
  )
 | 
						|
{
 | 
						|
 | 
						|
  UINTN                     Index;
 | 
						|
  UINTN                     RetryNum;
 | 
						|
  UINTN                     MaxRetryNum;
 | 
						|
  ATAPI_REQUEST_SENSE_DATA  *SenseBuffers;
 | 
						|
  BOOLEAN                   NeedReadCapacity;
 | 
						|
  BOOLEAN                   NeedRetry;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  UINT8                     SenseCounts;
 | 
						|
 | 
						|
  SenseBuffers = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*SenseBuffers)));
 | 
						|
  if (SenseBuffers == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Test Unit Ready command is used to detect whether device is accessible,
 | 
						|
  // the device will produce corresponding Sense data.
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < 2; Index++) {
 | 
						|
 | 
						|
    Status = TestUnitReady (AtapiBlkIoDev, DevicePosition);
 | 
						|
    if (Status != EFI_SUCCESS) {
 | 
						|
      Status = ResetDevice (AtapiBlkIoDev, DevicePosition, FALSE);
 | 
						|
 | 
						|
      if (Status != EFI_SUCCESS) {
 | 
						|
        ResetDevice (AtapiBlkIoDev, DevicePosition, TRUE);
 | 
						|
      }
 | 
						|
 | 
						|
    } else {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  SenseCounts       = MAX_SENSE_KEY_COUNT;
 | 
						|
  Status            = EFI_SUCCESS;
 | 
						|
  NeedReadCapacity  = TRUE;
 | 
						|
 | 
						|
  for (Index = 0; Index < 5; Index++) {
 | 
						|
    SenseCounts = MAX_SENSE_KEY_COUNT;
 | 
						|
    Status = RequestSense (
 | 
						|
              AtapiBlkIoDev,
 | 
						|
              DevicePosition,
 | 
						|
              SenseBuffers,
 | 
						|
              &SenseCounts
 | 
						|
              );
 | 
						|
    DEBUG ((EFI_D_INFO, "Atapi Request Sense Count is %d\n", SenseCounts));
 | 
						|
    if (IsDeviceStateUnclear (SenseBuffers, SenseCounts) || IsNoMedia (SenseBuffers, SenseCounts)) {
 | 
						|
      //
 | 
						|
      // We are not sure whether the media is present or not, try again
 | 
						|
      //
 | 
						|
      TestUnitReady (AtapiBlkIoDev, DevicePosition);
 | 
						|
    } else {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Status == EFI_SUCCESS) {
 | 
						|
 | 
						|
    if (IsNoMedia (SenseBuffers, SenseCounts)) {
 | 
						|
 | 
						|
      NeedReadCapacity        = FALSE;
 | 
						|
      MediaInfo->MediaPresent = FALSE;
 | 
						|
      MediaInfo->LastBlock    = 0;
 | 
						|
      MediaInfo2->MediaPresent = FALSE;
 | 
						|
      MediaInfo2->LastBlock    = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (IsMediaError (SenseBuffers, SenseCounts)) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (NeedReadCapacity) {
 | 
						|
    //
 | 
						|
    // at most retry 5 times
 | 
						|
    //
 | 
						|
    MaxRetryNum = 5;
 | 
						|
    RetryNum    = 1;
 | 
						|
    //
 | 
						|
    // initial retry once
 | 
						|
    //
 | 
						|
    for (Index = 0; (Index < RetryNum) && (Index < MaxRetryNum); Index++) {
 | 
						|
 | 
						|
      Status = ReadCapacity (AtapiBlkIoDev, DevicePosition, MediaInfo, MediaInfo2);
 | 
						|
      MicroSecondDelay (200000);
 | 
						|
      SenseCounts = MAX_SENSE_KEY_COUNT;
 | 
						|
 | 
						|
      if (Status != EFI_SUCCESS) {
 | 
						|
 | 
						|
        Status = RequestSense (AtapiBlkIoDev, DevicePosition, SenseBuffers, &SenseCounts);
 | 
						|
        //
 | 
						|
        // If Request Sense data failed, reset the device and retry.
 | 
						|
        //
 | 
						|
        if (Status != EFI_SUCCESS) {
 | 
						|
 | 
						|
          Status = ResetDevice (AtapiBlkIoDev, DevicePosition, FALSE);
 | 
						|
          //
 | 
						|
          // if ATAPI soft reset fail,
 | 
						|
          // use stronger reset mechanism -- ATA soft reset.
 | 
						|
          //
 | 
						|
          if (Status != EFI_SUCCESS) {
 | 
						|
            ResetDevice (AtapiBlkIoDev, DevicePosition, TRUE);
 | 
						|
          }
 | 
						|
 | 
						|
          RetryNum++;
 | 
						|
          //
 | 
						|
          // retry once more
 | 
						|
          //
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // No Media
 | 
						|
        //
 | 
						|
        if (IsNoMedia (SenseBuffers, SenseCounts)) {
 | 
						|
 | 
						|
          MediaInfo->MediaPresent = FALSE;
 | 
						|
          MediaInfo->LastBlock    = 0;
 | 
						|
          MediaInfo2->MediaPresent = FALSE;
 | 
						|
          MediaInfo2->LastBlock    = 0;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (IsMediaError (SenseBuffers, SenseCounts)) {
 | 
						|
          return EFI_DEVICE_ERROR;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!IsDriveReady (SenseBuffers, SenseCounts, &NeedRetry)) {
 | 
						|
          //
 | 
						|
          // Drive not ready: if NeedRetry, then retry once more;
 | 
						|
          // else return error
 | 
						|
          //
 | 
						|
          if (NeedRetry) {
 | 
						|
            RetryNum++;
 | 
						|
            continue;
 | 
						|
          } else {
 | 
						|
            return EFI_DEVICE_ERROR;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // if read capacity fail not for above reasons, retry once more
 | 
						|
        //
 | 
						|
        RetryNum++;
 | 
						|
 | 
						|
      }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**  
 | 
						|
  Reset specified Atapi device.
 | 
						|
 | 
						|
  @param[in]  AtapiBlkIoDev     A pointer to atapi block IO device.
 | 
						|
  @param[in]  DevicePosition    An integer to signify device position.
 | 
						|
  @param[in]  Extensive         If TRUE, use ATA soft reset, otherwise use Atapi soft reset.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      Some device errors happen.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ResetDevice (
 | 
						|
  IN  ATAPI_BLK_IO_DEV  *AtapiBlkIoDev,
 | 
						|
  IN  UINTN             DevicePosition,
 | 
						|
  IN  BOOLEAN           Extensive
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8   DevControl;
 | 
						|
  UINT8   Command;
 | 
						|
  UINT8   DeviceSelect;
 | 
						|
  UINT16  DeviceControlReg;
 | 
						|
  UINT16  CommandReg;
 | 
						|
  UINT16  HeadReg;
 | 
						|
  UINT8   Channel;
 | 
						|
  UINT8   Device;
 | 
						|
 | 
						|
  Channel           = (UINT8) (DevicePosition / 2);
 | 
						|
  Device            = (UINT8) (DevicePosition % 2);
 | 
						|
 | 
						|
  ASSERT (Channel < MAX_IDE_CHANNELS);
 | 
						|
 | 
						|
  DeviceControlReg  = AtapiBlkIoDev->IdeIoPortReg[Channel].Alt.DeviceControl;
 | 
						|
  CommandReg        = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;
 | 
						|
  HeadReg           = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;
 | 
						|
 | 
						|
  if (Extensive) {
 | 
						|
 | 
						|
    DevControl = 0;
 | 
						|
    DevControl |= ATA_CTLREG_SRST;
 | 
						|
    //
 | 
						|
    // set SRST bit to initiate soft reset
 | 
						|
    //
 | 
						|
    DevControl |= BIT1;
 | 
						|
    //
 | 
						|
    // disable Interrupt
 | 
						|
    //
 | 
						|
    IoWrite8 (DeviceControlReg, DevControl);
 | 
						|
 | 
						|
    //
 | 
						|
    // Wait 10us
 | 
						|
    //
 | 
						|
    MicroSecondDelay (10);
 | 
						|
 | 
						|
    //
 | 
						|
    // Clear SRST bit
 | 
						|
    //
 | 
						|
    DevControl &= 0xfb;
 | 
						|
    //
 | 
						|
    // 0xfb:1111,1011
 | 
						|
    //
 | 
						|
    IoWrite8 (DeviceControlReg, DevControl);
 | 
						|
 | 
						|
    //
 | 
						|
    // slave device needs at most 31s to clear BSY
 | 
						|
    //
 | 
						|
    if (WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 31000) == EFI_TIMEOUT) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // for ATAPI device, no need to wait DRDY ready after device selecting.
 | 
						|
    // bit7 and bit5 are both set to 1 for backward compatibility
 | 
						|
    //
 | 
						|
    DeviceSelect = (UINT8) (((BIT7 | BIT5) | (Device << 4)));
 | 
						|
    IoWrite8 (HeadReg, DeviceSelect);
 | 
						|
 | 
						|
    Command = ATA_CMD_SOFT_RESET;
 | 
						|
    IoWrite8 (CommandReg, Command);
 | 
						|
 | 
						|
    //
 | 
						|
    // BSY cleared is the only status return to the host by the device when reset is completed
 | 
						|
    // slave device needs at most 31s to clear BSY
 | 
						|
    //
 | 
						|
    if (WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 31000) != EFI_SUCCESS) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // stall 5 seconds to make the device status stable
 | 
						|
    //
 | 
						|
    MicroSecondDelay (STALL_1_SECONDS * 5);
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**  
 | 
						|
  Sends out ATAPI Request Sense Packet Command to the specified device.
 | 
						|
 | 
						|
  @param[in]      AtapiBlkIoDev   A pointer to atapi block IO device.
 | 
						|
  @param[in]      DevicePosition  An integer to signify device position.
 | 
						|
  @param[in]      SenseBuffers    Pointer to sense buffer.
 | 
						|
  @param[in, out] SenseCounts     Length of sense buffer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      Some device errors happen.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
RequestSense (
 | 
						|
  IN  ATAPI_BLK_IO_DEV           *AtapiBlkIoDev,
 | 
						|
  IN  UINTN                      DevicePosition,
 | 
						|
  IN  ATAPI_REQUEST_SENSE_DATA   *SenseBuffers,
 | 
						|
  IN  OUT  UINT8                 *SenseCounts
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  ATAPI_REQUEST_SENSE_DATA    *Sense;
 | 
						|
  UINT16                *Ptr;
 | 
						|
  BOOLEAN               SenseReq;
 | 
						|
  ATAPI_PACKET_COMMAND  Packet;
 | 
						|
 | 
						|
  ZeroMem (SenseBuffers, sizeof (ATAPI_REQUEST_SENSE_DATA) * (*SenseCounts));
 | 
						|
  //
 | 
						|
  // fill command packet for Request Sense Packet Command
 | 
						|
  //
 | 
						|
  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
 | 
						|
  Packet.RequestSence.opcode            = ATA_CMD_REQUEST_SENSE;
 | 
						|
  Packet.RequestSence.allocation_length = (UINT8) sizeof (ATAPI_REQUEST_SENSE_DATA);
 | 
						|
 | 
						|
  Ptr = (UINT16 *) SenseBuffers;
 | 
						|
  //
 | 
						|
  // initialize pointer
 | 
						|
  //
 | 
						|
  *SenseCounts = 0;
 | 
						|
  //
 | 
						|
  //  request sense data from device continiously until no sense data exists in the device.
 | 
						|
  //
 | 
						|
  for (SenseReq = TRUE; SenseReq;) {
 | 
						|
 | 
						|
    Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;
 | 
						|
 | 
						|
    //
 | 
						|
    // send out Request Sense Packet Command and get one Sense data form device
 | 
						|
    //
 | 
						|
    Status = AtapiPacketCommandIn (
 | 
						|
              AtapiBlkIoDev,
 | 
						|
              DevicePosition,
 | 
						|
              &Packet,
 | 
						|
              Ptr,
 | 
						|
              sizeof (ATAPI_REQUEST_SENSE_DATA),
 | 
						|
              ATAPITIMEOUT
 | 
						|
              );
 | 
						|
    //
 | 
						|
    // failed to get Sense data
 | 
						|
    //
 | 
						|
    if (Status != EFI_SUCCESS) {
 | 
						|
      if (*SenseCounts == 0) {
 | 
						|
        return EFI_DEVICE_ERROR;
 | 
						|
      } else {
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    (*SenseCounts)++;
 | 
						|
 | 
						|
    if (*SenseCounts > MAX_SENSE_KEY_COUNT) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // We limit MAX sense data count to 20 in order to avoid dead loop. Some
 | 
						|
    // incompatible ATAPI devices don't retrive NO_SENSE when there is no media.
 | 
						|
    // In this case, dead loop occurs if we don't have a gatekeeper. 20 is
 | 
						|
    // supposed to be large enough for any ATAPI device.
 | 
						|
    //
 | 
						|
    if ((Sense->sense_key != ATA_SK_NO_SENSE) && ((*SenseCounts) < 20)) {
 | 
						|
 | 
						|
      Ptr += sizeof (ATAPI_REQUEST_SENSE_DATA) / 2;
 | 
						|
      //
 | 
						|
      // Ptr is word based pointer
 | 
						|
      //
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // when no sense key, skip out the loop
 | 
						|
      //
 | 
						|
      SenseReq = FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**  
 | 
						|
  Sends out ATAPI Read Capacity Packet Command to the specified device.
 | 
						|
  This command will return the information regarding the capacity of the
 | 
						|
  media in the device.
 | 
						|
 | 
						|
  @param[in]  AtapiBlkIoDev     A pointer to atapi block IO device.
 | 
						|
  @param[in]  DevicePosition    An integer to signify device position.
 | 
						|
  @param[in, out] MediaInfo     The media information of the specified block media.
 | 
						|
  @param[in, out] MediaInfo2    The media information 2 of the specified block media.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      Some device errors happen.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ReadCapacity (
 | 
						|
  IN  ATAPI_BLK_IO_DEV              *AtapiBlkIoDev,
 | 
						|
  IN  UINTN                         DevicePosition,
 | 
						|
  IN OUT EFI_PEI_BLOCK_IO_MEDIA     *MediaInfo,
 | 
						|
  IN OUT EFI_PEI_BLOCK_IO2_MEDIA    *MediaInfo2
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  ATAPI_PACKET_COMMAND      Packet;
 | 
						|
 | 
						|
  //
 | 
						|
  // used for capacity data returned from ATAPI device
 | 
						|
  //
 | 
						|
  ATAPI_READ_CAPACITY_DATA        Data;
 | 
						|
  ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;
 | 
						|
 | 
						|
  ZeroMem (&Data, sizeof (Data));
 | 
						|
  ZeroMem (&FormatData, sizeof (FormatData));
 | 
						|
 | 
						|
  if (MediaInfo->DeviceType == IdeCDROM) {
 | 
						|
 | 
						|
    ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
 | 
						|
    Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;
 | 
						|
    Status = AtapiPacketCommandIn (
 | 
						|
              AtapiBlkIoDev,
 | 
						|
              DevicePosition,
 | 
						|
              &Packet,
 | 
						|
              (UINT16 *) (&Data),
 | 
						|
              sizeof (ATAPI_READ_CAPACITY_DATA),
 | 
						|
              ATAPITIMEOUT
 | 
						|
              );
 | 
						|
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // DeviceType == IdeLS120
 | 
						|
    //
 | 
						|
    ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
 | 
						|
    Packet.ReadFormatCapacity.opcode                = ATA_CMD_READ_FORMAT_CAPACITY;
 | 
						|
    Packet.ReadFormatCapacity.allocation_length_lo  = 12;
 | 
						|
    Status = AtapiPacketCommandIn (
 | 
						|
              AtapiBlkIoDev,
 | 
						|
              DevicePosition,
 | 
						|
              &Packet,
 | 
						|
              (UINT16 *) (&FormatData),
 | 
						|
              sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),
 | 
						|
              ATAPITIMEOUT*10
 | 
						|
              );
 | 
						|
  }
 | 
						|
 | 
						|
  if (Status == EFI_SUCCESS) {
 | 
						|
 | 
						|
    if (MediaInfo->DeviceType == IdeCDROM) {
 | 
						|
 | 
						|
      MediaInfo->LastBlock    = ((UINT32) Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;
 | 
						|
      MediaInfo->MediaPresent = TRUE;
 | 
						|
      //
 | 
						|
      // Because the user data portion in the sector of the Data CD supported
 | 
						|
      // is always 800h
 | 
						|
      //
 | 
						|
      MediaInfo->BlockSize     = 0x800;
 | 
						|
 | 
						|
      MediaInfo2->LastBlock    = MediaInfo->LastBlock;
 | 
						|
      MediaInfo2->MediaPresent = MediaInfo->MediaPresent;
 | 
						|
      MediaInfo2->BlockSize    = (UINT32)MediaInfo->BlockSize;
 | 
						|
    }
 | 
						|
 | 
						|
    if (MediaInfo->DeviceType == IdeLS120) {
 | 
						|
 | 
						|
      if (FormatData.DesCode == 3) {
 | 
						|
        MediaInfo->MediaPresent = FALSE;
 | 
						|
        MediaInfo->LastBlock    = 0;
 | 
						|
        MediaInfo2->MediaPresent = FALSE;
 | 
						|
        MediaInfo2->LastBlock    = 0;
 | 
						|
      } else {
 | 
						|
        MediaInfo->LastBlock = ((UINT32) FormatData.LastLba3 << 24) |
 | 
						|
          (FormatData.LastLba2 << 16) |
 | 
						|
          (FormatData.LastLba1 << 8) |
 | 
						|
          FormatData.LastLba0;
 | 
						|
        MediaInfo->LastBlock--;
 | 
						|
 | 
						|
        MediaInfo->MediaPresent = TRUE;
 | 
						|
 | 
						|
        MediaInfo->BlockSize    = 0x200;
 | 
						|
 | 
						|
        MediaInfo2->LastBlock    = MediaInfo->LastBlock;
 | 
						|
        MediaInfo2->MediaPresent = MediaInfo->MediaPresent;
 | 
						|
        MediaInfo2->BlockSize    = (UINT32)MediaInfo->BlockSize;
 | 
						|
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_SUCCESS;
 | 
						|
 | 
						|
  } else {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**  
 | 
						|
  Perform read from disk in block unit.
 | 
						|
 | 
						|
  @param[in]  AtapiBlkIoDev   A pointer to atapi block IO device.
 | 
						|
  @param[in]  DevicePosition  An integer to signify device position.
 | 
						|
  @param[in]  Buffer          Buffer to contain read data.
 | 
						|
  @param[in]  StartLba        Starting LBA address.
 | 
						|
  @param[in]  NumberOfBlocks  Number of blocks to read.
 | 
						|
  @param[in]  BlockSize       Size of each block.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Command executed successfully.
 | 
						|
  @retval EFI_DEVICE_ERROR      Some device errors happen.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ReadSectors (
 | 
						|
  IN  ATAPI_BLK_IO_DEV    *AtapiBlkIoDev,
 | 
						|
  IN  UINTN               DevicePosition,
 | 
						|
  IN  VOID                *Buffer,
 | 
						|
  IN  EFI_PEI_LBA         StartLba,
 | 
						|
  IN  UINTN               NumberOfBlocks,
 | 
						|
  IN  UINTN               BlockSize
 | 
						|
  )
 | 
						|
{
 | 
						|
 | 
						|
  ATAPI_PACKET_COMMAND  Packet;
 | 
						|
  ATAPI_READ10_CMD      *Read10Packet;
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  UINTN                 BlocksRemaining;
 | 
						|
  UINT32                Lba32;
 | 
						|
  UINT32                ByteCount;
 | 
						|
  UINT16                SectorCount;
 | 
						|
  VOID                  *PtrBuffer;
 | 
						|
  UINT16                MaxBlock;
 | 
						|
 | 
						|
  //
 | 
						|
  // fill command packet for Read(10) command
 | 
						|
  //
 | 
						|
  ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
 | 
						|
  Read10Packet  = &Packet.Read10;
 | 
						|
  Lba32         = (UINT32) StartLba;
 | 
						|
  PtrBuffer     = Buffer;
 | 
						|
 | 
						|
  //
 | 
						|
  // limit the data bytes that can be transfered by one Read(10) Command
 | 
						|
  //
 | 
						|
  MaxBlock = (UINT16) (0x10000 / BlockSize);
 | 
						|
  //
 | 
						|
  // (64k bytes)
 | 
						|
  //
 | 
						|
  BlocksRemaining = NumberOfBlocks;
 | 
						|
 | 
						|
  Status          = EFI_SUCCESS;
 | 
						|
  while (BlocksRemaining > 0) {
 | 
						|
 | 
						|
    if (BlocksRemaining <= MaxBlock) {
 | 
						|
      SectorCount = (UINT16) BlocksRemaining;
 | 
						|
    } else {
 | 
						|
      SectorCount = MaxBlock;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // fill the Packet data sturcture
 | 
						|
    //
 | 
						|
    Read10Packet->opcode = ATA_CMD_READ_10;
 | 
						|
 | 
						|
    //
 | 
						|
    // Lba0 ~ Lba3 specify the start logical block address of the data transfer.
 | 
						|
    // Lba0 is MSB, Lba3 is LSB
 | 
						|
    //
 | 
						|
    Read10Packet->Lba3  = (UINT8) (Lba32 & 0xff);
 | 
						|
    Read10Packet->Lba2  = (UINT8) (Lba32 >> 8);
 | 
						|
    Read10Packet->Lba1  = (UINT8) (Lba32 >> 16);
 | 
						|
    Read10Packet->Lba0  = (UINT8) (Lba32 >> 24);
 | 
						|
 | 
						|
    //
 | 
						|
    // TranLen0 ~ TranLen1 specify the transfer length in block unit.
 | 
						|
    // TranLen0 is MSB, TranLen is LSB
 | 
						|
    //
 | 
						|
    Read10Packet->TranLen1  = (UINT8) (SectorCount & 0xff);
 | 
						|
    Read10Packet->TranLen0  = (UINT8) (SectorCount >> 8);
 | 
						|
 | 
						|
    ByteCount               = (UINT32) (SectorCount * BlockSize);
 | 
						|
 | 
						|
    Status = AtapiPacketCommandIn (
 | 
						|
              AtapiBlkIoDev,
 | 
						|
              DevicePosition,
 | 
						|
              &Packet,
 | 
						|
              (UINT16 *) PtrBuffer,
 | 
						|
              ByteCount,
 | 
						|
              ATAPILONGTIMEOUT
 | 
						|
              );
 | 
						|
    if (Status != EFI_SUCCESS) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    Lba32 += SectorCount;
 | 
						|
    PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;
 | 
						|
    BlocksRemaining -= SectorCount;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**  
 | 
						|
  Check if there is media according to sense data.
 | 
						|
 | 
						|
  @param[in]  SenseData   Pointer to sense data.
 | 
						|
  @param[in]  SenseCounts Count of sense data.
 | 
						|
 | 
						|
  @retval TRUE    No media
 | 
						|
  @retval FALSE   Media exists
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsNoMedia (
 | 
						|
  IN  ATAPI_REQUEST_SENSE_DATA  *SenseData,
 | 
						|
  IN  UINTN                     SenseCounts
 | 
						|
  )
 | 
						|
{
 | 
						|
  ATAPI_REQUEST_SENSE_DATA  *SensePtr;
 | 
						|
  UINTN                     Index;
 | 
						|
  BOOLEAN                   IsNoMedia;
 | 
						|
 | 
						|
  IsNoMedia = FALSE;
 | 
						|
 | 
						|
  SensePtr  = SenseData;
 | 
						|
 | 
						|
  for (Index = 0; Index < SenseCounts; Index++) {
 | 
						|
 | 
						|
    if ((SensePtr->sense_key == ATA_SK_NOT_READY) && (SensePtr->addnl_sense_code == ATA_ASC_NO_MEDIA)) {
 | 
						|
      IsNoMedia = TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    SensePtr++;
 | 
						|
  }
 | 
						|
 | 
						|
  return IsNoMedia;
 | 
						|
}
 | 
						|
 | 
						|
/**  
 | 
						|
  Check if device state is unclear according to sense data.
 | 
						|
 | 
						|
  @param[in]  SenseData   Pointer to sense data.
 | 
						|
  @param[in]  SenseCounts Count of sense data.
 | 
						|
 | 
						|
  @retval TRUE    Device state is unclear
 | 
						|
  @retval FALSE   Device state is clear  
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsDeviceStateUnclear (
 | 
						|
  IN  ATAPI_REQUEST_SENSE_DATA    *SenseData,
 | 
						|
  IN  UINTN                       SenseCounts
 | 
						|
  )
 | 
						|
{
 | 
						|
  ATAPI_REQUEST_SENSE_DATA  *SensePtr;
 | 
						|
  UINTN                     Index;
 | 
						|
  BOOLEAN                   Unclear;
 | 
						|
 | 
						|
  Unclear  = FALSE;
 | 
						|
 | 
						|
  SensePtr  = SenseData;
 | 
						|
 | 
						|
  for (Index = 0; Index < SenseCounts; Index++) {
 | 
						|
 | 
						|
    if (SensePtr->sense_key == 0x06) {
 | 
						|
      //
 | 
						|
      // Sense key is 0x06 means the device is just be reset or media just
 | 
						|
      // changed. The current state of the device is unclear.
 | 
						|
      //
 | 
						|
      Unclear = TRUE;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    SensePtr++;
 | 
						|
  }
 | 
						|
 | 
						|
  return Unclear;
 | 
						|
}
 | 
						|
 | 
						|
/**  
 | 
						|
  Check if there is media error according to sense data.
 | 
						|
 | 
						|
  @param[in]  SenseData   Pointer to sense data.
 | 
						|
  @param[in]  SenseCounts Count of sense data.
 | 
						|
 | 
						|
  @retval TRUE    Media error
 | 
						|
  @retval FALSE   No media error
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsMediaError (
 | 
						|
  IN  ATAPI_REQUEST_SENSE_DATA  *SenseData,
 | 
						|
  IN  UINTN                     SenseCounts
 | 
						|
  )
 | 
						|
{
 | 
						|
  ATAPI_REQUEST_SENSE_DATA  *SensePtr;
 | 
						|
  UINTN                     Index;
 | 
						|
  BOOLEAN                   IsError;
 | 
						|
 | 
						|
  IsError   = FALSE;
 | 
						|
 | 
						|
  SensePtr  = SenseData;
 | 
						|
 | 
						|
  for (Index = 0; Index < SenseCounts; Index++) {
 | 
						|
 | 
						|
    switch (SensePtr->sense_key) {
 | 
						|
 | 
						|
    case ATA_SK_MEDIUM_ERROR:
 | 
						|
      switch (SensePtr->addnl_sense_code) {
 | 
						|
      case ATA_ASC_MEDIA_ERR1:
 | 
						|
        //
 | 
						|
        // fall through
 | 
						|
        //
 | 
						|
      case ATA_ASC_MEDIA_ERR2:
 | 
						|
        //
 | 
						|
        // fall through
 | 
						|
        //
 | 
						|
      case ATA_ASC_MEDIA_ERR3:
 | 
						|
        //
 | 
						|
        // fall through
 | 
						|
        //
 | 
						|
      case ATA_ASC_MEDIA_ERR4:
 | 
						|
        IsError = TRUE;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    case ATA_SK_NOT_READY:
 | 
						|
      switch (SensePtr->addnl_sense_code) {
 | 
						|
      case ATA_ASC_MEDIA_UPSIDE_DOWN:
 | 
						|
        IsError = TRUE;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    SensePtr++;
 | 
						|
  }
 | 
						|
 | 
						|
  return IsError;
 | 
						|
}
 | 
						|
 | 
						|
/**  
 | 
						|
  Check if drive is ready according to sense data.
 | 
						|
 | 
						|
  @param[in]  SenseData   Pointer to sense data.
 | 
						|
  @param[in]  SenseCounts Count of sense data.
 | 
						|
  @param[out] NeedRetry   Indicate if retry is needed.
 | 
						|
 | 
						|
  @retval TRUE    Drive ready
 | 
						|
  @retval FALSE   Drive not ready
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsDriveReady (
 | 
						|
  IN  ATAPI_REQUEST_SENSE_DATA    *SenseData,
 | 
						|
  IN  UINTN                       SenseCounts,
 | 
						|
  OUT BOOLEAN                     *NeedRetry
 | 
						|
  )
 | 
						|
{
 | 
						|
  ATAPI_REQUEST_SENSE_DATA  *SensePtr;
 | 
						|
  UINTN                     Index;
 | 
						|
  BOOLEAN                   IsReady;
 | 
						|
 | 
						|
  IsReady     = TRUE;
 | 
						|
  *NeedRetry  = FALSE;
 | 
						|
 | 
						|
  SensePtr    = SenseData;
 | 
						|
 | 
						|
  for (Index = 0; Index < SenseCounts; Index++) {
 | 
						|
 | 
						|
    switch (SensePtr->sense_key) {
 | 
						|
 | 
						|
    case ATA_SK_NOT_READY:
 | 
						|
      switch (SensePtr->addnl_sense_code) {
 | 
						|
      case ATA_ASC_NOT_READY:
 | 
						|
        switch (SensePtr->addnl_sense_code_qualifier) {
 | 
						|
        case ATA_ASCQ_IN_PROGRESS:
 | 
						|
          IsReady     = FALSE;
 | 
						|
          *NeedRetry  = TRUE;
 | 
						|
          break;
 | 
						|
 | 
						|
        default:
 | 
						|
          IsReady     = FALSE;
 | 
						|
          *NeedRetry  = FALSE;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    SensePtr++;
 | 
						|
  }
 | 
						|
 | 
						|
  return IsReady;
 | 
						|
}
 |