mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 19:13:50 +00:00 
			
		
		
		
	 034ffda8b2
			
		
	
	
		034ffda8b2
		
	
	
	
	
		
			
			git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10849 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			512 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			512 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   This file implements ATA pass through transaction for ATA bus driver.
 | |
| 
 | |
|   This file implements the low level execution of ATA pass through transaction.
 | |
|   It transforms the high level identity, read/write, reset command to ATA pass
 | |
|   through command and protocol. 
 | |
|     
 | |
|   Copyright (c) 2009 - 2010, 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 "AtaBus.h"
 | |
| 
 | |
| //
 | |
| // Look up table (UdmaValid, IsWrite) for EFI_ATA_PASS_THRU_CMD_PROTOCOL
 | |
| //
 | |
| EFI_ATA_PASS_THRU_CMD_PROTOCOL mAtaPassThruCmdProtocols[][2] = {
 | |
|   {
 | |
|     EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN,
 | |
|     EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT
 | |
|   },
 | |
|   {
 | |
|     EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN,
 | |
|     EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT,
 | |
|   }
 | |
| };
 | |
| 
 | |
| //
 | |
| // Look up table (UdmaValid, Lba48Bit, IsIsWrite) for ATA_CMD
 | |
| //
 | |
| UINT8 mAtaCommands[][2][2] = {
 | |
|   {
 | |
|     {
 | |
|       ATA_CMD_READ_SECTORS,            // 28-bit LBA; PIO read
 | |
|       ATA_CMD_WRITE_SECTORS            // 28-bit LBA; PIO write
 | |
|     },
 | |
|     {
 | |
|       ATA_CMD_READ_SECTORS_EXT,        // 48-bit LBA; PIO read
 | |
|       ATA_CMD_WRITE_SECTORS_EXT        // 48-bit LBA; PIO write
 | |
|     }
 | |
|   },
 | |
|   {
 | |
|     {
 | |
|       ATA_CMD_READ_DMA,                // 28-bit LBA; DMA read
 | |
|       ATA_CMD_WRITE_DMA                // 28-bit LBA; DMA write
 | |
|     },
 | |
|     {
 | |
|       ATA_CMD_READ_DMA_EXT,            // 48-bit LBA; DMA read
 | |
|       ATA_CMD_WRITE_DMA_EXT            // 48-bit LBA; DMA write
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| //
 | |
| // Look up table (Lba48Bit) for maximum transfer block number
 | |
| //
 | |
| UINTN mMaxTransferBlockNumber[] = {
 | |
|   MAX_28BIT_TRANSFER_BLOCK_NUM,
 | |
|   MAX_48BIT_TRANSFER_BLOCK_NUM
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.PassThru().
 | |
| 
 | |
|   This function wraps the PassThru() invocation for ATA pass through function
 | |
|   for an ATA device. It assembles the ATA pass through command packet for ATA
 | |
|   transaction.
 | |
| 
 | |
|   @param  AtaDevice         The ATA child device involved for the operation.
 | |
| 
 | |
|   @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru().
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| AtaDevicePassThru (
 | |
|   IN OUT ATA_DEVICE                       *AtaDevice
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                              Status;
 | |
|   EFI_ATA_PASS_THRU_PROTOCOL              *AtaPassThru;
 | |
|   EFI_ATA_PASS_THRU_COMMAND_PACKET        *Packet;
 | |
| 
 | |
|   //
 | |
|   // Assemble packet
 | |
|   //
 | |
|   Packet = &AtaDevice->Packet;
 | |
|   Packet->Asb = AtaDevice->Asb;
 | |
|   Packet->Acb = &AtaDevice->Acb;
 | |
|   Packet->Timeout = ATA_TIMEOUT;
 | |
| 
 | |
|   AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;
 | |
| 
 | |
|   Status = AtaPassThru->PassThru (
 | |
|                           AtaPassThru,
 | |
|                           AtaDevice->Port,
 | |
|                           AtaDevice->PortMultiplierPort,
 | |
|                           Packet,
 | |
|                           NULL
 | |
|                           );
 | |
|   //
 | |
|   // Ensure ATA pass through caller and callee have the same
 | |
|   // interpretation of ATA pass through protocol. 
 | |
|   //
 | |
|   ASSERT (Status != EFI_INVALID_PARAMETER);
 | |
|   ASSERT (Status != EFI_BAD_BUFFER_SIZE);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.ResetDevice().
 | |
| 
 | |
|   This function wraps the ResetDevice() invocation for ATA pass through function
 | |
|   for an ATA device. 
 | |
| 
 | |
|   @param  AtaDevice         The ATA child device involved for the operation.
 | |
| 
 | |
|   @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru().
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ResetAtaDevice (
 | |
|   IN ATA_DEVICE                           *AtaDevice
 | |
|   )
 | |
| {
 | |
|   EFI_ATA_PASS_THRU_PROTOCOL              *AtaPassThru;
 | |
|   
 | |
|   AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;
 | |
|   
 | |
|   return AtaPassThru->ResetDevice (
 | |
|                         AtaPassThru,
 | |
|                         AtaDevice->Port,
 | |
|                         AtaDevice->PortMultiplierPort
 | |
|                         );
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Prints ATA model name to ATA device structure.
 | |
| 
 | |
|   This function converts ATA device model name from ATA identify data 
 | |
|   to a string in ATA device structure. It needs to change the character
 | |
|   order in the original model name string.
 | |
| 
 | |
|   @param  AtaDevice         The ATA child device involved for the operation.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| PrintAtaModelName (
 | |
|   IN OUT ATA_DEVICE  *AtaDevice
 | |
|   )
 | |
| {
 | |
|   UINTN   Index;
 | |
|   CHAR8   *Source;
 | |
|   CHAR16  *Destination;
 | |
| 
 | |
|   Source = AtaDevice->IdentifyData->ModelName;
 | |
|   Destination = AtaDevice->ModelName;
 | |
| 
 | |
|   //
 | |
|   // Swap the byte order in the original module name.
 | |
|   //
 | |
|   for (Index = 0; Index < MAX_MODEL_NAME_LEN; Index += 2) {
 | |
|     Destination[Index]      = Source[Index + 1];
 | |
|     Destination[Index + 1]  = Source[Index];
 | |
|   }
 | |
|   AtaDevice->ModelName[MAX_MODEL_NAME_LEN] = L'\0';
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Gets ATA device Capacity according to ATA 6.
 | |
| 
 | |
|   This function returns the capacity of the ATA device if it follows
 | |
|   ATA 6 to support 48 bit addressing.
 | |
| 
 | |
|   @param  AtaDevice         The ATA child device involved for the operation.
 | |
| 
 | |
|   @return The capacity of the ATA device or 0 if the device does not support
 | |
|           48-bit addressing defined in ATA 6.
 | |
| 
 | |
| **/
 | |
| EFI_LBA
 | |
| GetAtapi6Capacity (
 | |
|   IN ATA_DEVICE                 *AtaDevice
 | |
|   )
 | |
| {
 | |
|   EFI_LBA                       Capacity;
 | |
|   EFI_LBA                       TmpLba;
 | |
|   UINTN                         Index;
 | |
|   ATA_IDENTIFY_DATA             *IdentifyData;
 | |
| 
 | |
|   IdentifyData = AtaDevice->IdentifyData;
 | |
|   if ((IdentifyData->command_set_supported_83 & BIT10) == 0) {
 | |
|     //
 | |
|     // The device doesn't support 48 bit addressing
 | |
|     //
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 48 bit address feature set is supported, get maximum capacity
 | |
|   //
 | |
|   Capacity = 0;
 | |
|   for (Index = 0; Index < 4; Index++) {
 | |
|     //
 | |
|     // Lower byte goes first: word[100] is the lowest word, word[103] is highest
 | |
|     //
 | |
|     TmpLba = IdentifyData->maximum_lba_for_48bit_addressing[Index];
 | |
|     Capacity |= LShiftU64 (TmpLba, 16 * Index);
 | |
|   }
 | |
| 
 | |
|   return Capacity;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Identifies ATA device via the Identify data.
 | |
| 
 | |
|   This function identifies the ATA device and initializes the Media information in 
 | |
|   Block IO protocol interface.
 | |
| 
 | |
|   @param  AtaDevice         The ATA child device involved for the operation.
 | |
| 
 | |
|   @retval EFI_UNSUPPORTED   The device is not a valid ATA device (hard disk).
 | |
|   @retval EFI_SUCCESS       The device is successfully identified and Media information
 | |
|                             is correctly initialized.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IdentifyAtaDevice (
 | |
|   IN OUT ATA_DEVICE                 *AtaDevice
 | |
|   )
 | |
| {
 | |
|   ATA_IDENTIFY_DATA                 *IdentifyData;
 | |
|   EFI_BLOCK_IO_MEDIA                *BlockMedia;
 | |
|   EFI_LBA                           Capacity;
 | |
|   UINT16                            PhyLogicSectorSupport;
 | |
|   UINT16                            UdmaMode;
 | |
| 
 | |
|   IdentifyData = AtaDevice->IdentifyData;
 | |
| 
 | |
|   if ((IdentifyData->config & BIT15) != 0) {
 | |
|     //
 | |
|     // This is not an hard disk
 | |
|     //
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check whether the WORD 88 (supported UltraDMA by drive) is valid
 | |
|   //
 | |
|   if ((IdentifyData->field_validity & BIT2) != 0) {
 | |
|     UdmaMode = IdentifyData->ultra_dma_mode;
 | |
|     if ((UdmaMode & (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6)) != 0) {
 | |
|       //
 | |
|       // If BIT0~BIT6 is selected, then UDMA is supported
 | |
|       //
 | |
|       AtaDevice->UdmaValid = TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Capacity = GetAtapi6Capacity (AtaDevice);
 | |
|   if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {
 | |
|     //
 | |
|     // Capacity exceeds 120GB. 48-bit addressing is really needed
 | |
|     //
 | |
|     AtaDevice->Lba48Bit = TRUE;
 | |
|   } else {
 | |
|     //
 | |
|     // This is a hard disk <= 120GB capacity, treat it as normal hard disk
 | |
|     //
 | |
|     Capacity = ((UINT32)IdentifyData->user_addressable_sectors_hi << 16) | IdentifyData->user_addressable_sectors_lo;
 | |
|     AtaDevice->Lba48Bit = FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Block Media Information:
 | |
|   //
 | |
|   BlockMedia = &AtaDevice->BlockMedia;
 | |
|   BlockMedia->LastBlock = Capacity - 1;
 | |
|   BlockMedia->IoAlign = AtaDevice->AtaBusDriverData->AtaPassThru->Mode->IoAlign;
 | |
|   //
 | |
|   // Check whether Long Physical Sector Feature is supported
 | |
|   //
 | |
|   PhyLogicSectorSupport = IdentifyData->phy_logic_sector_support;
 | |
|   if ((PhyLogicSectorSupport & (BIT14 | BIT15)) == BIT14) {
 | |
|     //
 | |
|     // Check whether one physical block contains multiple physical blocks
 | |
|     //
 | |
|     if ((PhyLogicSectorSupport & BIT13) != 0) {
 | |
|       BlockMedia->LogicalBlocksPerPhysicalBlock = (UINT32) (1 << (PhyLogicSectorSupport & 0x000f));
 | |
|       //
 | |
|       // Check lowest alignment of logical blocks within physical block
 | |
|       //
 | |
|       if ((IdentifyData->alignment_logic_in_phy_blocks & (BIT14 | BIT15)) == BIT14) {
 | |
|         BlockMedia->LowestAlignedLba = (EFI_LBA) ((BlockMedia->LogicalBlocksPerPhysicalBlock - ((UINT32)IdentifyData->alignment_logic_in_phy_blocks & 0x3fff)) %
 | |
|           BlockMedia->LogicalBlocksPerPhysicalBlock);
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // Check logical block size
 | |
|     //
 | |
|     if ((PhyLogicSectorSupport & BIT12) != 0) {
 | |
|       BlockMedia->BlockSize = (UINT32) (((IdentifyData->logic_sector_size_hi << 16) | IdentifyData->logic_sector_size_lo) * sizeof (UINT16));
 | |
|     }
 | |
|     AtaDevice->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;
 | |
|   }
 | |
|   //
 | |
|   // Get ATA model name from identify data structure. 
 | |
|   //
 | |
|   PrintAtaModelName (AtaDevice); 
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Discovers whether it is a valid ATA device.
 | |
| 
 | |
|   This function issues ATA_CMD_IDENTIFY_DRIVE command to the ATA device to identify it.
 | |
|   If the command is executed successfully, it then identifies it and initializes
 | |
|   the Media information in Block IO protocol interface.
 | |
| 
 | |
|   @param  AtaDevice         The ATA child device involved for the operation.
 | |
| 
 | |
|   @retval EFI_SUCCESS       The device is successfully identified and Media information
 | |
|                             is correctly initialized.
 | |
|   @return others            Some error occurs when discovering the ATA device. 
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DiscoverAtaDevice (
 | |
|   IN OUT ATA_DEVICE                 *AtaDevice
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   EFI_ATA_COMMAND_BLOCK             *Acb;
 | |
|   EFI_ATA_PASS_THRU_COMMAND_PACKET  *Packet;
 | |
|   UINTN                             Retry;
 | |
| 
 | |
|   //
 | |
|   // Prepare for ATA command block.
 | |
|   //
 | |
|   Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb));
 | |
|   Acb->AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
 | |
|   Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort << 4)); 
 | |
| 
 | |
|   //
 | |
|   // Prepare for ATA pass through packet.
 | |
|   //
 | |
|   Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet));
 | |
|   Packet->InDataBuffer = AtaDevice->IdentifyData;
 | |
|   Packet->InTransferLength = sizeof (*AtaDevice->IdentifyData);
 | |
|   Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN;
 | |
|   Packet->Length = EFI_ATA_PASS_THRU_LENGTH_BYTES | EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;
 | |
| 
 | |
|   Retry = MAX_RETRY_TIMES;
 | |
|   do {
 | |
|     Status = AtaDevicePassThru (AtaDevice);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // The command is issued successfully
 | |
|       //
 | |
|       Status = IdentifyAtaDevice (AtaDevice);
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
|   } while (Retry-- > 0);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Transfer data from ATA device.
 | |
| 
 | |
|   This function performs one ATA pass through transaction to transfer data from/to
 | |
|   ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru
 | |
|   interface of ATA pass through.
 | |
| 
 | |
|   @param  AtaDevice         The ATA child device involved for the operation.
 | |
|   @param  Buffer            The pointer to the current transaction buffer.
 | |
|   @param  StartLba          The starting logical block address to be accessed.
 | |
|   @param  TransferLength    The block number or sector count of the transfer.
 | |
|   @param  IsWrite           Indicates whether it is a write operation.
 | |
| 
 | |
|   @retval EFI_SUCCESS       The data transfer is complete successfully.
 | |
|   @return others            Some error occurs when transferring data. 
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| TransferAtaDevice (
 | |
|   IN OUT ATA_DEVICE                 *AtaDevice,
 | |
|   IN OUT VOID                       *Buffer,
 | |
|   IN EFI_LBA                        StartLba,
 | |
|   IN UINT32                         TransferLength,
 | |
|   IN BOOLEAN                        IsWrite
 | |
|   )
 | |
| {
 | |
|   EFI_ATA_COMMAND_BLOCK             *Acb;
 | |
|   EFI_ATA_PASS_THRU_COMMAND_PACKET  *Packet;
 | |
| 
 | |
|   //
 | |
|   // Ensure AtaDevice->UdmaValid, AtaDevice->Lba48Bit and IsWrite are valid boolean values 
 | |
|   //
 | |
|   ASSERT ((UINTN) AtaDevice->UdmaValid < 2);
 | |
|   ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);
 | |
|   ASSERT ((UINTN) IsWrite < 2);
 | |
|   //
 | |
|   // Prepare for ATA command block.
 | |
|   //
 | |
|   Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb));
 | |
|   Acb->AtaCommand = mAtaCommands[AtaDevice->UdmaValid][AtaDevice->Lba48Bit][IsWrite];
 | |
|   Acb->AtaSectorNumber = (UINT8) StartLba;
 | |
|   Acb->AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8);
 | |
|   Acb->AtaCylinderHigh = (UINT8) RShiftU64 (StartLba, 16);
 | |
|   Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort << 4)); 
 | |
|   Acb->AtaSectorCount = (UINT8) TransferLength;
 | |
|   if (AtaDevice->Lba48Bit) {
 | |
|     Acb->AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24);
 | |
|     Acb->AtaCylinderLowExp = (UINT8) RShiftU64 (StartLba, 32);
 | |
|     Acb->AtaCylinderHighExp = (UINT8) RShiftU64 (StartLba, 40);
 | |
|     Acb->AtaSectorCountExp = (UINT8) (TransferLength >> 8);
 | |
|   } else {
 | |
|     Acb->AtaDeviceHead = (UINT8) (Acb->AtaDeviceHead | RShiftU64 (StartLba, 24));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Prepare for ATA pass through packet.
 | |
|   //
 | |
|   Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet));
 | |
|   if (IsWrite) {
 | |
|     Packet->OutDataBuffer = Buffer;
 | |
|     Packet->OutTransferLength = TransferLength;
 | |
|   } else {
 | |
|     Packet->InDataBuffer = Buffer;
 | |
|     Packet->InTransferLength = TransferLength;
 | |
|   }
 | |
|   Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsWrite];
 | |
|   Packet->Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;
 | |
| 
 | |
|   return AtaDevicePassThru (AtaDevice); 
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Read or write a number of blocks from ATA device.
 | |
| 
 | |
|   This function performs ATA pass through transactions to read/write data from/to
 | |
|   ATA device. It may separate the read/write request into several ATA pass through
 | |
|   transactions.
 | |
| 
 | |
|   @param  AtaDevice         The ATA child device involved for the operation.
 | |
|   @param  Buffer            The pointer to the current transaction buffer.
 | |
|   @param  StartLba          The starting logical block address to be accessed.
 | |
|   @param  NumberOfBlocks    The block number or sector count of the transfer.
 | |
|   @param  IsWrite           Indicates whether it is a write operation.
 | |
| 
 | |
|   @retval EFI_SUCCESS       The data transfer is complete successfully.
 | |
|   @return others            Some error occurs when transferring data. 
 | |
| 
 | |
| **/
 | |
| EFI_STATUS 
 | |
| AccessAtaDevice(
 | |
|   IN OUT ATA_DEVICE                 *AtaDevice,
 | |
|   IN OUT UINT8                      *Buffer,
 | |
|   IN EFI_LBA                        StartLba,
 | |
|   IN UINTN                          NumberOfBlocks,
 | |
|   IN BOOLEAN                        IsWrite
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   UINTN                             MaxTransferBlockNumber;
 | |
|   UINTN                             TransferBlockNumber;
 | |
|   UINTN                             BlockSize;
 | |
|  
 | |
|   //
 | |
|   // Ensure AtaDevice->Lba48Bit is a valid boolean value 
 | |
|   //
 | |
|   ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);
 | |
|   MaxTransferBlockNumber = mMaxTransferBlockNumber[AtaDevice->Lba48Bit];
 | |
|   BlockSize = AtaDevice->BlockMedia.BlockSize;
 | |
|   do {
 | |
|     if (NumberOfBlocks > MaxTransferBlockNumber) {
 | |
|       TransferBlockNumber = MaxTransferBlockNumber;
 | |
|       NumberOfBlocks -= MaxTransferBlockNumber;
 | |
|     } else  {
 | |
|       TransferBlockNumber = NumberOfBlocks;
 | |
|       NumberOfBlocks  = 0;
 | |
|     }
 | |
| 
 | |
|     Status = TransferAtaDevice (AtaDevice, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|     StartLba += TransferBlockNumber;
 | |
|     Buffer   += TransferBlockNumber * BlockSize;
 | |
|   } while (NumberOfBlocks > 0);
 | |
| 
 | |
|   return Status;
 | |
| }
 |