/** @file\r
+ This file contains all helper functions on the ATA command \r
+ \r
Copyright (c) 2006 - 2008, Intel Corporation.<BR>\r
All rights reserved. This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
**/\r
\r
#include "IdeBus.h"\r
+/**\r
+ This function is called by ATAIdentify() to identity whether this disk\r
+ supports ATA/ATAPI6 48bit addressing, ie support >120G capacity\r
+\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r
+ all the information of the IDE device.\r
+\r
+ @retval EFI_SUCCESS The disk specified by IdeDev is a Atapi6 supported one and \r
+ 48-bit addressing must be used\r
+ @retval EFI_UNSUPPORTED The disk dosn't not support Atapi6 or it supports but the \r
+ capacity is below 120G, 48bit addressing is not needed\r
+ @retval EFI_DEVICE_ERROR The identify data in IdeDev is incorrect\r
+ @retval EFI_INVALID_PARAMETER The identify data in IdeDev is NULL.\r
+\r
+ @note This function must be called after DEVICE_IDENTITY command has been\r
+ successfully returned\r
+\r
+**/\r
+EFI_STATUS\r
+AtaAtapi6Identify (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ UINT8 Index;\r
+ EFI_LBA TmpLba;\r
+ EFI_LBA Capacity;\r
+ EFI_IDENTIFY_DATA *Atapi6IdentifyStruct;\r
+\r
+ if (IdeDev->IdData == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Atapi6IdentifyStruct = IdeDev->IdData;\r
+\r
+ if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & (BIT15 | BIT14)) != 0x4000) {\r
+ //\r
+ // Per ATA-6 spec, word83: bit15 is zero and bit14 is one\r
+ //\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & BIT10) == 0) {\r
+ //\r
+ // The device dosn't support 48 bit addressing\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // 48 bit address feature set is supported, get maximum capacity\r
+ //\r
+ Capacity = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[0];\r
+ for (Index = 1; Index < 4; Index++) {\r
+ //\r
+ // Lower byte goes first: word[100] is the lowest word, word[103] is highest\r
+ //\r
+ TmpLba = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[Index];\r
+ Capacity |= LShiftU64 (TmpLba, 16 * Index);\r
+ }\r
+\r
+ if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {\r
+ //\r
+ // Capacity exceeds 120GB. 48-bit addressing is really needed\r
+ //\r
+ IdeDev->Type = Ide48bitAddressingHardDisk;\r
+\r
+ //\r
+ // Fill block media information:Media->LogicalPartition ,\r
+ // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function.\r
+ //\r
+ IdeDev->BlkIo.Media->IoAlign = 4;\r
+ IdeDev->BlkIo.Media->MediaId = 1;\r
+ IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
+ IdeDev->BlkIo.Media->ReadOnly = FALSE;\r
+ IdeDev->BlkIo.Media->BlockSize = 0x200;\r
+ IdeDev->BlkIo.Media->LastBlock = Capacity - 1;\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+/**\r
+ Enable SMART of the disk if supported\r
+\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to record \r
+ all the information of the IDE device.\r
+**/\r
+VOID\r
+AtaSMARTSupport (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN SMARTSupported;\r
+ UINT8 Device;\r
+ EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer;\r
+ UINT8 DeviceSelect;\r
+ UINT8 LBAMid;\r
+ UINT8 LBAHigh;\r
+\r
+ //\r
+ // Detect if the device supports S.M.A.R.T.\r
+ //\r
+ if ((IdeDev->IdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) {\r
+ //\r
+ // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one)\r
+ //\r
+ return ;\r
+ } else {\r
+ if ((IdeDev->IdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
+ //\r
+ // S.M.A.R.T is not supported by the device\r
+ //\r
+ SMARTSupported = FALSE;\r
+ } else {\r
+ SMARTSupported = TRUE;\r
+ }\r
+ }\r
+\r
+ if (!SMARTSupported) {\r
+ //\r
+ // Report nonsupport status code\r
+ //\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
+ );\r
+ } else {\r
+ //\r
+ // Enable this feature\r
+ //\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
+ );\r
+\r
+ Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
+ Status = AtaNonDataCommandIn (\r
+ IdeDev,\r
+ ATA_CMD_SMART,\r
+ Device,\r
+ ATA_SMART_ENABLE_OPERATION,\r
+ 0,\r
+ 0,\r
+ ATA_CONSTANT_4F,\r
+ ATA_CONSTANT_C2\r
+ );\r
+ //\r
+ // Detect if this feature is enabled\r
+ //\r
+ TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r
+ if (TmpAtaIdentifyPointer == NULL) {\r
+ return;\r
+ }\r
+\r
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
+ Status = AtaPioDataIn (\r
+ IdeDev,\r
+ (VOID *) TmpAtaIdentifyPointer,\r
+ sizeof (EFI_IDENTIFY_DATA),\r
+ ATA_CMD_IDENTIFY_DRIVE,\r
+ DeviceSelect,\r
+ 0,\r
+ 0,\r
+ 0,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (TmpAtaIdentifyPointer);\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Check if the feature is enabled\r
+ //\r
+ if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) {\r
+ //\r
+ // Read status data\r
+ //\r
+ AtaNonDataCommandIn (\r
+ IdeDev,\r
+ ATA_CMD_SMART,\r
+ Device,\r
+ ATA_SMART_RETURN_STATUS,\r
+ 0,\r
+ 0,\r
+ ATA_CONSTANT_4F,\r
+ ATA_CONSTANT_C2\r
+ );\r
+ LBAMid = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);\r
+ LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb);\r
+\r
+ if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
+ //\r
+ // The threshold exceeded condition is not detected by the device\r
+ //\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
+ );\r
\r
+ } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
+ //\r
+ // The threshold exceeded condition is detected by the device\r
+ //\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
+ );\r
+ }\r
+\r
+ } else {\r
+ //\r
+ // Report disabled status code\r
+ //\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
+ );\r
+ }\r
+\r
+ gBS->FreePool (TmpAtaIdentifyPointer);\r
+ }\r
+\r
+ return ;\r
+}\r
/**\r
Sends out an ATA Identify Command to the specified device.\r
\r
information it needs to fill the IDE_BLK_IO_DEV data structure,\r
including device type, media block size, media capacity, and etc.\r
\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure,used\r
- to record all the information of the IDE device.\r
-\r
- @retval EFI_SUCCESS Identify ATA device successfully.\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to record \r
+ all the information of the IDE device.\r
\r
- @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or\r
- device is not ATA device.\r
-\r
- @note\r
- parameter IdeDev will be updated in this function.\r
+ @retval EFI_SUCCESS Identify ATA device successfully.\r
+ @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.\r
+ @note parameter IdeDev will be updated in this function.\r
\r
**/\r
EFI_STATUS\r
return EFI_DEVICE_ERROR;\r
}\r
\r
-\r
/**\r
- This function is called by ATAIdentify() to identity whether this disk\r
- supports ATA/ATAPI6 48bit addressing, ie support >120G capacity\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @retval EFI_SUCCESS The disk specified by IdeDev is a Atapi6 supported one\r
- and 48-bit addressing must be used\r
-\r
- @retval EFI_UNSUPPORTED The disk dosn't not support Atapi6 or it supports but\r
- the capacity is below 120G, 48bit addressing is not needed\r
+ This function is a helper function used to change the char order in a string. It\r
+ is designed specially for the PrintAtaModuleName() function. After the IDE device \r
+ is detected, the IDE driver gets the device module name by sending ATA command \r
+ called ATA Identify Command or ATAPI Identify Command to the specified IDE device.\r
+ The module name returned is a string of ASCII characters: the first character is bit8--bit15\r
+ of the first word, the second character is BIT0--bit7 of the first word and so on. Thus\r
+ the string can not be print directly before it is preprocessed by this func to change \r
+ the order of characters in each word in the string.\r
+\r
+ @param Destination Indicates the destination string.\r
+ @param Source Indicates the source string.\r
+ @param Size the length of the string\r
+**/\r
+VOID\r
+SwapStringChars (\r
+ IN CHAR8 *Destination,\r
+ IN CHAR8 *Source,\r
+ IN UINT32 Size\r
+ )\r
+{\r
+ UINT32 Index;\r
+ CHAR8 Temp;\r
\r
- @retval EFI_DEVICE_ERROR The identify data in IdeDev is incorrect\r
- \r
- @retval EFI_INVALID_PARAMETER The identify data in IdeDev is NULL.\r
+ for (Index = 0; Index < Size; Index += 2) {\r
\r
- @note\r
- This function must be called after DEVICE_IDENTITY command has been\r
- successfully returned\r
+ Temp = Source[Index + 1];\r
+ Destination[Index + 1] = Source[Index];\r
+ Destination[Index] = Temp;\r
+ }\r
+}\r
+/**\r
+ This function is called by ATAIdentify() or ATAPIIdentify() to print device's module name.\r
\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r
+ all the information of the IDE device.\r
**/\r
-EFI_STATUS\r
-AtaAtapi6Identify (\r
+VOID\r
+PrintAtaModuleName (\r
IN IDE_BLK_IO_DEV *IdeDev\r
)\r
{\r
- UINT8 Index;\r
- EFI_LBA TmpLba;\r
- EFI_LBA Capacity;\r
- EFI_IDENTIFY_DATA *Atapi6IdentifyStruct;\r
-\r
if (IdeDev->IdData == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
+ return ;\r
}\r
\r
- Atapi6IdentifyStruct = IdeDev->IdData;\r
+ SwapStringChars (IdeDev->ModelName, IdeDev->IdData->AtaData.ModelName, 40);\r
+ IdeDev->ModelName[40] = 0x00;\r
+}\r
\r
- if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & (BIT15 | BIT14)) != 0x4000) {\r
- //\r
- // Per ATA-6 spec, word83: bit15 is zero and bit14 is one\r
- //\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & BIT10) == 0) {\r
- //\r
- // The device dosn't support 48 bit addressing\r
- //\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- //\r
- // 48 bit address feature set is supported, get maximum capacity\r
- //\r
- Capacity = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[0];\r
- for (Index = 1; Index < 4; Index++) {\r
- //\r
- // Lower byte goes first: word[100] is the lowest word, word[103] is highest\r
- //\r
- TmpLba = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[Index];\r
- Capacity |= LShiftU64 (TmpLba, 16 * Index);\r
- }\r
-\r
- if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {\r
- //\r
- // Capacity exceeds 120GB. 48-bit addressing is really needed\r
- //\r
- IdeDev->Type = Ide48bitAddressingHardDisk;\r
-\r
- //\r
- // Fill block media information:Media->LogicalPartition ,\r
- // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function.\r
- //\r
- IdeDev->BlkIo.Media->IoAlign = 4;\r
- IdeDev->BlkIo.Media->MediaId = 1;\r
- IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r
- IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
- IdeDev->BlkIo.Media->ReadOnly = FALSE;\r
- IdeDev->BlkIo.Media->BlockSize = 0x200;\r
- IdeDev->BlkIo.Media->LastBlock = Capacity - 1;\r
-\r
- return EFI_SUCCESS;\r
- }\r
-\r
- return EFI_UNSUPPORTED;\r
-}\r
-\r
-/**\r
- This function is called by ATAIdentify() or ATAPIIdentify()\r
- to print device's module name.\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
-**/\r
-VOID\r
-PrintAtaModuleName (\r
- IN IDE_BLK_IO_DEV *IdeDev\r
- )\r
-{\r
- if (IdeDev->IdData == NULL) {\r
- return ;\r
- }\r
-\r
- SwapStringChars (IdeDev->ModelName, IdeDev->IdData->AtaData.ModelName, 40);\r
- IdeDev->ModelName[40] = 0x00;\r
-}\r
-\r
-/**\r
- This function is used to send out ATA commands conforms to the\r
- PIO Data In Protocol.\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *Buffer\r
- buffer contained data transferred from device to host.\r
-\r
- @param[in] ByteCount\r
- data size in byte unit of the buffer.\r
-\r
- @param[in] AtaCommand\r
- value of the Command Register\r
-\r
- @param[in] Head\r
- value of the Head/Device Register\r
-\r
- @param[in] SectorCount\r
- value of the Sector Count Register\r
-\r
- @param[in] SectorNumber\r
- value of the Sector Number Register\r
-\r
- @param[in] CylinderLsb\r
- value of the low byte of the Cylinder Register\r
-\r
- @param[in] CylinderMsb\r
- value of the high byte of the Cylinder Register\r
-\r
- @retval EFI_SUCCESS send out the ATA command and device send required\r
- data successfully.\r
+/**\r
+ This function is used to send out ATA commands conforms to the PIO Data In Protocol.\r
\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record \r
+ all the information of the IDE device.\r
+ @param Buffer buffer contained data transferred from device to host.\r
+ @param ByteCount data size in byte unit of the buffer.\r
+ @param AtaCommand value of the Command Register\r
+ @param Head value of the Head/Device Register\r
+ @param SectorCount value of the Sector Count Register\r
+ @param SectorNumber value of the Sector Number Register\r
+ @param CylinderLsb value of the low byte of the Cylinder Register\r
+ @param CylinderMsb value of the high byte of the Cylinder Register\r
+ \r
+ @retval EFI_SUCCESS send out the ATA command and device send required data successfully.\r
@retval EFI_DEVICE_ERROR command sent failed.\r
\r
**/\r
This function is used to send out ATA commands conforms to the\r
PIO Data Out Protocol.\r
\r
- @param *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
@param *Buffer buffer contained data transferred from host to device.\r
@param ByteCount data size in byte unit of the buffer.\r
@param AtaCommand value of the Command Register\r
@param CylinderLsb value of the low byte of the Cylinder Register\r
@param CylinderMsb value of the high byte of the Cylinder Register\r
\r
- @retval EFI_SUCCESS send out the ATA command and device received required\r
- data successfully.\r
-\r
+ @retval EFI_SUCCESS send out the ATA command and device received required\r
+ data successfully.\r
@retval EFI_DEVICE_ERROR command sent failed.\r
\r
**/\r
some debug information and if there is ERR bit set in the Status\r
Register, the Error Register's value is also be parsed and print out.\r
\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to \r
+ record all the information of the IDE device.\r
\r
@retval EFI_SUCCESS No err information in the Status Register.\r
@retval EFI_DEVICE_ERROR Any err information in the Status Register.\r
\r
DEBUG_CODE_BEGIN ();\r
\r
- if ((StatusRegister & ATA_STSREG_DWF) != 0) {\r
- DEBUG (\r
- (EFI_D_BLKIO,\r
- "CheckErrorStatus()-- %02x : Error : Write Fault\n",\r
- StatusRegister)\r
- );\r
- }\r
+ if ((StatusRegister & ATA_STSREG_DWF) != 0) {\r
+ DEBUG (\r
+ (EFI_D_BLKIO,\r
+ "CheckErrorStatus()-- %02x : Error : Write Fault\n",\r
+ StatusRegister)\r
+ );\r
+ }\r
\r
- if ((StatusRegister & ATA_STSREG_CORR) != 0) {\r
- DEBUG (\r
- (EFI_D_BLKIO,\r
- "CheckErrorStatus()-- %02x : Error : Corrected Data\n",\r
- StatusRegister)\r
- );\r
- }\r
+ if ((StatusRegister & ATA_STSREG_CORR) != 0) {\r
+ DEBUG (\r
+ (EFI_D_BLKIO,\r
+ "CheckErrorStatus()-- %02x : Error : Corrected Data\n",\r
+ StatusRegister)\r
+ );\r
+ }\r
\r
- if ((StatusRegister & ATA_STSREG_ERR) != 0) {\r
- ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((StatusRegister & ATA_STSREG_ERR) != 0) {\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
\r
- if ((ErrorRegister & ATA_ERRREG_BBK) != 0) {\r
+ if ((ErrorRegister & ATA_ERRREG_BBK) != 0) {\r
DEBUG (\r
(EFI_D_BLKIO,\r
"CheckErrorStatus()-- %02x : Error : Bad Block Detected\n",\r
}\r
\r
/**\r
- This function is called by the AtaBlkIoReadBlocks() to perform\r
- reading from media in block unit.\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *DataBuffer\r
- A pointer to the destination buffer for the data.\r
-\r
- @param[in] Lba\r
- The starting logical block address to read from\r
- on the device media.\r
-\r
- @param[in] NumberOfBlocks\r
- The number of transfer data blocks.\r
-\r
- @return return status is fully dependent on the return status\r
- of AtaPioDataIn() function.\r
+ This function is called by the AtaBlkIoReadBlocks() to perform reading from \r
+ media in block unit.\r
+\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record \r
+ all the information of the IDE device.\r
+ @param DataBuffer A pointer to the destination buffer for the data.\r
+ @param Lba The starting logical block address to read from on the device media.\r
+ @param NumberOfBlocks The number of transfer data blocks.\r
+ \r
+ @return status is fully dependent on the return status of AtaPioDataIn() function.\r
\r
**/\r
EFI_STATUS\r
}\r
\r
/**\r
- This function is called by the AtaBlkIoWriteBlocks() to perform\r
- writing onto media in block unit.\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure,used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *BufferData\r
- A pointer to the source buffer for the data.\r
-\r
- @param[in] Lba\r
- The starting logical block address to write onto\r
- the device media.\r
-\r
- @param[in] NumberOfBlocks\r
- The number of transfer data blocks.\r
-\r
- @return return status is fully dependent on the return status\r
- of AtaPioDataOut() function.\r
+ This function is called by the AtaBlkIoWriteBlocks() to perform writing onto \r
+ media in block unit.\r
+\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to record\r
+ all the information of the IDE device.\r
+ @param BufferData A pointer to the source buffer for the data.\r
+ @param Lba The starting logical block address to write onto the device media.\r
+ @param NumberOfBlocks The number of transfer data blocks.\r
+ \r
+ @return status is fully dependent on the return status of AtaPioDataIn() function.\r
\r
**/\r
EFI_STATUS\r
\r
return Status;\r
}\r
-\r
/**\r
- This function is used to implement the Soft Reset on the specified\r
- device. But, the ATA Soft Reset mechanism is so strong a reset method\r
- that it will force resetting on both devices connected to the\r
- same cable.\r
+ This function is used to implement the Soft Reset on the specified device. But,\r
+ the ATA Soft Reset mechanism is so strong a reset method that it will force \r
+ resetting on both devices connected to the same cable.\r
\r
It is called by IdeBlkIoReset(), a interface function of Block\r
I/O protocol.\r
This function can also be used by the ATAPI device to perform reset when\r
ATAPI Reset command is failed.\r
\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r
+ all the information of the IDE device.\r
@retval EFI_SUCCESS Soft reset completes successfully.\r
@retval EFI_DEVICE_ERROR Any step during the reset process is failed.\r
\r
- @note\r
- The registers initial values after ATA soft reset are different\r
- to the ATA device and ATAPI device.\r
-\r
+ @note The registers initial values after ATA soft reset are different\r
+ to the ATA device and ATAPI device.\r
**/\r
EFI_STATUS\r
AtaSoftReset (\r
\r
return EFI_SUCCESS;\r
}\r
-\r
/**\r
- This function is the ATA implementation for ReadBlocks in the\r
- Block I/O Protocol interface.\r
-\r
- @param[in] *IdeBlkIoDevice\r
- Indicates the calling context.\r
-\r
- @param[in] MediaId\r
- The media id that the read request is for.\r
+ This function is used to send out ATA commands conforms to the PIO Data In \r
+ Protocol, supporting ATA/ATAPI-6 standard\r
\r
- @param[in] LBA\r
- The starting logical block address to read from\r
- on the device.\r
-\r
- @param[in] BufferSize\r
- The size of the Buffer in bytes. This must be a\r
- multiple of the intrinsic block size of the device.\r
-\r
- @param[out] *Buffer\r
- A pointer to the destination buffer for the data.\r
- The caller is responsible for either having implicit\r
- or explicit ownership of the memory that data is read into.\r
-\r
- @retval EFI_SUCCESS Read Blocks successfully.\r
- @retval EFI_DEVICE_ERROR Read Blocks failed.\r
- @retval EFI_NO_MEDIA There is no media in the device.\r
- @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.\r
+ Comparing with ATA-3 data in protocol, we have two differents here:\r
+ 1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
+ wait will frequently fail... cause writing function return error)\r
\r
- @retval EFI_BAD_BUFFER_SIZE\r
- The BufferSize parameter is not a multiple of the\r
- intrinsic block size of the device.\r
+ 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
+ slow down writing performance by 100 times!)\r
\r
- @retval EFI_INVALID_PARAMETER\r
- The read request contains LBAs that are not valid,\r
- or the data buffer is not valid.\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+ @param Buffer buffer contained data transferred from device to host.\r
+ @param ByteCount data size in byte unit of the buffer.\r
+ @param AtaCommand value of the Command Register\r
+ @param StartLba the start LBA of this transaction\r
+ @param SectorCount the count of sectors to be transfered\r
\r
- @note\r
- If Read Block error because of device error, this function will call\r
- AtaSoftReset() function to reset device.\r
+ @retval EFI_SUCCESS send out the ATA command and device send required data successfully.\r
+ @retval EFI_DEVICE_ERROR command sent failed.\r
\r
**/\r
EFI_STATUS\r
-AtaBlkIoReadBlocks (\r
- IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
- IN UINT32 MediaId,\r
- IN EFI_LBA LBA,\r
- IN UINTN BufferSize,\r
- OUT VOID *Buffer\r
+AtaPioDataInExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN OUT VOID *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN UINT8 AtaCommand,\r
+ IN EFI_LBA StartLba,\r
+ IN UINT16 SectorCount\r
)\r
{\r
- EFI_BLOCK_IO_MEDIA *Media;\r
- UINTN BlockSize;\r
- UINTN NumberOfBlocks;\r
- EFI_STATUS Status;\r
+ UINT8 DevSel;\r
+ UINT8 SectorCount8;\r
+ UINT8 LbaLow;\r
+ UINT8 LbaMid;\r
+ UINT8 LbaHigh;\r
+ UINTN WordCount;\r
+ UINTN Increment;\r
+ UINT16 *Buffer16;\r
+ EFI_STATUS Status;\r
\r
- if (Buffer == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
}\r
\r
- if (BufferSize == 0) {\r
- return EFI_SUCCESS;\r
+ //\r
+ // Select device, set bit6 as 1 to indicate LBA mode is used\r
+ //\r
+ DevSel = (UINT8) (IdeDev->Device << 4);\r
+ DevSel |= 0x40;\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ DevSel\r
+ );\r
+\r
+ //\r
+ // Wait for DRDY singnal asserting. ATAPI device needn't wait\r
+ //\r
+ if ( (IdeDev->Type == IdeHardDisk) ||\r
+ (IdeDev->Type == Ide48bitAddressingHardDisk)) {\r
+\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
}\r
\r
- Status = EFI_SUCCESS;\r
+ //\r
+ // Fill feature register if needed\r
+ //\r
+ if (AtaCommand == ATA_CMD_SET_FEATURES) {\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
+ }\r
\r
//\r
- // Get the intrinsic block size\r
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
//\r
- Media = IdeBlkIoDevice->BlkIo.Media;\r
- BlockSize = Media->BlockSize;\r
+ SectorCount8 = (UINT8) (SectorCount >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
\r
- NumberOfBlocks = BufferSize / BlockSize;\r
+ SectorCount8 = (UINT8) SectorCount;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
\r
- if (MediaId != Media->MediaId) {\r
- return EFI_MEDIA_CHANGED;\r
- }\r
+ //\r
+ // Fill the start LBA registers, which are also two-byte FIFO\r
+ //\r
+ LbaLow = (UINT8) RShiftU64 (StartLba, 24);\r
+ LbaMid = (UINT8) RShiftU64 (StartLba, 32);\r
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
\r
- if (BufferSize % BlockSize != 0) {\r
- return EFI_BAD_BUFFER_SIZE;\r
- }\r
+ LbaLow = (UINT8) StartLba;\r
+ LbaMid = (UINT8) RShiftU64 (StartLba, 8);\r
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
\r
- if (!(Media->MediaPresent)) {\r
- return EFI_NO_MEDIA;\r
- }\r
+ //\r
+ // Send command via Command Register, invoking the processing of this command\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
\r
- if (LBA > Media->LastBlock) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ Buffer16 = (UINT16 *) Buffer;\r
\r
- if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ //\r
+ // According to PIO data in protocol, host can perform a series of reads to\r
+ // the data register after each time device set DRQ ready;\r
+ //\r
\r
- if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ //\r
+ // 256 words\r
+ //\r
+ Increment = 256;\r
\r
- Status = EFI_SUCCESS;\r
- if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
+ //\r
+ // used to record bytes of currently transfered data\r
+ //\r
+ WordCount = 0;\r
+\r
+ while (WordCount < ByteCount / 2) {\r
//\r
- // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism\r
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
//\r
- if (IdeBlkIoDevice->UdmaMode.Valid) {\r
- Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- } else {\r
- Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
}\r
- } else {\r
+\r
+ Status = CheckErrorStatus (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
//\r
- // For ATA-3 compatible device, use ATA-3 read block mechanism\r
+ // Get the byte count for one series of read\r
//\r
- if (IdeBlkIoDevice->UdmaMode.Valid) {\r
- Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- } else {\r
- Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ if ((WordCount + Increment) > ByteCount / 2) {\r
+ Increment = ByteCount / 2 - WordCount;\r
}\r
- }\r
\r
- if (EFI_ERROR (Status)) {\r
- AtaSoftReset (IdeBlkIoDevice);\r
- return EFI_DEVICE_ERROR;\r
- }\r
+ IDEReadPortWMultiple (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Data,\r
+ Increment,\r
+ Buffer16\r
+ );\r
\r
- return EFI_SUCCESS;\r
+ WordCount += Increment;\r
+ Buffer16 += Increment;\r
\r
-}\r
+ }\r
\r
+ return CheckErrorStatus (IdeDev);\r
+}\r
/**\r
- This function is the ATA implementation for WriteBlocks in the\r
- Block I/O Protocol interface.\r
-\r
- @param[in] *IdeBlkIoDevice\r
- Indicates the calling context.\r
-\r
- @param[in] MediaId\r
- The media id that the write request is for.\r
-\r
- @param[in] LBA\r
- The starting logical block address to write onto\r
- the device.\r
-\r
- @param[in] BufferSize\r
- The size of the Buffer in bytes. This must be a\r
- multiple of the intrinsic block size of the device.\r
-\r
- @param[out] *Buffer\r
- A pointer to the source buffer for the data.\r
- The caller is responsible for either having implicit\r
- or explicit ownership of the memory that data is\r
- written from.\r
-\r
- @retval EFI_SUCCESS Write Blocks successfully.\r
- @retval EFI_DEVICE_ERROR Write Blocks failed.\r
- @retval EFI_NO_MEDIA There is no media in the device.\r
- @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.\r
-\r
- @retval EFI_BAD_BUFFER_SIZE\r
- The BufferSize parameter is not a multiple of the\r
- intrinsic block size of the device.\r
+ Send ATA Ext command into device with NON_DATA protocol\r
\r
- @retval EFI_INVALID_PARAMETER\r
- The write request contains LBAs that are not valid,\r
- or the data buffer is not valid.\r
+ @param IdeDev Standard IDE device private data structure\r
+ @param AtaCommand The ATA command to be sent\r
+ @param Device The value in Device register\r
+ @param Feature The value in Feature register\r
+ @param SectorCount The value in SectorCount register\r
+ @param LbaAddress The LBA address in 48-bit mode\r
\r
- @note\r
- If Write Block error because of device error, this function will call\r
- AtaSoftReset() function to reset device.\r
+ @retval EFI_SUCCESS Reading succeed\r
+ @retval EFI_DEVICE_ERROR Error executing commands on this device.\r
\r
**/\r
EFI_STATUS\r
-AtaBlkIoWriteBlocks (\r
- IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
- IN UINT32 MediaId,\r
- IN EFI_LBA LBA,\r
- IN UINTN BufferSize,\r
- OUT VOID *Buffer\r
+AtaCommandIssueExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT16 Feature,\r
+ IN UINT16 SectorCount,\r
+ IN EFI_LBA LbaAddress\r
)\r
{\r
+ EFI_STATUS Status;\r
+ UINT8 SectorCount8;\r
+ UINT8 Feature8;\r
+ UINT8 LbaLow;\r
+ UINT8 LbaMid;\r
+ UINT8 LbaHigh;\r
\r
- EFI_BLOCK_IO_MEDIA *Media;\r
- UINTN BlockSize;\r
- UINTN NumberOfBlocks;\r
- EFI_STATUS Status;\r
-\r
- if (Buffer == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
}\r
\r
- if (BufferSize == 0) {\r
- return EFI_SUCCESS;\r
+ //\r
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+ );\r
+\r
+ //\r
+ // ATA commands for ATA device must be issued when DRDY is set\r
+ //\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
}\r
\r
- Status = EFI_SUCCESS;\r
+ //\r
+ // Pass parameter into device register block\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
\r
//\r
- // Get the intrinsic block size\r
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
//\r
- Media = IdeBlkIoDevice->BlkIo.Media;\r
- BlockSize = Media->BlockSize;\r
- NumberOfBlocks = BufferSize / BlockSize;\r
+ Feature8 = (UINT8) (Feature >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
\r
- if (MediaId != Media->MediaId) {\r
- return EFI_MEDIA_CHANGED;\r
- }\r
+ Feature8 = (UINT8) Feature;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
\r
- if (BufferSize % BlockSize != 0) {\r
- return EFI_BAD_BUFFER_SIZE;\r
- }\r
+ //\r
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ SectorCount8 = (UINT8) (SectorCount >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
\r
- if (LBA > Media->LastBlock) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ SectorCount8 = (UINT8) SectorCount;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
\r
- if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ //\r
+ // Fill the start LBA registers, which are also two-byte FIFO\r
+ //\r
+ LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ LbaLow = (UINT8) LbaAddress;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
\r
- if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
\r
- Status = EFI_SUCCESS;\r
- if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
- //\r
- // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism\r
- //\r
- if (IdeBlkIoDevice->UdmaMode.Valid) {\r
- Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- } else {\r
- Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- }\r
- } else {\r
- //\r
- // For ATA-3 compatible device, use ATA-3 write block mechanism\r
- //\r
- if (IdeBlkIoDevice->UdmaMode.Valid) {\r
- Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- } else {\r
- Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- }\r
- }\r
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
\r
- if (EFI_ERROR (Status)) {\r
- AtaSoftReset (IdeBlkIoDevice);\r
- return EFI_DEVICE_ERROR;\r
- }\r
+ //\r
+ // Work around for Segate 160G disk writing\r
+ //\r
+ gBS->Stall (1800);\r
+\r
+ //\r
+ // Send command via Command Register\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+ //\r
+ // Stall at least 400ns\r
+ //\r
+ gBS->Stall (100);\r
\r
return EFI_SUCCESS;\r
}\r
-\r
/**\r
- This function is called by the AtaBlkIoReadBlocks() to perform\r
- reading from media in block unit. The function has been enhanced to\r
- support >120GB access and transfer at most 65536 blocks per command\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
+ Send ATA Ext command into device with NON_DATA protocol\r
\r
- @param[in] *DataBuffer A pointer to the destination buffer for the data.\r
- @param[in] StartLba The starting logical block address to read from\r
- on the device media.\r
- @param[in] NumberOfBlocks The number of transfer data blocks.\r
+ @param IdeDev Standard IDE device private data structure\r
+ @param AtaCommand The ATA command to be sent\r
+ @param Device The value in Device register\r
+ @param Feature The value in Feature register\r
+ @param SectorCount The value in SectorCount register\r
+ @param LbaAddress The LBA address in 48-bit mode\r
\r
- @return return status is fully dependent on the return status\r
- of AtaPioDataInExt() function.\r
+ @retval EFI_SUCCESS Reading succeed\r
+ @retval EFI_DEVICE_ERROR Error executing commands on this device.\r
\r
**/\r
EFI_STATUS\r
-AtaReadSectorsExt (\r
+AtaCommandIssue (\r
IN IDE_BLK_IO_DEV *IdeDev,\r
- IN VOID *DataBuffer,\r
- IN EFI_LBA StartLba,\r
- IN UINTN NumberOfBlocks\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT16 Feature,\r
+ IN UINT16 SectorCount,\r
+ IN EFI_LBA LbaAddress\r
)\r
{\r
EFI_STATUS Status;\r
- UINTN BlocksRemaining;\r
- EFI_LBA Lba64;\r
- UINT8 AtaCommand;\r
- UINT16 SectorCount;\r
- UINT32 ByteCount;\r
- VOID *Buffer;\r
+ UINT8 SectorCount8;\r
+ UINT8 Feature8;\r
+ UINT8 Lba0;\r
+ UINT8 Lba1;\r
+ UINT8 Lba2;\r
+ UINT8 Lba3;\r
+\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
//\r
- // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol\r
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
//\r
- AtaCommand = ATA_CMD_READ_SECTORS_EXT;\r
- Buffer = DataBuffer;\r
- BlocksRemaining = NumberOfBlocks;\r
- Lba64 = StartLba;\r
- Status = EFI_SUCCESS;\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+ );\r
\r
- while (BlocksRemaining > 0) {\r
+ //\r
+ // ATA commands for ATA device must be issued when DRDY is set\r
+ //\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
- if (BlocksRemaining >= 0x10000) {\r
- //\r
- // SectorCount is used to record the number of sectors to be read\r
- // Max 65536 sectors can be transfered at a time.\r
- //\r
- SectorCount = 0xffff;\r
- } else {\r
- SectorCount = (UINT16) BlocksRemaining;\r
- }\r
+ Lba0 = (UINT8) LbaAddress;\r
+ Lba1 = (UINT8) RShiftU64 (LbaAddress, 8);\r
+ Lba2 = (UINT8) RShiftU64 (LbaAddress, 16);\r
+ Lba3 = (UINT8) RShiftU64 (LbaAddress, 24);\r
+ Device = (UINT8) (Device | Lba3);\r
\r
- //\r
- // ByteCount is the number of bytes that will be read\r
- //\r
- ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+ //\r
+ // Pass parameter into device register block\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
\r
- //\r
- // call AtaPioDataInExt() to send Read Sector Command and receive data read\r
- //\r
- Status = AtaPioDataInExt (\r
- IdeDev,\r
- Buffer,\r
- ByteCount,\r
- AtaCommand,\r
- Lba64,\r
- SectorCount\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
+ //\r
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ Feature8 = (UINT8) Feature;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
\r
- Lba64 += SectorCount;\r
- Buffer = ((UINT8 *) Buffer + ByteCount);\r
- BlocksRemaining -= SectorCount;\r
- }\r
+ //\r
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ SectorCount8 = (UINT8) SectorCount;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
\r
- return Status;\r
-}\r
+ //\r
+ // Fill the start LBA registers, which are also two-byte FIFO\r
+ //\r
\r
-/**\r
- This function is called by the AtaBlkIoWriteBlocks() to perform\r
- writing onto media in block unit. The function has been enhanced to\r
- support >120GB access and transfer at most 65536 blocks per command\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2);\r
\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure,used\r
- to record all the information of the IDE device.\r
+ //\r
+ // Send command via Command Register\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
\r
- @param[in] *DataBuffer\r
- A pointer to the source buffer for the data.\r
+ //\r
+ // Stall at least 400ns\r
+ //\r
+ gBS->Stall (100);\r
\r
- @param[in] StartLba\r
- The starting logical block address to write onto\r
- the device media.\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
\r
- @param[in] NumberOfBlocks\r
- The number of transfer data blocks.\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+ @param DataBuffer A pointer to the source buffer for the data.\r
+ @param StartLba The starting logical block address to write to\r
+ on the device media.\r
+ @param NumberOfBlocks The number of transfer data blocks.\r
+ @param UdmaOp The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,\r
+ AtaUdmaWriteOp, AtaUdmaWriteExOp\r
\r
- @return status is fully dependent on the return status\r
- of AtaPioDataOutExt() function.\r
+ @retval EFI_SUCCESS the operation is successful.\r
+ @retval EFI_OUT_OF_RESOURCES Build PRD table failed\r
+ @retval EFI_UNSUPPORTED Unknown channel or operations command\r
+ @retval EFI_DEVICE_ERROR Ata command execute failed\r
\r
**/\r
EFI_STATUS\r
-AtaWriteSectorsExt (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN VOID *DataBuffer,\r
- IN EFI_LBA StartLba,\r
- IN UINTN NumberOfBlocks\r
+DoAtaUdma (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks,\r
+ IN ATA_UDMA_OPERATION UdmaOp\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_LBA Lba64;\r
- UINTN BlocksRemaining;\r
- UINT8 AtaCommand;\r
- UINT16 SectorCount;\r
- UINT32 ByteCount;\r
- VOID *Buffer;\r
+ IDE_DMA_PRD *PrdAddr;\r
+ IDE_DMA_PRD *UsedPrdAddr;\r
+ IDE_DMA_PRD *TempPrdAddr;\r
+ UINT8 RegisterValue;\r
+ UINT8 Device;\r
+ UINT64 IoPortForBmic;\r
+ UINT64 IoPortForBmis;\r
+ UINT64 IoPortForBmid;\r
+ EFI_STATUS Status;\r
+ UINTN PrdTableNum;\r
+ UINTN ByteCount;\r
+ UINTN ByteAvailable;\r
+ UINT8 *PrdBuffer;\r
+ UINTN RemainBlockNum;\r
+ UINT8 DeviceControl;\r
+ UINT32 Count;\r
+ UINTN PageCount;\r
+ VOID *Map;\r
+ VOID *MemPage;\r
+ EFI_PHYSICAL_ADDRESS DeviceAddress;\r
+ UINTN MaxDmaCommandSectors;\r
+ EFI_PCI_IO_PROTOCOL_OPERATION PciIoProtocolOp;\r
+ UINT8 AtaCommand;\r
+\r
+ switch (UdmaOp) {\r
+ case AtaUdmaReadOp:\r
+ MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;\r
+ PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;\r
+ AtaCommand = ATA_CMD_READ_DMA;\r
+ break;\r
+ case AtaUdmaReadExtOp:\r
+ MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;\r
+ PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;\r
+ AtaCommand = ATA_CMD_READ_DMA_EXT;\r
+ break;\r
+ case AtaUdmaWriteOp:\r
+ MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;\r
+ PciIoProtocolOp = EfiPciIoOperationBusMasterRead;\r
+ AtaCommand = ATA_CMD_WRITE_DMA;\r
+ break;\r
+ case AtaUdmaWriteExtOp:\r
+ MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;\r
+ PciIoProtocolOp = EfiPciIoOperationBusMasterRead;\r
+ AtaCommand = ATA_CMD_WRITE_DMA_EXT;\r
+ break;\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ break;\r
+ }\r
\r
//\r
- // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol\r
+ // Select device\r
//\r
- AtaCommand = ATA_CMD_WRITE_SECTORS_EXT;\r
- Lba64 = StartLba;\r
- Buffer = DataBuffer;\r
- BlocksRemaining = NumberOfBlocks;\r
+ Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
\r
- Status = EFI_SUCCESS;\r
+ //\r
+ // Enable interrupt to support UDMA\r
+ //\r
+ DeviceControl = 0;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
\r
- while (BlocksRemaining > 0) {\r
+ if (IdePrimary == IdeDev->Channel) {\r
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
+ } else {\r
+ if (IdeSecondary == IdeDev->Channel) {\r
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
+ } else {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
\r
- if (BlocksRemaining >= 0x10000) {\r
+ //\r
+ // Read BMIS register and clear ERROR and INTR bit\r
+ //\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmis,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+ \r
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+ \r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmis,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ Status = EFI_SUCCESS;\r
+ \r
+ RemainBlockNum = NumberOfBlocks;\r
+ while (RemainBlockNum > 0) {\r
+\r
+ if (RemainBlockNum >= MaxDmaCommandSectors) {\r
//\r
- // SectorCount is used to record the number of sectors to be written.\r
+ // SectorCount is used to record the number of sectors to be read\r
// Max 65536 sectors can be transfered at a time.\r
//\r
- SectorCount = 0xffff;\r
+ NumberOfBlocks = MaxDmaCommandSectors;\r
+ RemainBlockNum -= MaxDmaCommandSectors;\r
} else {\r
- SectorCount = (UINT16) BlocksRemaining;\r
+ NumberOfBlocks = (UINT16) RemainBlockNum;\r
+ RemainBlockNum = 0;\r
}\r
\r
//\r
- // ByteCount is the number of bytes that will be written\r
+ // Calculate the number of PRD table to make sure the memory region\r
+ // not cross 64K boundary\r
//\r
- ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+ ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
+ PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
\r
//\r
- // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command\r
+ // Build PRD table\r
//\r
- Status = AtaPioDataOutExt (\r
- IdeDev,\r
- Buffer,\r
- ByteCount,\r
- AtaCommand,\r
- Lba64,\r
- SectorCount\r
- );\r
+ PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
+ Status = IdeDev->PciIo->AllocateBuffer (\r
+ IdeDev->PciIo,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ PageCount,\r
+ &MemPage,\r
+ 0\r
+ );\r
if (EFI_ERROR (Status)) {\r
- return Status;\r
+ return EFI_OUT_OF_RESOURCES;\r
}\r
+ ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));\r
\r
- Lba64 += SectorCount;\r
- Buffer = ((UINT8 *) Buffer + ByteCount);\r
- BlocksRemaining -= SectorCount;\r
- }\r
-\r
- return Status;\r
-}\r
+ PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);\r
+ //\r
+ // To make sure PRD is allocated in one 64K page\r
+ //\r
+ if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
+ } else {\r
+ if ((UINTN) PrdAddr & 0x03) {\r
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
+ } else {\r
+ UsedPrdAddr = PrdAddr;\r
+ }\r
+ }\r
\r
-/**\r
- This function is used to send out ATA commands conforms to the\r
- PIO Data In Protocol, supporting ATA/ATAPI-6 standard\r
-\r
- Comparing with ATA-3 data in protocol, we have two differents here:<BR>\r
- 1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
- wait will frequently fail... cause writing function return error)\r
+ //\r
+ // Build the PRD table\r
+ //\r
+ Status = IdeDev->PciIo->Map (\r
+ IdeDev->PciIo,\r
+ PciIoProtocolOp,\r
+ DataBuffer,\r
+ &ByteCount,\r
+ &DeviceAddress,\r
+ &Map\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ PrdBuffer = (VOID *) ((UINTN) DeviceAddress);\r
+ TempPrdAddr = UsedPrdAddr;\r
+ while (TRUE) {\r
\r
- 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
- slow down writing performance by 100 times!)\r
+ ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
\r
- @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
+ if (ByteCount <= ByteAvailable) {\r
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
+ TempPrdAddr->ByteCount = (UINT16) ByteCount;\r
+ TempPrdAddr->EndOfTable = 0x8000;\r
+ break;\r
+ }\r
\r
- @param[in, out] *Buffer buffer contained data transferred from device to host.\r
- @param[in] ByteCount data size in byte unit of the buffer.\r
- @param[in] AtaCommand value of the Command Register\r
- @param[in] StartLba the start LBA of this transaction\r
- @param[in] SectorCount the count of sectors to be transfered\r
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
+ TempPrdAddr->ByteCount = (UINT16) ByteAvailable;\r
\r
- @retval EFI_SUCCESS send out the ATA command and device send required\r
- data successfully.\r
+ ByteCount -= ByteAvailable;\r
+ PrdBuffer += ByteAvailable;\r
+ TempPrdAddr++;\r
+ }\r
\r
- @retval EFI_DEVICE_ERROR command sent failed.\r
+ //\r
+ // Set the base address to BMID register\r
+ //\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint32,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmid,\r
+ 1,\r
+ &UsedPrdAddr\r
+ );\r
\r
-**/\r
-EFI_STATUS\r
-AtaPioDataInExt (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN OUT VOID *Buffer,\r
- IN UINT32 ByteCount,\r
- IN UINT8 AtaCommand,\r
- IN EFI_LBA StartLba,\r
- IN UINT16 SectorCount\r
- )\r
-{\r
- UINT8 DevSel;\r
- UINT8 SectorCount8;\r
- UINT8 LbaLow;\r
- UINT8 LbaMid;\r
- UINT8 LbaHigh;\r
- UINTN WordCount;\r
- UINTN Increment;\r
- UINT16 *Buffer16;\r
- EFI_STATUS Status;\r
+ //\r
+ // Set BMIC register to identify the operation direction\r
+ //\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
\r
- Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
+ if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) {\r
+ RegisterValue |= BMIC_NREAD;\r
+ } else {\r
+ RegisterValue &= ~((UINT8) BMIC_NREAD);\r
+ }\r
\r
- //\r
- // Select device, set bit6 as 1 to indicate LBA mode is used\r
- //\r
- DevSel = (UINT8) (IdeDev->Device << 4);\r
- DevSel |= 0x40;\r
- IDEWritePortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Head,\r
- DevSel\r
- );\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
\r
- //\r
- // Wait for DRDY singnal asserting. ATAPI device needn't wait\r
- //\r
- if ( (IdeDev->Type == IdeHardDisk) ||\r
- (IdeDev->Type == Ide48bitAddressingHardDisk)) {\r
+ if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) {\r
+ Status = AtaCommandIssueExt (\r
+ IdeDev,\r
+ AtaCommand,\r
+ Device,\r
+ 0,\r
+ (UINT16) NumberOfBlocks,\r
+ StartLba\r
+ );\r
+ } else {\r
+ Status = AtaCommandIssue (\r
+ IdeDev,\r
+ AtaCommand,\r
+ Device,\r
+ 0,\r
+ (UINT16) NumberOfBlocks,\r
+ StartLba\r
+ );\r
+ }\r
\r
- Status = DRDYReady (IdeDev, ATATIMEOUT);\r
if (EFI_ERROR (Status)) {\r
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+ IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
return EFI_DEVICE_ERROR;\r
}\r
- }\r
-\r
- //\r
- // Fill feature register if needed\r
- //\r
- if (AtaCommand == ATA_CMD_SET_FEATURES) {\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
- }\r
-\r
- //\r
- // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
- //\r
- SectorCount8 = (UINT8) (SectorCount >> 8);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
-\r
- SectorCount8 = (UINT8) SectorCount;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
-\r
- //\r
- // Fill the start LBA registers, which are also two-byte FIFO\r
- //\r
- LbaLow = (UINT8) RShiftU64 (StartLba, 24);\r
- LbaMid = (UINT8) RShiftU64 (StartLba, 32);\r
- LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
-\r
- LbaLow = (UINT8) StartLba;\r
- LbaMid = (UINT8) RShiftU64 (StartLba, 8);\r
- LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
\r
- //\r
- // Send command via Command Register, invoking the processing of this command\r
- //\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
-\r
- Buffer16 = (UINT16 *) Buffer;\r
-\r
- //\r
- // According to PIO data in protocol, host can perform a series of reads to\r
- // the data register after each time device set DRQ ready;\r
- //\r
+ //\r
+ // Set START bit of BMIC register\r
+ //\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
\r
- //\r
- // 256 words\r
- //\r
- Increment = 256;\r
+ RegisterValue |= BMIC_START;\r
\r
- //\r
- // used to record bytes of currently transfered data\r
- //\r
- WordCount = 0;\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
\r
- while (WordCount < ByteCount / 2) {\r
//\r
- // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
+ // Check the INTERRUPT and ERROR bit of BMIS\r
+ // Max transfer number of sectors for one command is 65536(32Mbyte),\r
+ // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
+ // So set the variable Count to 2000, for about 2 second timeout time.\r
//\r
- Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
+ Status = EFI_SUCCESS;\r
+ Count = 2000;\r
+ while (TRUE) {\r
\r
- Status = CheckErrorStatus (IdeDev);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmis,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+ if (((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) != 0) || (Count == 0)) {\r
+ if (((RegisterValue & BMIS_ERROR) != 0) || (Count == 0)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (1000);\r
+ Count --;\r
}\r
\r
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+ IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
//\r
- // Get the byte count for one series of read\r
+ // Read BMIS register and clear ERROR and INTR bit\r
//\r
- if ((WordCount + Increment) > ByteCount / 2) {\r
- Increment = ByteCount / 2 - WordCount;\r
- }\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmis,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
\r
- IDEReadPortWMultiple (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Data,\r
- Increment,\r
- Buffer16\r
- );\r
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
\r
- WordCount += Increment;\r
- Buffer16 += Increment;\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmis,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+ //\r
+ // Read Status Register of IDE device to clear interrupt\r
+ //\r
+ RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);\r
+ //\r
+ // Clear START bit of BMIC register\r
+ //\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
\r
- }\r
+ RegisterValue &= ~((UINT8) BMIC_START);\r
\r
- return CheckErrorStatus (IdeDev);\r
-}\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
\r
-/**\r
- This function is used to send out ATA commands conforms to the\r
- PIO Data Out Protocol, supporting ATA/ATAPI-6 standard\r
+ if ((RegisterValue & BMIS_ERROR) != 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
- Comparing with ATA-3 data out protocol, we have two differents here:<BR>\r
- 1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
- wait will frequently fail... cause writing function return error)\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
+ StartLba += NumberOfBlocks;\r
+ }\r
\r
- 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
- slow down writing performance by 100 times!)\r
+ //\r
+ // Disable interrupt of Select device\r
+ //\r
+ IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);\r
+ DeviceControl |= ATA_CTLREG_IEN_L;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
+ return Status;\r
+}\r
\r
- @param[in] *Buffer buffer contained data transferred from host to device.\r
- @param[in] ByteCount data size in byte unit of the buffer.\r
- @param[in] AtaCommand value of the Command Register\r
- @param[in] StartLba the start LBA of this transaction\r
- @param[in] SectorCount the count of sectors to be transfered\r
\r
- @retval EFI_SUCCESS send out the ATA command and device receive required\r
- data successfully.\r
+/**\r
+ This function is called by the AtaBlkIoReadBlocks() to perform reading from\r
+ media in block unit. The function has been enhanced to support >120GB access \r
+ and transfer at most 65536 blocks per command\r
\r
- @retval EFI_DEVICE_ERROR command sent failed.\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record \r
+ all the information of the IDE device.\r
+ @param DataBuffer A pointer to the destination buffer for the data.\r
+ @param StartLba The starting logical block address to read from on the device media.\r
+ @param NumberOfBlocks The number of transfer data blocks.\r
\r
+ @return status depends on the function DoAtaUdma() returns.\r
**/\r
EFI_STATUS\r
-AtaPioDataOutExt (\r
+AtaUdmaReadExt (\r
IN IDE_BLK_IO_DEV *IdeDev,\r
- IN VOID *Buffer,\r
- IN UINT32 ByteCount,\r
- IN UINT8 AtaCommand,\r
+ IN VOID *DataBuffer,\r
IN EFI_LBA StartLba,\r
- IN UINT16 SectorCount\r
+ IN UINTN NumberOfBlocks\r
)\r
{\r
- UINT8 DevSel;\r
- UINT8 SectorCount8;\r
- UINT8 LbaLow;\r
- UINT8 LbaMid;\r
- UINT8 LbaHigh;\r
- UINTN WordCount;\r
- UINTN Increment;\r
- UINT16 *Buffer16;\r
- EFI_STATUS Status;\r
-\r
- Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Select device. Set bit6 as 1 to indicate LBA mode is used\r
- //\r
- DevSel = (UINT8) (IdeDev->Device << 4);\r
- DevSel |= 0x40;\r
- IDEWritePortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Head,\r
- DevSel\r
- );\r
-\r
- //\r
- // Wait for DRDY singnal asserting.\r
- //\r
- Status = DRDYReady (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Fill feature register if needed\r
- //\r
- if (AtaCommand == ATA_CMD_SET_FEATURES) {\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
- }\r
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadExtOp);\r
+}\r
+/**\r
+ This function is called by the AtaBlkIoReadBlocks() to perform\r
+ reading from media in block unit. The function has been enhanced to\r
+ support >120GB access and transfer at most 65536 blocks per command\r
\r
- //\r
- // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
- //\r
- SectorCount8 = (UINT8) (SectorCount >> 8);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r
+ all the information of the IDE device.\r
+ @param DataBuffer A pointer to the destination buffer for the data.\r
+ @param StartLba The starting logical block address to read from\r
+ on the device media.\r
+ @param NumberOfBlocks The number of transfer data blocks.\r
+ \r
+ @return status depends on the function DoAtaUdma() returns.\r
+**/\r
+EFI_STATUS\r
+AtaUdmaRead (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadOp);\r
+}\r
\r
- SectorCount8 = (UINT8) SectorCount;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+/**\r
+ This function is called by the AtaBlkIoReadBlocks() to perform\r
+ reading from media in block unit. The function has been enhanced to\r
+ support >120GB access and transfer at most 65536 blocks per command\r
\r
- //\r
- // Fill the start LBA registers, which are also two-byte FIFO\r
- //\r
- LbaLow = (UINT8) RShiftU64 (StartLba, 24);\r
- LbaMid = (UINT8) RShiftU64 (StartLba, 32);\r
- LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r
+ all the information of the IDE device.\r
+ @param DataBuffer A pointer to the destination buffer for the data.\r
+ @param StartLba The starting logical block address to read from on the device media.\r
+ @param NumberOfBlocks The number of transfer data blocks.\r
\r
- LbaLow = (UINT8) StartLba;\r
- LbaMid = (UINT8) RShiftU64 (StartLba, 8);\r
- LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+ @return status is fully dependent on the return status of AtaPioDataInExt() function.\r
+**/\r
+EFI_STATUS\r
+AtaReadSectorsExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BlocksRemaining;\r
+ EFI_LBA Lba64;\r
+ UINT8 AtaCommand;\r
+ UINT16 SectorCount;\r
+ UINT32 ByteCount;\r
+ VOID *Buffer;\r
\r
//\r
- // Send command via Command Register, invoking the processing of this command\r
+ // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol\r
//\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
-\r
- Buffer16 = (UINT16 *) Buffer;\r
+ AtaCommand = ATA_CMD_READ_SECTORS_EXT;\r
+ Buffer = DataBuffer;\r
+ BlocksRemaining = NumberOfBlocks;\r
+ Lba64 = StartLba;\r
+ Status = EFI_SUCCESS;\r
\r
- //\r
- // According to PIO Data Out protocol, host can perform a series of writes to\r
- // the data register after each time device set DRQ ready;\r
- //\r
- Increment = 256;\r
+ while (BlocksRemaining > 0) {\r
\r
- //\r
- // used to record bytes of currently transfered data\r
- //\r
- WordCount = 0;\r
+ if (BlocksRemaining >= 0x10000) {\r
+ //\r
+ // SectorCount is used to record the number of sectors to be read\r
+ // Max 65536 sectors can be transfered at a time.\r
+ //\r
+ SectorCount = 0xffff;\r
+ } else {\r
+ SectorCount = (UINT16) BlocksRemaining;\r
+ }\r
\r
- while (WordCount < ByteCount / 2) {\r
//\r
- // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
+ // ByteCount is the number of bytes that will be read\r
//\r
- Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- Status = CheckErrorStatus (IdeDev);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
\r
//\r
- // Write data into device by one series of writing to data register\r
+ // call AtaPioDataInExt() to send Read Sector Command and receive data read\r
//\r
- if ((WordCount + Increment) > ByteCount / 2) {\r
- Increment = ByteCount / 2 - WordCount;\r
+ Status = AtaPioDataInExt (\r
+ IdeDev,\r
+ Buffer,\r
+ ByteCount,\r
+ AtaCommand,\r
+ Lba64,\r
+ SectorCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
\r
- IDEWritePortWMultiple (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Data,\r
- Increment,\r
- Buffer16\r
- );\r
-\r
- WordCount += Increment;\r
- Buffer16 += Increment;\r
-\r
+ Lba64 += SectorCount;\r
+ Buffer = ((UINT8 *) Buffer + ByteCount);\r
+ BlocksRemaining -= SectorCount;\r
}\r
- //\r
- // while\r
- //\r
\r
- return CheckErrorStatus (IdeDev);\r
+ return Status;\r
}\r
+/**\r
+ This function is the ATA implementation for ReadBlocks in the\r
+ Block I/O Protocol interface.\r
\r
+ @param IdeBlkIoDevice Indicates the calling context.\r
+ @param MediaId The media id that the read request is for.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple\r
+ of the intrinsic block size of the device.\r
\r
-/**\r
- Enable SMART of the disk if supported\r
+ @param Buffer A pointer to the destination buffer for the data. The caller\r
+ is responsible for either having implicit or explicit ownership\r
+ of the memory that data is read into.\r
+\r
+ @retval EFI_SUCCESS Read Blocks successfully.\r
+ @retval EFI_DEVICE_ERROR Read Blocks failed.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the data buffer is not valid.\r
\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure,used\r
- to record all the information of the IDE device.\r
+ @note If Read Block error because of device error, this function will call\r
+ AtaSoftReset() function to reset device.\r
\r
**/\r
-VOID\r
-AtaSMARTSupport (\r
- IN IDE_BLK_IO_DEV *IdeDev\r
+EFI_STATUS\r
+AtaBlkIoReadBlocks (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
)\r
{\r
- EFI_STATUS Status;\r
- BOOLEAN SMARTSupported;\r
- UINT8 Device;\r
- EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer;\r
- UINT8 DeviceSelect;\r
- UINT8 LBAMid;\r
- UINT8 LBAHigh;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ EFI_STATUS Status;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
\r
//\r
- // Detect if the device supports S.M.A.R.T.\r
+ // Get the intrinsic block size\r
//\r
- if ((IdeDev->IdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) {\r
- //\r
- // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one)\r
- //\r
- return ;\r
- } else {\r
- if ((IdeDev->IdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
- //\r
- // S.M.A.R.T is not supported by the device\r
- //\r
- SMARTSupported = FALSE;\r
- } else {\r
- SMARTSupported = TRUE;\r
- }\r
+ Media = IdeBlkIoDevice->BlkIo.Media;\r
+ BlockSize = Media->BlockSize;\r
+\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
}\r
\r
- if (!SMARTSupported) {\r
- //\r
- // Report nonsupport status code\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
- (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
- );\r
- } else {\r
- //\r
- // Enable this feature\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_PROGRESS_CODE,\r
- (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
- );\r
+ if (BufferSize % BlockSize != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
\r
- Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
- Status = AtaNonDataCommandIn (\r
- IdeDev,\r
- ATA_CMD_SMART,\r
- Device,\r
- ATA_SMART_ENABLE_OPERATION,\r
- 0,\r
- 0,\r
- ATA_CONSTANT_4F,\r
- ATA_CONSTANT_C2\r
- );\r
+ if (!(Media->MediaPresent)) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ if (LBA > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
//\r
- // Detect if this feature is enabled\r
+ // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism\r
//\r
- TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r
- if (TmpAtaIdentifyPointer == NULL) {\r
- return;\r
- }\r
-\r
- DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
- Status = AtaPioDataIn (\r
- IdeDev,\r
- (VOID *) TmpAtaIdentifyPointer,\r
- sizeof (EFI_IDENTIFY_DATA),\r
- ATA_CMD_IDENTIFY_DRIVE,\r
- DeviceSelect,\r
- 0,\r
- 0,\r
- 0,\r
- 0\r
- );\r
- if (EFI_ERROR (Status)) {\r
- gBS->FreePool (TmpAtaIdentifyPointer);\r
- return ;\r
+ if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+ Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ } else {\r
+ Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
}\r
-\r
+ } else {\r
//\r
- // Check if the feature is enabled\r
+ // For ATA-3 compatible device, use ATA-3 read block mechanism\r
//\r
- if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) {\r
- //\r
- // Read status data\r
- //\r
- AtaNonDataCommandIn (\r
- IdeDev,\r
- ATA_CMD_SMART,\r
- Device,\r
- ATA_SMART_RETURN_STATUS,\r
- 0,\r
- 0,\r
- ATA_CONSTANT_4F,\r
- ATA_CONSTANT_C2\r
- );\r
- LBAMid = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);\r
- LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb);\r
-\r
- if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
- //\r
- // The threshold exceeded condition is not detected by the device\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_PROGRESS_CODE,\r
- (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
- );\r
-\r
- } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
- //\r
- // The threshold exceeded condition is detected by the device\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_PROGRESS_CODE,\r
- (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
- );\r
- }\r
-\r
+ if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+ Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
} else {\r
- //\r
- // Report disabled status code\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
- (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
- );\r
+ Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
}\r
+ }\r
\r
- gBS->FreePool (TmpAtaIdentifyPointer);\r
+ if (EFI_ERROR (Status)) {\r
+ AtaSoftReset (IdeBlkIoDevice);\r
+ return EFI_DEVICE_ERROR;\r
}\r
\r
- return ;\r
-}\r
+ return EFI_SUCCESS;\r
\r
+}\r
/**\r
- Enable Long Physical Sector Feature for ATA device.\r
+ This function is used to send out ATA commands conforms to the\r
+ PIO Data Out Protocol, supporting ATA/ATAPI-6 standard\r
\r
- @param IdeDev The IDE device data\r
+ Comparing with ATA-3 data out protocol, we have two differents here:<BR>\r
+ 1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
+ wait will frequently fail... cause writing function return error)\r
+\r
+ 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
+ slow down writing performance by 100 times!)\r
+\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+ @param Buffer buffer contained data transferred from host to device.\r
+ @param ByteCount data size in byte unit of the buffer.\r
+ @param AtaCommand value of the Command Register\r
+ @param StartLba the start LBA of this transaction\r
+ @param SectorCount the count of sectors to be transfered\r
+\r
+ @retval EFI_SUCCESS send out the ATA command and device receive required\r
+ data successfully.\r
+ @retval EFI_DEVICE_ERROR command sent failed.\r
\r
- @retval EFI_SUCCESS The ATA device supports Long Physical Sector feature\r
- and corresponding fields in BlockIo structure is updated.\r
- @retval EFI_UNSUPPORTED The device is not ATA device or Long Physical Sector\r
- feature is not supported.\r
**/\r
EFI_STATUS\r
-AtaEnableLongPhysicalSector (\r
- IN IDE_BLK_IO_DEV *IdeDev\r
+AtaPioDataOutExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN UINT8 AtaCommand,\r
+ IN EFI_LBA StartLba,\r
+ IN UINT16 SectorCount\r
)\r
{\r
- EFI_ATA_IDENTIFY_DATA *AtaIdentifyData;\r
- UINT16 PhyLogicSectorSupport;\r
+ UINT8 DevSel;\r
+ UINT8 SectorCount8;\r
+ UINT8 LbaLow;\r
+ UINT8 LbaMid;\r
+ UINT8 LbaHigh;\r
+ UINTN WordCount;\r
+ UINTN Increment;\r
+ UINT16 *Buffer16;\r
+ EFI_STATUS Status;\r
+\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
- ASSERT (IdeDev->IdData != NULL);\r
//\r
- // Only valid for ATA device\r
+ // Select device. Set bit6 as 1 to indicate LBA mode is used\r
//\r
- AtaIdentifyData = (EFI_ATA_IDENTIFY_DATA *) &IdeDev->IdData->AtaData;\r
- if ((AtaIdentifyData->config & 0x8000) != 0) {\r
- return EFI_UNSUPPORTED;\r
- }\r
- PhyLogicSectorSupport = AtaIdentifyData->phy_logic_sector_support;\r
+ DevSel = (UINT8) (IdeDev->Device << 4);\r
+ DevSel |= 0x40;\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ DevSel\r
+ );\r
+\r
//\r
- // Check whether Long Physical Sector Feature is supported\r
- //\r
- if ((PhyLogicSectorSupport & 0xc000) == 0x4000) {\r
- IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 1;\r
- IdeDev->BlkIo.Media->LowestAlignedLba = 0;\r
- //\r
- // Check whether one physical block contains multiple physical blocks\r
- //\r
- if ((PhyLogicSectorSupport & 0x2000) != 0) {\r
- IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock =\r
- (UINT32) (1 << (PhyLogicSectorSupport & 0x000f));\r
- //\r
- // Check lowest alignment of logical blocks within physical block\r
- //\r
- if ((AtaIdentifyData->alignment_logic_in_phy_blocks & 0xc000) == 0x4000) {\r
- IdeDev->BlkIo.Media->LowestAlignedLba =\r
- (EFI_LBA) (AtaIdentifyData->alignment_logic_in_phy_blocks & 0x3fff);\r
- }\r
- }\r
- //\r
- // Check logical block size\r
- //\r
- IdeDev->BlkIo.Media->BlockSize = 0x200;\r
- if ((PhyLogicSectorSupport & 0x1000) != 0) {\r
- IdeDev->BlkIo.Media->BlockSize = (UINT32) (\r
- ((AtaIdentifyData->logic_sector_size_hi << 16) |\r
- AtaIdentifyData->logic_sector_size_lo) * sizeof (UINT16)\r
- );\r
- }\r
- return EFI_SUCCESS;\r
- } else {\r
- return EFI_UNSUPPORTED;\r
- }\r
-}\r
-\r
-\r
-/**\r
- Send ATA Ext command into device with NON_DATA protocol\r
-\r
- @param IdeDev Standard IDE device private data structure\r
- @param AtaCommand The ATA command to be sent\r
- @param Device The value in Device register\r
- @param Feature The value in Feature register\r
- @param SectorCount The value in SectorCount register\r
- @param LbaAddress The LBA address in 48-bit mode\r
-\r
- @retval EFI_SUCCESS Reading succeed\r
- @retval EFI_DEVICE_ERROR Error executing commands on this device.\r
-\r
-**/\r
-EFI_STATUS\r
-AtaCommandIssueExt (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN UINT8 AtaCommand,\r
- IN UINT8 Device,\r
- IN UINT16 Feature,\r
- IN UINT16 SectorCount,\r
- IN EFI_LBA LbaAddress\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT8 SectorCount8;\r
- UINT8 Feature8;\r
- UINT8 LbaLow;\r
- UINT8 LbaMid;\r
- UINT8 LbaHigh;\r
-\r
- Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
- //\r
- IDEWritePortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Head,\r
- (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
- );\r
-\r
- //\r
- // ATA commands for ATA device must be issued when DRDY is set\r
+ // Wait for DRDY singnal asserting.\r
//\r
Status = DRDYReady (IdeDev, ATATIMEOUT);\r
if (EFI_ERROR (Status)) {\r
}\r
\r
//\r
- // Pass parameter into device register block\r
- //\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
-\r
- //\r
- // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+ // Fill feature register if needed\r
//\r
- Feature8 = (UINT8) (Feature >> 8);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
-\r
- Feature8 = (UINT8) Feature;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+ if (AtaCommand == ATA_CMD_SET_FEATURES) {\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
+ }\r
\r
//\r
// Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
//\r
// Fill the start LBA registers, which are also two-byte FIFO\r
//\r
- LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
- LbaLow = (UINT8) LbaAddress;\r
+ LbaLow = (UINT8) RShiftU64 (StartLba, 24);\r
+ LbaMid = (UINT8) RShiftU64 (StartLba, 32);\r
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r
IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
-\r
- LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
- LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
-\r
- LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
- LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
\r
- //\r
- // Work around for Segate 160G disk writing\r
- //\r
- gBS->Stall (1800);\r
+ LbaLow = (UINT8) StartLba;\r
+ LbaMid = (UINT8) RShiftU64 (StartLba, 8);\r
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
\r
//\r
- // Send command via Command Register\r
+ // Send command via Command Register, invoking the processing of this command\r
//\r
IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
\r
- //\r
- // Stall at least 400ns\r
- //\r
- gBS->Stall (100);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Send ATA Ext command into device with NON_DATA protocol\r
-\r
- @param IdeDev Standard IDE device private data structure\r
- @param AtaCommand The ATA command to be sent\r
- @param Device The value in Device register\r
- @param Feature The value in Feature register\r
- @param SectorCount The value in SectorCount register\r
- @param LbaAddress The LBA address in 48-bit mode\r
-\r
- @retval EFI_SUCCESS Reading succeed\r
- @retval EFI_DEVICE_ERROR Error executing commands on this device.\r
-\r
-**/\r
-EFI_STATUS\r
-AtaCommandIssue (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN UINT8 AtaCommand,\r
- IN UINT8 Device,\r
- IN UINT16 Feature,\r
- IN UINT16 SectorCount,\r
- IN EFI_LBA LbaAddress\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT8 SectorCount8;\r
- UINT8 Feature8;\r
- UINT8 Lba0;\r
- UINT8 Lba1;\r
- UINT8 Lba2;\r
- UINT8 Lba3;\r
-\r
- Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
- //\r
- IDEWritePortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Head,\r
- (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
- );\r
-\r
- //\r
- // ATA commands for ATA device must be issued when DRDY is set\r
- //\r
- Status = DRDYReady (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- Lba0 = (UINT8) LbaAddress;\r
- Lba1 = (UINT8) RShiftU64 (LbaAddress, 8);\r
- Lba2 = (UINT8) RShiftU64 (LbaAddress, 16);\r
- Lba3 = (UINT8) RShiftU64 (LbaAddress, 24);\r
- Device = (UINT8) (Device | Lba3);\r
+ Buffer16 = (UINT16 *) Buffer;\r
\r
//\r
- // Pass parameter into device register block\r
+ // According to PIO Data Out protocol, host can perform a series of writes to\r
+ // the data register after each time device set DRQ ready;\r
//\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+ Increment = 256;\r
\r
//\r
- // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+ // used to record bytes of currently transfered data\r
//\r
- Feature8 = (UINT8) Feature;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+ WordCount = 0;\r
\r
- //\r
- // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
- //\r
- SectorCount8 = (UINT8) SectorCount;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+ while (WordCount < ByteCount / 2) {\r
+ //\r
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
+ //\r
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
- //\r
- // Fill the start LBA registers, which are also two-byte FIFO\r
- //\r
+ Status = CheckErrorStatus (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2);\r
+ //\r
+ // Write data into device by one series of writing to data register\r
+ //\r
+ if ((WordCount + Increment) > ByteCount / 2) {\r
+ Increment = ByteCount / 2 - WordCount;\r
+ }\r
\r
- //\r
- // Send command via Command Register\r
- //\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+ IDEWritePortWMultiple (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Data,\r
+ Increment,\r
+ Buffer16\r
+ );\r
\r
- //\r
- // Stall at least 400ns\r
- //\r
- gBS->Stall (100);\r
+ WordCount += Increment;\r
+ Buffer16 += Increment;\r
\r
- return EFI_SUCCESS;\r
+ }\r
+ return CheckErrorStatus (IdeDev);\r
}\r
-\r
/**\r
- This function is called by the AtaBlkIoReadBlocks() to perform\r
- reading from media in block unit. The function has been enhanced to\r
+ This function is called by the AtaBlkIoWriteBlocks() to perform\r
+ writing to media in block unit. The function has been enhanced to\r
support >120GB access and transfer at most 65536 blocks per command\r
\r
- @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *DataBuffer A pointer to the destination buffer for the data.\r
-\r
- @param[in] StartLba The starting logical block address to read from\r
- on the device media.\r
-\r
- @param[in] NumberOfBlocks The number of transfer data blocks.\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+ @param DataBuffer A pointer to the source buffer for the data.\r
+ @param StartLba The starting logical block address to write to\r
+ on the device media.\r
+ @param NumberOfBlocks The number of transfer data blocks.\r
\r
- @return The device status of UDMA operation. If the operation is\r
- successful, return EFI_SUCCESS.\r
-\r
- TODO: EFI_UNSUPPORTED - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ @return status depends on the function DoAtaUdma() returns.\r
**/\r
EFI_STATUS\r
-AtaUdmaReadExt (\r
+AtaUdmaWriteExt (\r
IN IDE_BLK_IO_DEV *IdeDev,\r
IN VOID *DataBuffer,\r
IN EFI_LBA StartLba,\r
IN UINTN NumberOfBlocks\r
)\r
{\r
- return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadExtOp);\r
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);\r
}\r
\r
/**\r
- This function is called by the AtaBlkIoReadBlocks() to perform\r
- reading from media in block unit. The function has been enhanced to\r
- support >120GB access and transfer at most 65536 blocks per command\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *DataBuffer A pointer to the destination buffer for the data.\r
- @param[in] StartLba The starting logical block address to read from\r
- on the device media.\r
- @param[in] NumberOfBlocks The number of transfer data blocks.\r
-\r
- @return The device status of UDMA operation. If the operation is\r
- successful, return EFI_SUCCESS.\r
-\r
- TODO: EFI_UNSUPPORTED - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ This function is called by the AtaBlkIoWriteBlocks() to perform\r
+ writing to media in block unit. \r
+\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+ @param DataBuffer A pointer to the source buffer for the data.\r
+ @param StartLba The starting logical block address to write to\r
+ on the device media.\r
+ @param NumberOfBlocks The number of transfer data blocks.\r
+ \r
+ @return status depends on the function DoAtaUdma() returns.\r
**/\r
EFI_STATUS\r
-AtaUdmaRead (\r
+AtaUdmaWrite (\r
IN IDE_BLK_IO_DEV *IdeDev,\r
IN VOID *DataBuffer,\r
IN EFI_LBA StartLba,\r
IN UINTN NumberOfBlocks\r
)\r
{\r
- return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadOp);\r
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp);\r
}\r
-\r
/**\r
This function is called by the AtaBlkIoWriteBlocks() to perform\r
- writing to media in block unit. The function has been enhanced to\r
+ writing onto media in block unit. The function has been enhanced to\r
support >120GB access and transfer at most 65536 blocks per command\r
\r
- @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *DataBuffer A pointer to the source buffer for the data.\r
-\r
- @param[in] StartLba The starting logical block address to write to\r
- on the device media.\r
-\r
- @param[in] NumberOfBlocks The number of transfer data blocks.\r
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+ to record all the information of the IDE device.\r
+ @param DataBuffer A pointer to the source buffer for the data.\r
+ @param StartLba The starting logical block address to write onto the device \r
+ media.\r
+ @param NumberOfBlocks The number of transfer data blocks.\r
\r
- @return The device status of UDMA operation. If the operation is\r
- successful, return EFI_SUCCESS.\r
-\r
- TODO: EFI_UNSUPPORTED - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ @return status is fully dependent on the return status of AtaPioDataOutExt() function.\r
**/\r
EFI_STATUS\r
-AtaUdmaWriteExt (\r
+AtaWriteSectorsExt (\r
IN IDE_BLK_IO_DEV *IdeDev,\r
IN VOID *DataBuffer,\r
IN EFI_LBA StartLba,\r
IN UINTN NumberOfBlocks\r
)\r
{\r
- return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);\r
-}\r
+ EFI_STATUS Status;\r
+ EFI_LBA Lba64;\r
+ UINTN BlocksRemaining;\r
+ UINT8 AtaCommand;\r
+ UINT16 SectorCount;\r
+ UINT32 ByteCount;\r
+ VOID *Buffer;\r
\r
-/**\r
- This function is called by the AtaBlkIoWriteBlocks() to perform\r
- writing to media in block unit. The function has been enhanced to\r
- support >120GB access and transfer at most 65536 blocks per command\r
+ //\r
+ // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol\r
+ //\r
+ AtaCommand = ATA_CMD_WRITE_SECTORS_EXT;\r
+ Lba64 = StartLba;\r
+ Buffer = DataBuffer;\r
+ BlocksRemaining = NumberOfBlocks;\r
+\r
+ Status = EFI_SUCCESS;\r
\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
+ while (BlocksRemaining > 0) {\r
\r
- @param[in] *DataBuffer\r
- A pointer to the source buffer for the data.\r
+ if (BlocksRemaining >= 0x10000) {\r
+ //\r
+ // SectorCount is used to record the number of sectors to be written.\r
+ // Max 65536 sectors can be transfered at a time.\r
+ //\r
+ SectorCount = 0xffff;\r
+ } else {\r
+ SectorCount = (UINT16) BlocksRemaining;\r
+ }\r
\r
- @param[in] StartLba\r
- The starting logical block address to write to\r
- on the device media.\r
+ //\r
+ // ByteCount is the number of bytes that will be written\r
+ //\r
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
\r
- @param[in] NumberOfBlocks\r
- The number of transfer data blocks.\r
+ //\r
+ // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command\r
+ //\r
+ Status = AtaPioDataOutExt (\r
+ IdeDev,\r
+ Buffer,\r
+ ByteCount,\r
+ AtaCommand,\r
+ Lba64,\r
+ SectorCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
\r
- @return The device status of UDMA operation. If the operation is\r
- successful, return EFI_SUCCESS.\r
+ Lba64 += SectorCount;\r
+ Buffer = ((UINT8 *) Buffer + ByteCount);\r
+ BlocksRemaining -= SectorCount;\r
+ }\r
\r
- TODO: EFI_UNSUPPORTED - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
-**/\r
-EFI_STATUS\r
-AtaUdmaWrite (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN VOID *DataBuffer,\r
- IN EFI_LBA StartLba,\r
- IN UINTN NumberOfBlocks\r
- )\r
-{\r
- return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp);\r
+ return Status;\r
}\r
-\r
/**\r
- Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *DataBuffer\r
- A pointer to the source buffer for the data.\r
-\r
- @param[in] StartLba\r
- The starting logical block address to write to\r
- on the device media.\r
+ This function is the ATA implementation for WriteBlocks in the\r
+ Block I/O Protocol interface.\r
\r
- @param[in] NumberOfBlocks\r
- The number of transfer data blocks.\r
+ @param IdeBlkIoDevice Indicates the calling context.\r
+ @param MediaId The media id that the write request is for.\r
+ @param LBA The starting logical block address to write onto the device.\r
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple\r
+ of the intrinsic block size of the device.\r
+ @param Buffer A pointer to the source buffer for the data.The caller\r
+ is responsible for either having implicit or explicit \r
+ ownership of the memory that data is written from.\r
\r
- @param[in] UdmaOp\r
- The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,\r
- AtaUdmaWriteOp, AtaUdmaWriteExOp\r
+ @retval EFI_SUCCESS Write Blocks successfully.\r
+ @retval EFI_DEVICE_ERROR Write Blocks failed.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.\r
\r
- @return The device status of UDMA operation. If the operation is\r
- successful, return EFI_SUCCESS.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the data buffer is not valid.\r
\r
+ @note If Write Block error because of device error, this function will call\r
+ AtaSoftReset() function to reset device.\r
**/\r
EFI_STATUS\r
-DoAtaUdma (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN VOID *DataBuffer,\r
- IN EFI_LBA StartLba,\r
- IN UINTN NumberOfBlocks,\r
- IN ATA_UDMA_OPERATION UdmaOp\r
+AtaBlkIoWriteBlocks (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
)\r
{\r
- IDE_DMA_PRD *PrdAddr;\r
- IDE_DMA_PRD *UsedPrdAddr;\r
- IDE_DMA_PRD *TempPrdAddr;\r
- UINT8 RegisterValue;\r
- UINT8 Device;\r
- UINT64 IoPortForBmic;\r
- UINT64 IoPortForBmis;\r
- UINT64 IoPortForBmid;\r
- EFI_STATUS Status;\r
- UINTN PrdTableNum;\r
- UINTN ByteCount;\r
- UINTN ByteAvailable;\r
- UINT8 *PrdBuffer;\r
- UINTN RemainBlockNum;\r
- UINT8 DeviceControl;\r
- UINT32 Count;\r
- UINTN PageCount;\r
- VOID *Map;\r
- VOID *MemPage;\r
- EFI_PHYSICAL_ADDRESS DeviceAddress;\r
- UINTN MaxDmaCommandSectors;\r
- EFI_PCI_IO_PROTOCOL_OPERATION PciIoProtocolOp;\r
- UINT8 AtaCommand;\r
\r
- switch (UdmaOp) {\r
- case AtaUdmaReadOp:\r
- MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;\r
- PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;\r
- AtaCommand = ATA_CMD_READ_DMA;\r
- break;\r
- case AtaUdmaReadExtOp:\r
- MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;\r
- PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;\r
- AtaCommand = ATA_CMD_READ_DMA_EXT;\r
- break;\r
- case AtaUdmaWriteOp:\r
- MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;\r
- PciIoProtocolOp = EfiPciIoOperationBusMasterRead;\r
- AtaCommand = ATA_CMD_WRITE_DMA;\r
- break;\r
- case AtaUdmaWriteExtOp:\r
- MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;\r
- PciIoProtocolOp = EfiPciIoOperationBusMasterRead;\r
- AtaCommand = ATA_CMD_WRITE_DMA_EXT;\r
- break;\r
- default:\r
- return EFI_UNSUPPORTED;\r
- break;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ EFI_STATUS Status;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
}\r
\r
- //\r
- // Select device\r
- //\r
- Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
\r
//\r
- // Enable interrupt to support UDMA\r
+ // Get the intrinsic block size\r
//\r
- DeviceControl = 0;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+ Media = IdeBlkIoDevice->BlkIo.Media;\r
+ BlockSize = Media->BlockSize;\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
\r
- if (IdePrimary == IdeDev->Channel) {\r
- IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
- IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
- IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
- } else {\r
- if (IdeSecondary == IdeDev->Channel) {\r
- IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
- IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
- IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
- } else {\r
- return EFI_UNSUPPORTED;\r
- }\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
}\r
\r
- //\r
- // Read BMIS register and clear ERROR and INTR bit\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
- \r
- RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
- \r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
+ if (BufferSize % BlockSize != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
\r
- Status = EFI_SUCCESS;\r
- \r
- RemainBlockNum = NumberOfBlocks;\r
- while (RemainBlockNum > 0) {\r
+ if (LBA > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
- if (RemainBlockNum >= MaxDmaCommandSectors) {\r
- //\r
- // SectorCount is used to record the number of sectors to be read\r
- // Max 65536 sectors can be transfered at a time.\r
- //\r
- NumberOfBlocks = MaxDmaCommandSectors;\r
- RemainBlockNum -= MaxDmaCommandSectors;\r
- } else {\r
- NumberOfBlocks = (UINT16) RemainBlockNum;\r
- RemainBlockNum = 0;\r
- }\r
+ if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
- //\r
- // Calculate the number of PRD table to make sure the memory region\r
- // not cross 64K boundary\r
- //\r
- ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
- PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
+ Status = EFI_SUCCESS;\r
+ if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
//\r
- // Build PRD table\r
+ // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism\r
//\r
- PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
- Status = IdeDev->PciIo->AllocateBuffer (\r
- IdeDev->PciIo,\r
- AllocateAnyPages,\r
- EfiBootServicesData,\r
- PageCount,\r
- &MemPage,\r
- 0\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));\r
-\r
- PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);\r
- //\r
- // To make sure PRD is allocated in one 64K page\r
- //\r
- if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
- UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
+ if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+ Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
} else {\r
- if ((UINTN) PrdAddr & 0x03) {\r
- UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
- } else {\r
- UsedPrdAddr = PrdAddr;\r
- }\r
+ Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
}\r
-\r
+ } else {\r
//\r
- // Build the PRD table\r
+ // For ATA-3 compatible device, use ATA-3 write block mechanism\r
//\r
- Status = IdeDev->PciIo->Map (\r
- IdeDev->PciIo,\r
- PciIoProtocolOp,\r
- DataBuffer,\r
- &ByteCount,\r
- &DeviceAddress,\r
- &Map\r
- );\r
- if (EFI_ERROR (Status)) {\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- return EFI_OUT_OF_RESOURCES;\r
+ if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+ Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ } else {\r
+ Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
}\r
- PrdBuffer = (VOID *) ((UINTN) DeviceAddress);\r
- TempPrdAddr = UsedPrdAddr;\r
- while (TRUE) {\r
+ }\r
\r
- ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
+ if (EFI_ERROR (Status)) {\r
+ AtaSoftReset (IdeBlkIoDevice);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
- if (ByteCount <= ByteAvailable) {\r
- TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
- TempPrdAddr->ByteCount = (UINT16) ByteCount;\r
- TempPrdAddr->EndOfTable = 0x8000;\r
- break;\r
- }\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Enable Long Physical Sector Feature for ATA device.\r
\r
- TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
- TempPrdAddr->ByteCount = (UINT16) ByteAvailable;\r
+ @param IdeDev The IDE device data\r
\r
- ByteCount -= ByteAvailable;\r
- PrdBuffer += ByteAvailable;\r
- TempPrdAddr++;\r
- }\r
+ @retval EFI_SUCCESS The ATA device supports Long Physical Sector feature\r
+ and corresponding fields in BlockIo structure is updated.\r
+ @retval EFI_UNSUPPORTED The device is not ATA device or Long Physical Sector\r
+ feature is not supported.\r
+**/\r
+EFI_STATUS\r
+AtaEnableLongPhysicalSector (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ EFI_ATA_IDENTIFY_DATA *AtaIdentifyData;\r
+ UINT16 PhyLogicSectorSupport;\r
\r
+ ASSERT (IdeDev->IdData != NULL);\r
+ //\r
+ // Only valid for ATA device\r
+ //\r
+ AtaIdentifyData = (EFI_ATA_IDENTIFY_DATA *) &IdeDev->IdData->AtaData;\r
+ if ((AtaIdentifyData->config & 0x8000) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ PhyLogicSectorSupport = AtaIdentifyData->phy_logic_sector_support;\r
+ //\r
+ // Check whether Long Physical Sector Feature is supported\r
+ //\r
+ if ((PhyLogicSectorSupport & 0xc000) == 0x4000) {\r
+ IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 1;\r
+ IdeDev->BlkIo.Media->LowestAlignedLba = 0;\r
//\r
- // Set the base address to BMID register\r
+ // Check whether one physical block contains multiple physical blocks\r
//\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint32,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmid,\r
- 1,\r
- &UsedPrdAddr\r
- );\r
-\r
+ if ((PhyLogicSectorSupport & 0x2000) != 0) {\r
+ IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock =\r
+ (UINT32) (1 << (PhyLogicSectorSupport & 0x000f));\r
+ //\r
+ // Check lowest alignment of logical blocks within physical block\r
+ //\r
+ if ((AtaIdentifyData->alignment_logic_in_phy_blocks & 0xc000) == 0x4000) {\r
+ IdeDev->BlkIo.Media->LowestAlignedLba =\r
+ (EFI_LBA) (AtaIdentifyData->alignment_logic_in_phy_blocks & 0x3fff);\r
+ }\r
+ }\r
//\r
- // Set BMIC register to identify the operation direction\r
+ // Check logical block size\r
//\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) {\r
- RegisterValue |= BMIC_NREAD;\r
- } else {\r
- RegisterValue &= ~((UINT8) BMIC_NREAD);\r
+ IdeDev->BlkIo.Media->BlockSize = 0x200;\r
+ if ((PhyLogicSectorSupport & 0x1000) != 0) {\r
+ IdeDev->BlkIo.Media->BlockSize = (UINT32) (\r
+ ((AtaIdentifyData->logic_sector_size_hi << 16) |\r
+ AtaIdentifyData->logic_sector_size_lo) * sizeof (UINT16)\r
+ );\r
}\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+}\r
+/**\r
+ Send ATA command into device with NON_DATA protocol\r
\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
+ @param IdeDev Standard IDE device private data structure\r
+ @param AtaCommand The ATA command to be sent\r
+ @param Device The value in Device register\r
+ @param Feature The value in Feature register\r
+ @param SectorCount The value in SectorCount register\r
+ @param LbaLow The value in LBA_LOW register\r
+ @param LbaMiddle The value in LBA_MIDDLE register\r
+ @param LbaHigh The value in LBA_HIGH register\r
\r
- if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) {\r
- Status = AtaCommandIssueExt (\r
- IdeDev,\r
- AtaCommand,\r
- Device,\r
- 0,\r
- (UINT16) NumberOfBlocks,\r
- StartLba\r
- );\r
- } else {\r
- Status = AtaCommandIssue (\r
- IdeDev,\r
- AtaCommand,\r
- Device,\r
- 0,\r
- (UINT16) NumberOfBlocks,\r
- StartLba\r
- );\r
- }\r
+ @retval EFI_SUCCESS Reading succeed\r
+ @retval EFI_ABORTED Command failed\r
+ @retval EFI_DEVICE_ERROR Device status error.\r
\r
- if (EFI_ERROR (Status)) {\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
- return EFI_DEVICE_ERROR;\r
- }\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandIn (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT8 Feature,\r
+ IN UINT8 SectorCount,\r
+ IN UINT8 LbaLow,\r
+ IN UINT8 LbaMiddle,\r
+ IN UINT8 LbaHigh\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 StatusRegister;\r
\r
- //\r
- // Set START bit of BMIC register\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
- RegisterValue |= BMIC_START;\r
+ //\r
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+ );\r
\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
+ //\r
+ // ATA commands for ATA device must be issued when DRDY is set\r
+ //\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
- //\r
- // Check the INTERRUPT and ERROR bit of BMIS\r
- // Max transfer number of sectors for one command is 65536(32Mbyte),\r
- // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
- // So set the variable Count to 2000, for about 2 second timeout time.\r
- //\r
- Status = EFI_SUCCESS;\r
- Count = 2000;\r
- while (TRUE) {\r
+ //\r
+ // Pass parameter into device register block\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
- if (((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) != 0) || (Count == 0)) {\r
- if (((RegisterValue & BMIS_ERROR) != 0) || (Count == 0)) {\r
- Status = EFI_DEVICE_ERROR;\r
- break;\r
- }\r
- break;\r
- }\r
+ //\r
+ // Send command via Command Register\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
\r
- gBS->Stall (1000);\r
- Count --;\r
- }\r
+ //\r
+ // Wait for command completion\r
+ // For ATAPI_SMART_CMD, we may need more timeout to let device\r
+ // adjust internal states.\r
+ //\r
+ if (AtaCommand == ATA_CMD_SMART) {\r
+ Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);\r
+ } else {\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+ if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
//\r
- // Read BMIS register and clear ERROR and INTR bit\r
+ // Failed to execute command, abort operation\r
//\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
+ return EFI_ABORTED;\r
+ }\r
\r
- RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+ return EFI_SUCCESS;\r
+}\r
\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
- //\r
- // Read Status Register of IDE device to clear interrupt\r
- //\r
- RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);\r
- //\r
- // Clear START bit of BMIC register\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
+/**\r
+ Send ATA Ext command into device with NON_DATA protocol\r
\r
- RegisterValue &= ~((UINT8) BMIC_START);\r
+ @param IdeDev Standard IDE device private data structure\r
+ @param AtaCommand The ATA command to be sent\r
+ @param Device The value in Device register\r
+ @param Feature The value in Feature register\r
+ @param SectorCount The value in SectorCount register\r
+ @param LbaAddress The LBA address in 48-bit mode\r
\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
+ @retval EFI_SUCCESS Reading succeed\r
+ @retval EFI_ABORTED Command failed\r
+ @retval EFI_DEVICE_ERROR Device status error.\r
\r
- if ((RegisterValue & BMIS_ERROR) != 0) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandInExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT16 Feature,\r
+ IN UINT16 SectorCount,\r
+ IN EFI_LBA LbaAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 StatusRegister;\r
+ UINT8 SectorCount8;\r
+ UINT8 Feature8;\r
+ UINT8 LbaLow;\r
+ UINT8 LbaMid;\r
+ UINT8 LbaHigh;\r
\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
- DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
- StartLba += NumberOfBlocks;\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
}\r
\r
//\r
- // Disable interrupt of Select device\r
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
//\r
- IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);\r
- DeviceControl |= ATA_CTLREG_IEN_L;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+ );\r
\r
- return Status;\r
+ //\r
+ // ATA commands for ATA device must be issued when DRDY is set\r
+ //\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Pass parameter into device register block\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+\r
+ //\r
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ Feature8 = (UINT8) (Feature >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+ Feature8 = (UINT8) Feature;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+ //\r
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ SectorCount8 = (UINT8) (SectorCount >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ SectorCount8 = (UINT8) SectorCount;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ //\r
+ // Fill the start LBA registers, which are also two-byte FIFO\r
+ //\r
+ LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ LbaLow = (UINT8) LbaAddress;\r
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ //\r
+ // Send command via Command Register\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+ //\r
+ // Wait for command completion\r
+ //\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+ if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
+ //\r
+ // Failed to execute command, abort operation\r
+ //\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
}\r
\r
+\r
+\r