// Look up table (Lba48Bit) for maximum transfer block number\r
//\r
#define MAX_28BIT_TRANSFER_BLOCK_NUM 0x100\r
-#define MAX_48BIT_TRANSFER_BLOCK_NUM 0xFFFF\r
+//\r
+// Due to limited resource for VTd PEI DMA buffer on platforms, the driver\r
+// limits the maximum transfer block number for 48-bit addressing.\r
+// Here, setting to 0x800 means that for device with 512-byte block size, the\r
+// maximum buffer for DMA mapping will be 1M bytes in size.\r
+//\r
+#define MAX_48BIT_TRANSFER_BLOCK_NUM 0x800\r
\r
UINT32 mMaxTransferBlockNumber[2] = {\r
MAX_28BIT_TRANSFER_BLOCK_NUM,\r
MaxPortNumber = MIN (MaxPortNumber, (UINT8)(UINTN)(HighBitSet32(PortImplementBitMap) + 1));\r
MaxPortNumber = MIN (MaxPortNumber, AhciGetNumberOfPortsFromMap (Private->PortBitMap));\r
\r
- PortInitializeBitMap = Private->PortBitMap;\r
+ PortInitializeBitMap = Private->PortBitMap & PortImplementBitMap;\r
AhciRegisters = &Private->AhciRegisters;\r
DeviceIndex = 0;\r
//\r
//\r
for (PortIndex = 1; PortIndex <= MaxPortNumber; PortIndex ++) {\r
Status = AhciGetPortFromMap (PortInitializeBitMap, PortIndex, &Port);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // No more available port, just break out of the loop.\r
+ //\r
+ break;\r
+ }\r
+\r
if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
//\r
// Initialize FIS Base Address Register and Command List Base Address\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Transfer data from ATA device.\r
+\r
+ This function performs one ATA pass through transaction to transfer data from/to\r
+ ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru\r
+ interface of ATA pass through.\r
+\r
+ @param[in] DeviceData A pointer to PEI_AHCI_ATA_DEVICE_DATA structure.\r
+ @param[in,out] Buffer The pointer to the current transaction buffer.\r
+ @param[in] StartLba The starting logical block address to be accessed.\r
+ @param[in] TransferLength The block number or sector count of the transfer.\r
+ @param[in] IsWrite Indicates whether it is a write operation.\r
+\r
+ @retval EFI_SUCCESS The data transfer is complete successfully.\r
+ @return others Some error occurs when transferring data.\r
+\r
+**/\r
+EFI_STATUS\r
+TransferAtaDevice (\r
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,\r
+ IN OUT VOID *Buffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINT32 TransferLength,\r
+ IN BOOLEAN IsWrite\r
+ )\r
+{\r
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;\r
+ EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThru;\r
+ EFI_ATA_COMMAND_BLOCK Acb;\r
+ EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ Private = DeviceData->Private;\r
+ AtaPassThru = &Private->AtaPassThruPpi;\r
+\r
+ //\r
+ // Ensure Lba48Bit and IsWrite are valid boolean values\r
+ //\r
+ ASSERT ((UINTN) DeviceData->Lba48Bit < 2);\r
+ ASSERT ((UINTN) IsWrite < 2);\r
+ if (((UINTN) DeviceData->Lba48Bit >= 2) ||\r
+ ((UINTN) IsWrite >= 2)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Prepare for ATA command block.\r
+ //\r
+ ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+ Acb.AtaCommand = mAtaCommands[DeviceData->Lba48Bit][IsWrite];\r
+ Acb.AtaSectorNumber = (UINT8) StartLba;\r
+ Acb.AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8);\r
+ Acb.AtaCylinderHigh = (UINT8) RShiftU64 (StartLba, 16);\r
+ Acb.AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 |\r
+ (DeviceData->PortMultiplier == 0xFFFF ?\r
+ 0 : (DeviceData->PortMultiplier << 4)));\r
+ Acb.AtaSectorCount = (UINT8) TransferLength;\r
+ if (DeviceData->Lba48Bit) {\r
+ Acb.AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24);\r
+ Acb.AtaCylinderLowExp = (UINT8) RShiftU64 (StartLba, 32);\r
+ Acb.AtaCylinderHighExp = (UINT8) RShiftU64 (StartLba, 40);\r
+ Acb.AtaSectorCountExp = (UINT8) (TransferLength >> 8);\r
+ } else {\r
+ Acb.AtaDeviceHead = (UINT8) (Acb.AtaDeviceHead | RShiftU64 (StartLba, 24));\r
+ }\r
+\r
+ //\r
+ // Prepare for ATA pass through packet.\r
+ //\r
+ ZeroMem (&Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
+ if (IsWrite) {\r
+ Packet.OutDataBuffer = Buffer;\r
+ Packet.OutTransferLength = TransferLength;\r
+ } else {\r
+ Packet.InDataBuffer = Buffer;\r
+ Packet.InTransferLength = TransferLength;\r
+ }\r
+ Packet.Asb = NULL;\r
+ Packet.Acb = &Acb;\r
+ Packet.Protocol = mAtaPassThruCmdProtocols[IsWrite];\r
+ Packet.Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;\r
+ //\r
+ // |------------------------|-----------------|\r
+ // | ATA PIO Transfer Mode | Transfer Rate |\r
+ // |------------------------|-----------------|\r
+ // | PIO Mode 0 | 3.3Mbytes/sec |\r
+ // |------------------------|-----------------|\r
+ // | PIO Mode 1 | 5.2Mbytes/sec |\r
+ // |------------------------|-----------------|\r
+ // | PIO Mode 2 | 8.3Mbytes/sec |\r
+ // |------------------------|-----------------|\r
+ // | PIO Mode 3 | 11.1Mbytes/sec |\r
+ // |------------------------|-----------------|\r
+ // | PIO Mode 4 | 16.6Mbytes/sec |\r
+ // |------------------------|-----------------|\r
+ //\r
+ // As AtaBus is used to manage ATA devices, we have to use the lowest transfer\r
+ // rate to calculate the possible maximum timeout value for each read/write\r
+ // operation. The timout value is rounded up to nearest integar and here an\r
+ // additional 30s is added to follow ATA spec in which it mentioned that the\r
+ // device may take up to 30s to respond commands in the Standby/Idle mode.\r
+ //\r
+ // Calculate the maximum timeout value for PIO read/write operation.\r
+ //\r
+ Packet.Timeout = TIMER_PERIOD_SECONDS (\r
+ DivU64x32 (\r
+ MultU64x32 (TransferLength, DeviceData->Media.BlockSize),\r
+ 3300000\r
+ ) + 31\r
+ );\r
+\r
+ return AtaPassThru->PassThru (\r
+ AtaPassThru,\r
+ DeviceData->Port,\r
+ DeviceData->PortMultiplier,\r
+ &Packet\r
+ );\r
+}\r
+\r
/**\r
Trust transfer data from/to ATA device.\r
\r