mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-31 03:03:46 +01:00 
			
		
		
		
	Fix various typos in documentation, comments and debug strings. Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Hao A Wu <hao.a.wu@intel.com> Cc: Ray Ni <ray.ni@intel.com> Signed-off-by: Antoine Coeur <coeur@gmx.fr> Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com> Acked-by: Liming Gao <liming.gao@intel.com> Signed-off-by: Philippe Mathieu-Daude <philmd@redhat.com> Message-Id: <20200207010831.9046-12-philmd@redhat.com> [lersek@redhat.com: replace EFI_D_xxx w/ DEBUG_xxx to shut up PatchCheck]
		
			
				
	
	
		
			1068 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1068 lines
		
	
	
		
			37 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.
 | |
| 
 | |
|   NOTE: This file also implements the StorageSecurityCommandProtocol(SSP). For input
 | |
|   parameter SecurityProtocolSpecificData, ATA spec has no explicitly definition
 | |
|   for Security Protocol Specific layout. This implementation uses big endian for
 | |
|   Cylinder register.
 | |
| 
 | |
|   Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
|   (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "AtaBus.h"
 | |
| 
 | |
| #define ATA_CMD_TRUST_NON_DATA    0x5B
 | |
| #define ATA_CMD_TRUST_RECEIVE     0x5C
 | |
| #define ATA_CMD_TRUST_RECEIVE_DMA 0x5D
 | |
| #define ATA_CMD_TRUST_SEND        0x5E
 | |
| #define ATA_CMD_TRUST_SEND_DMA    0x5F
 | |
| 
 | |
| //
 | |
| // 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 (UdmaValid, IsTrustSend) for ATA_CMD
 | |
| //
 | |
| UINT8 mAtaTrustCommands[2][2] = {
 | |
|   {
 | |
|     ATA_CMD_TRUST_RECEIVE,            // PIO read
 | |
|     ATA_CMD_TRUST_SEND                // PIO write
 | |
|   },
 | |
|   {
 | |
|     ATA_CMD_TRUST_RECEIVE_DMA,        // DMA read
 | |
|     ATA_CMD_TRUST_SEND_DMA            // 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[in, out]  AtaDevice   The ATA child device involved for the operation.
 | |
|   @param[in, out]  TaskPacket  Pointer to a Pass Thru Command Packet. Optional,
 | |
|                                if it is NULL, blocking mode, and use the packet
 | |
|                                in AtaDevice. If it is not NULL, non blocking mode,
 | |
|                                and pass down this Packet.
 | |
|   @param[in, out]  Event       If Event is NULL, then blocking I/O is performed.
 | |
|                                If Event is not NULL and non-blocking I/O is
 | |
|                                supported,then non-blocking I/O is performed,
 | |
|                                and Event will be signaled when the write
 | |
|                                request is completed.
 | |
| 
 | |
|   @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru().
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| AtaDevicePassThru (
 | |
|   IN OUT ATA_DEVICE                       *AtaDevice,
 | |
|   IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *TaskPacket, OPTIONAL
 | |
|   IN OUT EFI_EVENT                        Event OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                              Status;
 | |
|   EFI_ATA_PASS_THRU_PROTOCOL              *AtaPassThru;
 | |
|   EFI_ATA_PASS_THRU_COMMAND_PACKET        *Packet;
 | |
| 
 | |
|   //
 | |
|   // Assemble packet. If it is non blocking mode, the Ata driver should keep each
 | |
|   // subtask and clean them when the event is signaled.
 | |
|   //
 | |
|   if (TaskPacket != NULL) {
 | |
|     Packet = TaskPacket;
 | |
|     Packet->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (EFI_ATA_STATUS_BLOCK));
 | |
|     if (Packet->Asb == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     CopyMem (Packet->Asb, AtaDevice->Asb, sizeof (EFI_ATA_STATUS_BLOCK));
 | |
|     Packet->Acb = AllocateCopyPool (sizeof (EFI_ATA_COMMAND_BLOCK), &AtaDevice->Acb);
 | |
|   } else {
 | |
|     Packet = &AtaDevice->Packet;
 | |
|     Packet->Asb = AtaDevice->Asb;
 | |
|     Packet->Acb = &AtaDevice->Acb;
 | |
|   }
 | |
| 
 | |
|   AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;
 | |
| 
 | |
|   Status = AtaPassThru->PassThru (
 | |
|                           AtaPassThru,
 | |
|                           AtaDevice->Port,
 | |
|                           AtaDevice->PortMultiplierPort,
 | |
|                           Packet,
 | |
|                           Event
 | |
|                           );
 | |
|   //
 | |
|   // 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;
 | |
| 
 | |
|   //
 | |
|   // Report Status Code to indicate reset happens
 | |
|   //
 | |
|   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
 | |
|     AtaDevice->AtaBusDriverData->ParentDevicePath
 | |
|     );
 | |
| 
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((EFI_D_INFO, "AtaBus - Identify Device: Port %x PortMultiplierPort %x\n", AtaDevice->Port, AtaDevice->PortMultiplierPort));
 | |
| 
 | |
|   //
 | |
|   // 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 (EFI_ATA_COMMAND_BLOCK));
 | |
|   Acb->AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
 | |
|   Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort == 0xFFFF ? 0 : (AtaDevice->PortMultiplierPort << 4)));
 | |
| 
 | |
|   //
 | |
|   // Prepare for ATA pass through packet.
 | |
|   //
 | |
|   Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
 | |
|   Packet->InDataBuffer = AtaDevice->IdentifyData;
 | |
|   Packet->InTransferLength = sizeof (ATA_IDENTIFY_DATA);
 | |
|   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;
 | |
|   Packet->Timeout  = ATA_TIMEOUT;
 | |
| 
 | |
|   Retry = MAX_RETRY_TIMES;
 | |
|   do {
 | |
|     Status = AtaDevicePassThru (AtaDevice, NULL, NULL);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // The command is issued successfully
 | |
|       //
 | |
|       Status = IdentifyAtaDevice (AtaDevice);
 | |
|       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[in, out]  AtaDevice       The ATA child device involved for the operation.
 | |
|   @param[in, out]  TaskPacket      Pointer to a Pass Thru Command Packet. Optional,
 | |
|                                    if it is NULL, blocking mode, and use the packet
 | |
|                                    in AtaDevice. If it is not NULL, non blocking mode,
 | |
|                                    and pass down this Packet.
 | |
|   @param[in, out]  Buffer          The pointer to the current transaction buffer.
 | |
|   @param[in]       StartLba        The starting logical block address to be accessed.
 | |
|   @param[in]       TransferLength  The block number or sector count of the transfer.
 | |
|   @param[in]       IsWrite         Indicates whether it is a write operation.
 | |
|   @param[in]       Event           If Event is NULL, then blocking I/O is performed.
 | |
|                                    If Event is not NULL and non-blocking I/O is
 | |
|                                    supported,then non-blocking I/O is performed,
 | |
|                                    and Event will be signaled when the write
 | |
|                                    request is completed.
 | |
| 
 | |
|   @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 EFI_ATA_PASS_THRU_COMMAND_PACKET *TaskPacket, OPTIONAL
 | |
|   IN OUT VOID                             *Buffer,
 | |
|   IN EFI_LBA                              StartLba,
 | |
|   IN UINT32                               TransferLength,
 | |
|   IN BOOLEAN                              IsWrite,
 | |
|   IN EFI_EVENT                            Event OPTIONAL
 | |
|   )
 | |
| {
 | |
|   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 (EFI_ATA_COMMAND_BLOCK));
 | |
|   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 == 0xFFFF ? 0 : (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.
 | |
|   //
 | |
|   if (TaskPacket != NULL) {
 | |
|     Packet = ZeroMem (TaskPacket, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
 | |
|   } else {
 | |
|     Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_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;
 | |
|   //
 | |
|   // |------------------------|-----------------|------------------------|-----------------|
 | |
|   // | ATA PIO Transfer Mode  |  Transfer Rate  | ATA DMA Transfer Mode  |  Transfer Rate  |
 | |
|   // |------------------------|-----------------|------------------------|-----------------|
 | |
|   // |       PIO Mode 0       |  3.3Mbytes/sec  | Single-word DMA Mode 0 |  2.1Mbytes/sec  |
 | |
|   // |------------------------|-----------------|------------------------|-----------------|
 | |
|   // |       PIO Mode 1       |  5.2Mbytes/sec  | Single-word DMA Mode 1 |  4.2Mbytes/sec  |
 | |
|   // |------------------------|-----------------|------------------------|-----------------|
 | |
|   // |       PIO Mode 2       |  8.3Mbytes/sec  | Single-word DMA Mode 2 |  8.4Mbytes/sec  |
 | |
|   // |------------------------|-----------------|------------------------|-----------------|
 | |
|   // |       PIO Mode 3       | 11.1Mbytes/sec  | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |
 | |
|   // |------------------------|-----------------|------------------------|-----------------|
 | |
|   // |       PIO Mode 4       | 16.6Mbytes/sec  | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |
 | |
|   // |------------------------|-----------------|------------------------|-----------------|
 | |
|   //
 | |
|   // As AtaBus is used to manage ATA devices, we have to use the lowest transfer rate to
 | |
|   // calculate the possible maximum timeout value for each read/write operation.
 | |
|   // The timeout value is rounded up to nearest integer and here an additional 30s is added
 | |
|   // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
 | |
|   // commands in the Standby/Idle mode.
 | |
|   //
 | |
|   if (AtaDevice->UdmaValid) {
 | |
|     //
 | |
|     // Calculate the maximum timeout value for DMA read/write operation.
 | |
|     //
 | |
|     Packet->Timeout  = EFI_TIMER_PERIOD_SECONDS (DivU64x32 (MultU64x32 (TransferLength, AtaDevice->BlockMedia.BlockSize), 2100000) + 31);
 | |
|   } else {
 | |
|     //
 | |
|     // Calculate the maximum timeout value for PIO read/write operation
 | |
|     //
 | |
|     Packet->Timeout  = EFI_TIMER_PERIOD_SECONDS (DivU64x32 (MultU64x32 (TransferLength, AtaDevice->BlockMedia.BlockSize), 3300000) + 31);
 | |
|   }
 | |
| 
 | |
|   return AtaDevicePassThru (AtaDevice, TaskPacket, Event);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Free SubTask.
 | |
| 
 | |
|   @param[in, out]  Task      Pointer to task to be freed.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| FreeAtaSubTask (
 | |
|   IN OUT ATA_BUS_ASYN_SUB_TASK  *Task
 | |
|   )
 | |
| {
 | |
|   if (Task->Packet.Asb != NULL) {
 | |
|     FreeAlignedBuffer (Task->Packet.Asb, sizeof (EFI_ATA_STATUS_BLOCK));
 | |
|   }
 | |
|   if (Task->Packet.Acb != NULL) {
 | |
|     FreePool (Task->Packet.Acb);
 | |
|   }
 | |
| 
 | |
|   FreePool (Task);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Terminate any in-flight non-blocking I/O requests by signaling an EFI_ABORTED
 | |
|   in the TransactionStatus member of the EFI_BLOCK_IO2_TOKEN for the non-blocking
 | |
|   I/O. After that it is safe to free any Token or Buffer data structures that
 | |
|   were allocated to initiate the non-blockingI/O requests that were in-flight for
 | |
|   this device.
 | |
| 
 | |
|   @param[in]  AtaDevice     The ATA child device involved for the operation.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| AtaTerminateNonBlockingTask (
 | |
|   IN ATA_DEVICE               *AtaDevice
 | |
|   )
 | |
| {
 | |
|   BOOLEAN               SubTaskEmpty;
 | |
|   EFI_TPL               OldTpl;
 | |
|   ATA_BUS_ASYN_TASK     *AtaTask;
 | |
|   LIST_ENTRY            *Entry;
 | |
|   LIST_ENTRY            *List;
 | |
| 
 | |
|   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | |
|   //
 | |
|   // Abort all executing tasks from now.
 | |
|   //
 | |
|   AtaDevice->Abort = TRUE;
 | |
| 
 | |
|   List = &AtaDevice->AtaTaskList;
 | |
|   for (Entry = GetFirstNode (List); !IsNull (List, Entry);) {
 | |
|     AtaTask  = ATA_ASYN_TASK_FROM_ENTRY (Entry);
 | |
|     AtaTask->Token->TransactionStatus = EFI_ABORTED;
 | |
|     gBS->SignalEvent (AtaTask->Token->Event);
 | |
| 
 | |
|     Entry = RemoveEntryList (Entry);
 | |
|     FreePool (AtaTask);
 | |
|   }
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|   do {
 | |
|     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | |
|     //
 | |
|     // Wait for executing subtasks done.
 | |
|     //
 | |
|     SubTaskEmpty = IsListEmpty (&AtaDevice->AtaSubTaskList);
 | |
|     gBS->RestoreTPL (OldTpl);
 | |
|   } while (!SubTaskEmpty);
 | |
| 
 | |
|   //
 | |
|   // Aborting operation has been done. From now on, don't need to abort normal operation.
 | |
|   //
 | |
|   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | |
|   AtaDevice->Abort = FALSE;
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Call back function when the event is signaled.
 | |
| 
 | |
|   @param[in]  Event     The Event this notify function registered to.
 | |
|   @param[in]  Context   Pointer to the context data registered to the
 | |
|                         Event.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| AtaNonBlockingCallBack (
 | |
|   IN EFI_EVENT                Event,
 | |
|   IN VOID                     *Context
 | |
|   )
 | |
| {
 | |
|   ATA_BUS_ASYN_SUB_TASK *Task;
 | |
|   ATA_BUS_ASYN_TASK     *AtaTask;
 | |
|   ATA_DEVICE            *AtaDevice;
 | |
|   LIST_ENTRY            *Entry;
 | |
|   EFI_STATUS            Status;
 | |
| 
 | |
|   Task = (ATA_BUS_ASYN_SUB_TASK *) Context;
 | |
|   gBS->CloseEvent (Event);
 | |
| 
 | |
|   AtaDevice = Task->AtaDevice;
 | |
| 
 | |
|   //
 | |
|   // Check the command status.
 | |
|   // If there is error during the sub task source allocation, the error status
 | |
|   // should be returned to the caller directly, so here the Task->Token may already
 | |
|   // be deleted by the caller and no need to update the status.
 | |
|   //
 | |
|   if ((!(*Task->IsError)) && ((Task->Packet.Asb->AtaStatus & 0x01) == 0x01)) {
 | |
|     Task->Token->TransactionStatus = EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   if (AtaDevice->Abort) {
 | |
|     Task->Token->TransactionStatus = EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((
 | |
|     EFI_D_BLKIO,
 | |
|     "NON-BLOCKING EVENT FINISHED!- STATUS = %r\n",
 | |
|     Task->Token->TransactionStatus
 | |
|     ));
 | |
| 
 | |
|   //
 | |
|   // Reduce the SubEventCount, till it comes to zero.
 | |
|   //
 | |
|   (*Task->UnsignalledEventCount) --;
 | |
|   DEBUG ((EFI_D_BLKIO, "UnsignalledEventCount = %d\n", *Task->UnsignalledEventCount));
 | |
| 
 | |
|   //
 | |
|   // Remove the SubTask from the Task list.
 | |
|   //
 | |
|   RemoveEntryList (&Task->TaskEntry);
 | |
|   if ((*Task->UnsignalledEventCount) == 0) {
 | |
|     //
 | |
|     // All Sub tasks are done, then signal the upper layer event.
 | |
|     // Except there is error during the sub task source allocation.
 | |
|     //
 | |
|     if (!(*Task->IsError)) {
 | |
|       gBS->SignalEvent (Task->Token->Event);
 | |
|       DEBUG ((EFI_D_BLKIO, "Signal the upper layer event!\n"));
 | |
|     }
 | |
| 
 | |
|     FreePool (Task->UnsignalledEventCount);
 | |
|     FreePool (Task->IsError);
 | |
| 
 | |
| 
 | |
|     //
 | |
|     // Finish all subtasks and move to the next task in AtaTaskList.
 | |
|     //
 | |
|     if (!IsListEmpty (&AtaDevice->AtaTaskList)) {
 | |
|       Entry   = GetFirstNode (&AtaDevice->AtaTaskList);
 | |
|       AtaTask = ATA_ASYN_TASK_FROM_ENTRY (Entry);
 | |
|       DEBUG ((EFI_D_BLKIO, "Start to embark a new Ata Task\n"));
 | |
|       DEBUG ((EFI_D_BLKIO, "AtaTask->NumberOfBlocks = %x; AtaTask->Token=%x\n", AtaTask->NumberOfBlocks, AtaTask->Token));
 | |
|       Status = AccessAtaDevice (
 | |
|                  AtaTask->AtaDevice,
 | |
|                  AtaTask->Buffer,
 | |
|                  AtaTask->StartLba,
 | |
|                  AtaTask->NumberOfBlocks,
 | |
|                  AtaTask->IsWrite,
 | |
|                  AtaTask->Token
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         AtaTask->Token->TransactionStatus = Status;
 | |
|         gBS->SignalEvent (AtaTask->Token->Event);
 | |
|       }
 | |
|       RemoveEntryList (Entry);
 | |
|       FreePool (AtaTask);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   DEBUG ((
 | |
|     EFI_D_BLKIO,
 | |
|     "PACKET INFO: Write=%s, Length=%x, LowCylinder=%x, HighCylinder=%x, SectionNumber=%x\n",
 | |
|     Task->Packet.OutDataBuffer != NULL ? L"YES" : L"NO",
 | |
|     Task->Packet.OutDataBuffer != NULL ? Task->Packet.OutTransferLength : Task->Packet.InTransferLength,
 | |
|     Task->Packet.Acb->AtaCylinderLow,
 | |
|     Task->Packet.Acb->AtaCylinderHigh,
 | |
|     Task->Packet.Acb->AtaSectorCount
 | |
|     ));
 | |
| 
 | |
|   //
 | |
|   // Free the buffer of SubTask.
 | |
|   //
 | |
|   FreeAtaSubTask (Task);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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[in, out]  AtaDevice       The ATA child device involved for the operation.
 | |
|   @param[in, out]  Buffer          The pointer to the current transaction buffer.
 | |
|   @param[in]       StartLba        The starting logical block address to be accessed.
 | |
|   @param[in]       NumberOfBlocks  The block number or sector count of the transfer.
 | |
|   @param[in]       IsWrite         Indicates whether it is a write operation.
 | |
|   @param[in, out]  Token           A pointer to the token associated with the transaction.
 | |
| 
 | |
|   @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,
 | |
|   IN OUT EFI_BLOCK_IO2_TOKEN        *Token
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                        Status;
 | |
|   UINTN                             MaxTransferBlockNumber;
 | |
|   UINTN                             TransferBlockNumber;
 | |
|   UINTN                             BlockSize;
 | |
|   ATA_BUS_ASYN_SUB_TASK             *SubTask;
 | |
|   UINTN                             *EventCount;
 | |
|   UINTN                             TempCount;
 | |
|   ATA_BUS_ASYN_TASK                 *AtaTask;
 | |
|   EFI_EVENT                         SubEvent;
 | |
|   UINTN                             Index;
 | |
|   BOOLEAN                           *IsError;
 | |
|   EFI_TPL                           OldTpl;
 | |
| 
 | |
|   TempCount  = 0;
 | |
|   Status     = EFI_SUCCESS;
 | |
|   EventCount = NULL;
 | |
|   IsError    = NULL;
 | |
|   Index      = 0;
 | |
|   SubTask    = NULL;
 | |
|   SubEvent   = NULL;
 | |
|   AtaTask    = NULL;
 | |
| 
 | |
|   //
 | |
|   // Ensure AtaDevice->Lba48Bit is a valid boolean value
 | |
|   //
 | |
|   ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);
 | |
|   MaxTransferBlockNumber = mMaxTransferBlockNumber[AtaDevice->Lba48Bit];
 | |
|   BlockSize              = AtaDevice->BlockMedia.BlockSize;
 | |
| 
 | |
|   //
 | |
|   // Initial the return status and shared account for Non Blocking.
 | |
|   //
 | |
|   if ((Token != NULL) && (Token->Event != NULL)) {
 | |
|     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | |
| 
 | |
|     if (!IsListEmpty (&AtaDevice->AtaSubTaskList)) {
 | |
|       AtaTask = AllocateZeroPool (sizeof (ATA_BUS_ASYN_TASK));
 | |
|       if (AtaTask == NULL) {
 | |
|         gBS->RestoreTPL (OldTpl);
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
|       AtaTask->AtaDevice      = AtaDevice;
 | |
|       AtaTask->Buffer         = Buffer;
 | |
|       AtaTask->IsWrite        = IsWrite;
 | |
|       AtaTask->NumberOfBlocks = NumberOfBlocks;
 | |
|       AtaTask->Signature      = ATA_TASK_SIGNATURE;
 | |
|       AtaTask->StartLba       = StartLba;
 | |
|       AtaTask->Token          = Token;
 | |
| 
 | |
|       InsertTailList (&AtaDevice->AtaTaskList, &AtaTask->TaskEntry);
 | |
|       gBS->RestoreTPL (OldTpl);
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|     gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|     Token->TransactionStatus = EFI_SUCCESS;
 | |
|     EventCount = AllocateZeroPool (sizeof (UINTN));
 | |
|     if (EventCount == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     IsError = AllocateZeroPool (sizeof (BOOLEAN));
 | |
|     if (IsError == NULL) {
 | |
|       FreePool (EventCount);
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     DEBUG ((EFI_D_BLKIO, "Allocation IsError Addr=%x\n", IsError));
 | |
|     *IsError = FALSE;
 | |
|     TempCount   = (NumberOfBlocks + MaxTransferBlockNumber - 1) / MaxTransferBlockNumber;
 | |
|     *EventCount = TempCount;
 | |
|     DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, NumberOfBlocks=%x\n", NumberOfBlocks));
 | |
|     DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, MaxTransferBlockNumber=%x\n", MaxTransferBlockNumber));
 | |
|     DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, EventCount=%x\n", TempCount));
 | |
|   } else {
 | |
|     while (!IsListEmpty (&AtaDevice->AtaTaskList) || !IsListEmpty (&AtaDevice->AtaSubTaskList)) {
 | |
|       //
 | |
|       // Stall for 100us.
 | |
|       //
 | |
|       MicroSecondDelay (100);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   do {
 | |
|     if (NumberOfBlocks > MaxTransferBlockNumber) {
 | |
|       TransferBlockNumber = MaxTransferBlockNumber;
 | |
|       NumberOfBlocks     -= MaxTransferBlockNumber;
 | |
|     } else  {
 | |
|       TransferBlockNumber = NumberOfBlocks;
 | |
|       NumberOfBlocks      = 0;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Create sub event for the sub ata task. Non-blocking mode.
 | |
|     //
 | |
|     if ((Token != NULL) && (Token->Event != NULL)) {
 | |
|       SubTask  = NULL;
 | |
|       SubEvent = NULL;
 | |
| 
 | |
|       SubTask = AllocateZeroPool (sizeof (ATA_BUS_ASYN_SUB_TASK));
 | |
|       if (SubTask == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto EXIT;
 | |
|       }
 | |
| 
 | |
|       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | |
|       SubTask->UnsignalledEventCount = EventCount;
 | |
|       SubTask->Signature             = ATA_SUB_TASK_SIGNATURE;
 | |
|       SubTask->AtaDevice             = AtaDevice;
 | |
|       SubTask->Token                 = Token;
 | |
|       SubTask->IsError               = IsError;
 | |
|       InsertTailList (&AtaDevice->AtaSubTaskList, &SubTask->TaskEntry);
 | |
|       gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|       Status = gBS->CreateEvent (
 | |
|                       EVT_NOTIFY_SIGNAL,
 | |
|                       TPL_NOTIFY,
 | |
|                       AtaNonBlockingCallBack,
 | |
|                       SubTask,
 | |
|                       &SubEvent
 | |
|                       );
 | |
|       //
 | |
|       // If resource allocation fail, the un-signalled event count should equal to
 | |
|       // the original one minus the unassigned subtasks number.
 | |
|       //
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto EXIT;
 | |
|       }
 | |
| 
 | |
|       Status = TransferAtaDevice (AtaDevice, &SubTask->Packet, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, SubEvent);
 | |
|     } else {
 | |
|       //
 | |
|       // Blocking Mode.
 | |
|       //
 | |
|       DEBUG ((EFI_D_BLKIO, "Blocking AccessAtaDevice, TransferBlockNumber=%x; StartLba = %x\n", TransferBlockNumber, StartLba));
 | |
|       Status = TransferAtaDevice (AtaDevice, NULL, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, NULL);
 | |
|     }
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto EXIT;
 | |
|     }
 | |
| 
 | |
|     Index++;
 | |
|     StartLba += TransferBlockNumber;
 | |
|     Buffer   += TransferBlockNumber * BlockSize;
 | |
|   } while (NumberOfBlocks > 0);
 | |
| 
 | |
| EXIT:
 | |
|   if ((Token != NULL) && (Token->Event != NULL)) {
 | |
|     //
 | |
|     // Release resource at non-blocking mode.
 | |
|     //
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | |
|       Token->TransactionStatus = Status;
 | |
|       *EventCount = (*EventCount) - (TempCount - Index);
 | |
|       *IsError    = TRUE;
 | |
| 
 | |
|       if (*EventCount == 0) {
 | |
|         FreePool (EventCount);
 | |
|         FreePool (IsError);
 | |
|       }
 | |
| 
 | |
|       if (SubTask != NULL) {
 | |
|         RemoveEntryList (&SubTask->TaskEntry);
 | |
|         FreeAtaSubTask (SubTask);
 | |
|       }
 | |
| 
 | |
|       if (SubEvent != NULL) {
 | |
|         gBS->CloseEvent (SubEvent);
 | |
|       }
 | |
|       gBS->RestoreTPL (OldTpl);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Trust transfer data from/to ATA device.
 | |
| 
 | |
|   This function performs one ATA pass through transaction to do a trust transfer 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  SecurityProtocolId           The value of the "Security Protocol" parameter of
 | |
|                                        the security protocol command to be sent.
 | |
|   @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
 | |
|                                        of the security protocol command to be sent.
 | |
|   @param  TransferLength               The block number or sector count of the transfer.
 | |
|   @param  IsTrustSend                  Indicates whether it is a trust send operation or not.
 | |
|   @param  Timeout                      The timeout, in 100ns units, to use for the execution
 | |
|                                        of the security protocol command. A Timeout value of 0
 | |
|                                        means that this function will wait indefinitely for the
 | |
|                                        security protocol command to execute. If Timeout is greater
 | |
|                                        than zero, then this function will return EFI_TIMEOUT
 | |
|                                        if the time required to execute the receive data command
 | |
|                                        is greater than Timeout.
 | |
|   @param  TransferLengthOut            A pointer to a buffer to store the size in bytes of the data
 | |
|                                        written to the buffer. Ignore it when IsTrustSend is TRUE.
 | |
| 
 | |
|   @retval EFI_SUCCESS       The data transfer is complete successfully.
 | |
|   @return others            Some error occurs when transferring data.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| TrustTransferAtaDevice (
 | |
|   IN OUT ATA_DEVICE                 *AtaDevice,
 | |
|   IN OUT VOID                       *Buffer,
 | |
|   IN UINT8                          SecurityProtocolId,
 | |
|   IN UINT16                         SecurityProtocolSpecificData,
 | |
|   IN UINTN                          TransferLength,
 | |
|   IN BOOLEAN                        IsTrustSend,
 | |
|   IN UINT64                         Timeout,
 | |
|   OUT UINTN                         *TransferLengthOut
 | |
|   )
 | |
| {
 | |
|   EFI_ATA_COMMAND_BLOCK             *Acb;
 | |
|   EFI_ATA_PASS_THRU_COMMAND_PACKET  *Packet;
 | |
|   EFI_STATUS                        Status;
 | |
|   VOID                              *NewBuffer;
 | |
|   EFI_ATA_PASS_THRU_PROTOCOL        *AtaPassThru;
 | |
| 
 | |
|   //
 | |
|   // Ensure AtaDevice->UdmaValid and IsTrustSend are valid boolean values
 | |
|   //
 | |
|   ASSERT ((UINTN) AtaDevice->UdmaValid < 2);
 | |
|   ASSERT ((UINTN) IsTrustSend < 2);
 | |
|   //
 | |
|   // Prepare for ATA command block.
 | |
|   //
 | |
|   Acb = ZeroMem (&AtaDevice->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
 | |
|   if (TransferLength == 0) {
 | |
|     Acb->AtaCommand    = ATA_CMD_TRUST_NON_DATA;
 | |
|   } else {
 | |
|     Acb->AtaCommand    = mAtaTrustCommands[AtaDevice->UdmaValid][IsTrustSend];
 | |
|   }
 | |
|   Acb->AtaFeatures      = SecurityProtocolId;
 | |
|   Acb->AtaSectorCount   = (UINT8) (TransferLength / 512);
 | |
|   Acb->AtaSectorNumber  = (UINT8) ((TransferLength / 512) >> 8);
 | |
|   //
 | |
|   // NOTE: ATA Spec has no explicitly definition for Security Protocol Specific layout.
 | |
|   // Here use big endian for Cylinder register.
 | |
|   //
 | |
|   Acb->AtaCylinderHigh  = (UINT8) SecurityProtocolSpecificData;
 | |
|   Acb->AtaCylinderLow   = (UINT8) (SecurityProtocolSpecificData >> 8);
 | |
|   Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort == 0xFFFF ? 0 : (AtaDevice->PortMultiplierPort << 4)));
 | |
| 
 | |
|   //
 | |
|   // Prepare for ATA pass through packet.
 | |
|   //
 | |
|   Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
 | |
|   if (TransferLength == 0) {
 | |
|     Packet->InTransferLength  = 0;
 | |
|     Packet->OutTransferLength = 0;
 | |
|     Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;
 | |
|   } else if (IsTrustSend) {
 | |
|     //
 | |
|     // Check the alignment of the incoming buffer prior to invoking underlying ATA PassThru
 | |
|     //
 | |
|     AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;
 | |
|     if ((AtaPassThru->Mode->IoAlign > 1) && !IS_ALIGNED (Buffer, AtaPassThru->Mode->IoAlign)) {
 | |
|       NewBuffer = AllocateAlignedBuffer (AtaDevice, TransferLength);
 | |
|       if (NewBuffer == NULL) {
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
| 
 | |
|       CopyMem (NewBuffer, Buffer, TransferLength);
 | |
|       FreePool (Buffer);
 | |
|       Buffer = NewBuffer;
 | |
|     }
 | |
|     Packet->OutDataBuffer = Buffer;
 | |
|     Packet->OutTransferLength = (UINT32) TransferLength;
 | |
|     Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsTrustSend];
 | |
|   } else {
 | |
|     Packet->InDataBuffer = Buffer;
 | |
|     Packet->InTransferLength = (UINT32) TransferLength;
 | |
|     Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsTrustSend];
 | |
|   }
 | |
|   Packet->Length   = EFI_ATA_PASS_THRU_LENGTH_BYTES;
 | |
|   Packet->Timeout  = Timeout;
 | |
| 
 | |
|   Status = AtaDevicePassThru (AtaDevice, NULL, NULL);
 | |
|   if (TransferLengthOut != NULL) {
 | |
|     if (! IsTrustSend) {
 | |
|       *TransferLengthOut = Packet->InTransferLength;
 | |
|     }
 | |
|   }
 | |
|   return Status;
 | |
| }
 |