1. Changed device detect method to use ATA/ATAPI device signature;

2. Enhancements to better support SATA CDROM;
3. Fixed UDMA operation for buffer above 4G memory issue;
4. Fixed maximal block setting for ATAPI read sector operation to comply with spec;
5. Some minor fixes.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1739 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
jtang12 2006-10-13 05:51:59 +00:00
parent c51cec2560
commit a98f11c5b9
7 changed files with 1100 additions and 983 deletions

View File

@ -988,6 +988,10 @@ AtaSoftReset (
IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
//
// SRST should assert for at least 5 us, we use 10 us for
// better compatibility
//
gBS->Stall (10);
//
@ -996,6 +1000,11 @@ AtaSoftReset (
DeviceControl = 0;
IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
//
// Wait for at least 2 ms to check BSY status, we use 10 ms
// for better compatibility
//
gBS->Stall(10000);
//
// slave device needs at most 31s to clear BSY
//
@ -1114,13 +1123,9 @@ AtaBlkIoReadBlocks (
} else {
//
// For ATA-3 compatible device, use ATA-3 read block mechanism
// Notice DMA operation can only handle 32bit address
//
if ((UINTN) Buffer <= 0xFFFFFFFF) {
Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
}
if (EFI_ERROR (Status) || ((UINTN) Buffer > 0xFFFFFFFF)) {
if (EFI_ERROR (Status)) {
Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
}
}
@ -1241,7 +1246,7 @@ AtaBlkIoWriteBlocks (
// For ATA-3 compatible device, use ATA-3 write block mechanism
//
Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
if (EFI_ERROR (Status) || ((UINTN) Buffer > 0xFFFFFFFF)) {
if (EFI_ERROR (Status)) {
Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
}
}
@ -2154,6 +2159,11 @@ AtaUdmaReadExt (
UINT8 *PrdBuffer;
UINTN RemainBlockNum;
UINT8 DeviceControl;
UINT32 Count;
UINTN PageCount;
VOID *Map;
EFI_PHYSICAL_ADDRESS MemPage;
EFI_PHYSICAL_ADDRESS DeviceAddress;
//
// Channel and device differential. Select device.
@ -2207,7 +2217,20 @@ AtaUdmaReadExt (
//
// Build PRD table
//
PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));
MemPage = 0xFFFFFFFF;
PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiBootServicesData,
PageCount,
&MemPage
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));
PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);
//
// To make sure PRD is allocated in one 64K page
@ -2225,7 +2248,19 @@ AtaUdmaReadExt (
//
// Build the PRD table
//
PrdBuffer = DataBuffer;
Status = IdeDev->PciIo->Map (
IdeDev->PciIo,
EfiPciIoOperationBusMasterWrite,
DataBuffer,
&ByteCount,
&DeviceAddress,
&Map
);
if (EFI_ERROR (Status)) {
gBS->FreePages (MemPage, PageCount);
return EFI_OUT_OF_RESOURCES;
}
PrdBuffer = (VOID *) ((UINTN) DeviceAddress);
TempPrdAddr = UsedPrdAddr;
while (TRUE) {
@ -2316,7 +2351,8 @@ AtaUdmaReadExt (
StartLba
);
if (EFI_ERROR (Status)) {
gBS->FreePool (PrdAddr);
gBS->FreePages (MemPage, PageCount);
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
return EFI_DEVICE_ERROR;
}
@ -2345,7 +2381,11 @@ AtaUdmaReadExt (
//
// Check the INTERRUPT and ERROR bit of BMIS
// Max transfer number of sectors for one command is 65536(32Mbyte),
// it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).
// So set the variable Count to 2000, for about 2 second timeout time.
//
Count = 2000;
while (TRUE) {
IdeDev->PciIo->Io.Read (
@ -2356,21 +2396,49 @@ AtaUdmaReadExt (
1,
&RegisterValue
);
if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {
if (RegisterValue & BMIS_ERROR) {
gBS->FreePool (PrdAddr);
if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) {
if ((RegisterValue & BMIS_ERROR) || (Count == 0)) {
//
// Clear START bit of BMIC register before return EFI_DEVICE_ERROR
//
IdeDev->PciIo->Io.Read (
IdeDev->PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
IoPortForBmic,
1,
&RegisterValue
);
RegisterValue &= ~((UINT8)BMIC_START);
IdeDev->PciIo->Io.Write (
IdeDev->PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
IoPortForBmic,
1,
&RegisterValue
);
gBS->FreePages (MemPage, PageCount);
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
return EFI_DEVICE_ERROR;
}
break;
}
gBS->Stall (1000);
Count --;
}
gBS->FreePool (PrdAddr);
gBS->FreePages (MemPage, PageCount);
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
//
// Set START bit of BMIC register
// Read Status Register of IDE device to clear interrupt
//
RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);
//
// Clear START bit of BMIC register
//
IdeDev->PciIo->Io.Read (
IdeDev->PciIo,
@ -2400,6 +2468,13 @@ AtaUdmaReadExt (
StartLba += NumberOfBlocks;
}
//
// Disable interrupt of Select device
//
IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);
DeviceControl |= IEN_L;
IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
return EFI_SUCCESS;
}
@ -2448,6 +2523,11 @@ AtaUdmaRead (
UINT8 *PrdBuffer;
UINTN RemainBlockNum;
UINT8 DeviceControl;
UINT32 Count;
UINTN PageCount;
VOID *Map;
EFI_PHYSICAL_ADDRESS MemPage;
EFI_PHYSICAL_ADDRESS DeviceAddress;
//
// Channel and device differential
@ -2501,7 +2581,20 @@ AtaUdmaRead (
//
// Build PRD table
//
PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));
MemPage = 0xFFFFFFFF;
PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiBootServicesData,
PageCount,
&MemPage
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));
PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);
//
// To make sure PRD is allocated in one 64K page
//
@ -2518,7 +2611,19 @@ AtaUdmaRead (
//
// Build the PRD table
//
PrdBuffer = DataBuffer;
Status = IdeDev->PciIo->Map (
IdeDev->PciIo,
EfiPciIoOperationBusMasterWrite,
DataBuffer,
&ByteCount,
&DeviceAddress,
&Map
);
if (EFI_ERROR (Status)) {
gBS->FreePages (MemPage, PageCount);
return EFI_OUT_OF_RESOURCES;
}
PrdBuffer = (UINT8 *) ((UINTN) DeviceAddress);
TempPrdAddr = UsedPrdAddr;
while (TRUE) {
@ -2609,7 +2714,8 @@ AtaUdmaRead (
StartLba
);
if (EFI_ERROR (Status)) {
gBS->FreePool (PrdAddr);
gBS->FreePages (MemPage, PageCount);
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
return EFI_DEVICE_ERROR;
}
@ -2638,7 +2744,11 @@ AtaUdmaRead (
//
// Check the INTERRUPT and ERROR bit of BMIS
// Max transfer number of sectors for one command is 65536(32Mbyte),
// it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).
// So set the variable Count to 2000, for about 2 second timeout time.
//
Count = 2000;
while (TRUE) {
IdeDev->PciIo->Io.Read (
@ -2649,21 +2759,49 @@ AtaUdmaRead (
1,
&RegisterValue
);
if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {
if (RegisterValue & BMIS_ERROR) {
gBS->FreePool (PrdAddr);
if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) {
if ((RegisterValue & BMIS_ERROR) || (Count == 0)) {
//
// Clear START bit of BMIC register before return EFI_DEVICE_ERROR
//
IdeDev->PciIo->Io.Read (
IdeDev->PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
IoPortForBmic,
1,
&RegisterValue
);
RegisterValue &= ~((UINT8)BMIC_START);
IdeDev->PciIo->Io.Write (
IdeDev->PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
IoPortForBmic,
1,
&RegisterValue
);
gBS->FreePages (MemPage, PageCount);
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
return EFI_DEVICE_ERROR;
}
break;
}
gBS->Stall (1000);
Count --;
}
gBS->FreePool (PrdAddr);
gBS->FreePages (MemPage, PageCount);
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
//
// Set START bit of BMIC register
// Read Status Register of IDE device to clear interrupt
//
RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);
//
// Clear START bit of BMIC register
//
IdeDev->PciIo->Io.Read (
IdeDev->PciIo,
@ -2693,6 +2831,13 @@ AtaUdmaRead (
StartLba += NumberOfBlocks;
}
//
// Disable interrupt of Select device
//
IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);
DeviceControl |= IEN_L;
IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
return EFI_SUCCESS;
}
@ -2741,6 +2886,11 @@ AtaUdmaWriteExt (
UINT8 *PrdBuffer;
UINTN RemainBlockNum;
UINT8 DeviceControl;
UINT32 Count;
UINTN PageCount;
VOID *Map;
EFI_PHYSICAL_ADDRESS MemPage;
EFI_PHYSICAL_ADDRESS DeviceAddress;
//
// Channel and device differential
@ -2794,7 +2944,20 @@ AtaUdmaWriteExt (
//
// Build PRD table
//
PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));
MemPage = 0xFFFFFFFF;
PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiBootServicesData,
PageCount,
&MemPage
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));
PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);
//
// To make sure PRD is allocated in one 64K page
//
@ -2811,7 +2974,19 @@ AtaUdmaWriteExt (
//
// Build the PRD table
//
PrdBuffer = DataBuffer;
Status = IdeDev->PciIo->Map (
IdeDev->PciIo,
EfiPciIoOperationBusMasterRead,
DataBuffer,
&ByteCount,
&DeviceAddress,
&Map
);
if (EFI_ERROR (Status)) {
gBS->FreePages (MemPage, PageCount);
return EFI_OUT_OF_RESOURCES;
}
PrdBuffer = (UINT8 *) ((UINTN) DeviceAddress);
TempPrdAddr = UsedPrdAddr;
while (TRUE) {
@ -2904,7 +3079,8 @@ AtaUdmaWriteExt (
StartLba
);
if (EFI_ERROR (Status)) {
gBS->FreePool (PrdAddr);
gBS->FreePages (MemPage, PageCount);
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
return EFI_DEVICE_ERROR;
}
@ -2933,7 +3109,11 @@ AtaUdmaWriteExt (
//
// Check the INTERRUPT and ERROR bit of BMIS
// Max transfer number of sectors for one command is 65536(32Mbyte),
// it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).
// So set the variable Count to 2000, for about 2 second timeout time.
//
Count = 2000;
while (TRUE) {
IdeDev->PciIo->Io.Read (
@ -2944,21 +3124,49 @@ AtaUdmaWriteExt (
1,
&RegisterValue
);
if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {
if (RegisterValue & BMIS_ERROR) {
gBS->FreePool (PrdAddr);
if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) {
if ((RegisterValue & BMIS_ERROR) || (Count == 0)) {
//
// Clear START bit of BMIC register before return EFI_DEVICE_ERROR
//
IdeDev->PciIo->Io.Read (
IdeDev->PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
IoPortForBmic,
1,
&RegisterValue
);
RegisterValue &= ~((UINT8)BMIC_START);
IdeDev->PciIo->Io.Write (
IdeDev->PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
IoPortForBmic,
1,
&RegisterValue
);
gBS->FreePages (MemPage, PageCount);
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
return EFI_DEVICE_ERROR;
}
break;
}
gBS->Stall (1000);
Count --;
}
gBS->FreePool (PrdAddr);
gBS->FreePages (MemPage, PageCount);
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
//
// Set START bit of BMIC register
// Read Status Register of IDE device to clear interrupt
//
RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);
//
// Clear START bit of BMIC register
//
IdeDev->PciIo->Io.Read (
IdeDev->PciIo,
@ -2984,6 +3192,13 @@ AtaUdmaWriteExt (
StartLba += NumberOfBlocks;
}
//
// Disable interrupt of Select device
//
IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);
DeviceControl |= IEN_L;
IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
return EFI_SUCCESS;
}
@ -3036,6 +3251,11 @@ AtaUdmaWrite (
UINT8 *PrdBuffer;
UINTN RemainBlockNum;
UINT8 DeviceControl;
UINT32 Count;
UINTN PageCount;
VOID *Map;
EFI_PHYSICAL_ADDRESS MemPage;
EFI_PHYSICAL_ADDRESS DeviceAddress;
//
// Channel and device differential
@ -3089,7 +3309,20 @@ AtaUdmaWrite (
//
// Build PRD table
//
PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));
MemPage = 0xFFFFFFFF;
PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiBootServicesData,
PageCount,
&MemPage
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));
PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);
//
// To make sure PRD is allocated in one 64K page
@ -3107,7 +3340,19 @@ AtaUdmaWrite (
//
// Build the PRD table
//
PrdBuffer = DataBuffer;
Status = IdeDev->PciIo->Map (
IdeDev->PciIo,
EfiPciIoOperationBusMasterRead,
DataBuffer,
&ByteCount,
&DeviceAddress,
&Map
);
if (EFI_ERROR (Status)) {
gBS->FreePages (MemPage, PageCount);
return EFI_OUT_OF_RESOURCES;
}
PrdBuffer = (UINT8 *) ((UINTN) DeviceAddress);
TempPrdAddr = UsedPrdAddr;
while (TRUE) {
@ -3200,7 +3445,8 @@ AtaUdmaWrite (
StartLba
);
if (EFI_ERROR (Status)) {
gBS->FreePool (PrdAddr);
gBS->FreePages (MemPage, PageCount);
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
return EFI_DEVICE_ERROR;
}
@ -3229,7 +3475,11 @@ AtaUdmaWrite (
//
// Check the INTERRUPT and ERROR bit of BMIS
// Max transfer number of sectors for one command is 65536(32Mbyte),
// it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).
// So set the variable Count to 2000, for about 2 second timeout time.
//
Count = 2000;
while (TRUE) {
IdeDev->PciIo->Io.Read (
@ -3240,21 +3490,50 @@ AtaUdmaWrite (
1,
&RegisterValue
);
if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {
if (RegisterValue & BMIS_ERROR) {
gBS->FreePool (PrdAddr);
if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) {
if ((RegisterValue & BMIS_ERROR) || (Count == 0)) {
//
// Clear START bit of BMIC register before return EFI_DEVICE_ERROR
//
IdeDev->PciIo->Io.Read (
IdeDev->PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
IoPortForBmic,
1,
&RegisterValue
);
RegisterValue &= ~((UINT8)BMIC_START);
IdeDev->PciIo->Io.Write (
IdeDev->PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
IoPortForBmic,
1,
&RegisterValue
);
gBS->FreePages (MemPage, PageCount);
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
return EFI_DEVICE_ERROR;
}
break;
}
gBS->Stall (1000);
Count --;
}
gBS->FreePool (PrdAddr);
gBS->FreePages (MemPage, PageCount);
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
//
// Set START bit of BMIC register
// Read Status Register of IDE device to clear interrupt
//
RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);
//
// Clear START bit of BMIC register
//
IdeDev->PciIo->Io.Read (
IdeDev->PciIo,
@ -3280,5 +3559,12 @@ AtaUdmaWrite (
StartLba += NumberOfBlocks;
}
//
// Disable interrupt of Select device
//
IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);
DeviceControl |= IEN_L;
IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
return EFI_SUCCESS;
}

View File

@ -784,6 +784,15 @@ PioReadWriteData (
ActualWordCount += WordCount;
}
if (Read) {
//
// In the case where the drive wants to send more data than we need to read,
// the DRQ bit will be set and cause delays from DRQClear2().
// We need to read data from the drive until it clears DRQ so we can move on.
//
AtapiReadPendingData (IdeDev);
}
//
// After data transfer is completed, normally, DRQ bit should clear.
//
@ -802,25 +811,25 @@ PioReadWriteData (
Sends out ATAPI Test Unit Ready Packet Command to the specified device
to find out whether device is accessible.
@param[in] *IdeDev
pointer pointing to IDE_BLK_IO_DEV data structure, used
@param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used
to record all the information of the IDE device.
@param[in] *SenseCount Sense count for this packet command
@retval EFI_SUCCESS
device is accessible.
@retval EFI_DEVICE_ERROR
device is not accessible.
@retval EFI_SUCCESS Device is accessible.
@retval EFI_DEVICE_ERROR Device is not accessible.
**/
EFI_STATUS
AtapiTestUnitReady (
IN IDE_BLK_IO_DEV *IdeDev
IN IDE_BLK_IO_DEV *IdeDev,
OUT UINTN *SenseCount
)
{
ATAPI_PACKET_COMMAND Packet;
EFI_STATUS Status;
*SenseCount = 0;
//
// fill command packet
//
@ -831,9 +840,19 @@ AtapiTestUnitReady (
// send command packet
//
Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT);
if (EFI_ERROR (Status)) {
return Status;
}
Status = AtapiRequestSense (IdeDev, SenseCount);
if (EFI_ERROR (Status)) {
*SenseCount = 0;
return Status;
}
return EFI_SUCCESS;
}
/**
Sends out ATAPI Request Sense Packet Command to the specified device.
This command will return all the current Sense data in the device.
@ -927,7 +946,7 @@ AtapiRequestSense (
//
// Ptr is word-based pointer
//
Ptr += sizeof (REQUEST_SENSE_DATA) / 2;
Ptr += (sizeof (REQUEST_SENSE_DATA) + 1) >> 1;
} else {
//
@ -951,30 +970,28 @@ AtapiRequestSense (
if the Read Capacity Command failed, the Sense data must be requested
and be analyzed to determine if the Read Capacity Command should retry.
@param[in] *IdeDev
pointer pointing to IDE_BLK_IO_DEV data structure, used
@param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used
to record all the information of the IDE device.
@param[in] SenseCount Sense count for this packet command
@retval EFI_SUCCESS
Read Capacity Command finally completes successfully.
@retval EFI_SUCCESS Read Capacity Command finally completes successfully.
@retval EFI_DEVICE_ERROR Read Capacity Command failed because of device error.
@retval EFI_DEVICE_ERROR
Read Capacity Command failed because of device error.
@note
parameter "IdeDev" will be updated in this function.
@note Parameter "IdeDev" will be updated in this function.
TODO: EFI_NOT_READY - add return value to function comment
**/
EFI_STATUS
AtapiReadCapacity (
IN IDE_BLK_IO_DEV *IdeDev
IN IDE_BLK_IO_DEV *IdeDev,
OUT UINTN *SenseCount
)
{
//
// status returned by Read Capacity Packet Command
//
EFI_STATUS Status;
EFI_STATUS SenseStatus;
ATAPI_PACKET_COMMAND Packet;
//
@ -983,6 +1000,8 @@ AtapiReadCapacity (
READ_CAPACITY_DATA Data;
READ_FORMAT_CAPACITY_DATA FormatData;
*SenseCount = 0;
ZeroMem (&Data, sizeof (Data));
ZeroMem (&FormatData, sizeof (FormatData));
@ -1014,6 +1033,15 @@ AtapiReadCapacity (
);
}
if (Status == EFI_TIMEOUT) {
*SenseCount = 0;
return Status;
}
SenseStatus = AtapiRequestSense (IdeDev, SenseCount);
if (!EFI_ERROR (SenseStatus)) {
if (!EFI_ERROR (Status)) {
if (IdeDev->Type == IdeCdRom) {
@ -1076,11 +1104,12 @@ AtapiReadCapacity (
}
}
}
return EFI_SUCCESS;
} else {
*SenseCount = 0;
return EFI_DEVICE_ERROR;
}
}
@ -1120,239 +1149,157 @@ AtapiDetectMedia (
)
{
EFI_STATUS Status;
EFI_STATUS ReadCapacityStatus;
EFI_STATUS CleanStateStatus;
EFI_BLOCK_IO_MEDIA OldMediaInfo;
UINTN SenseCounts;
UINTN RetryIndex;
UINTN RetryTimes;
UINTN MaximumRetryTimes;
UINTN ReadyWaitFactor;
BOOLEAN NeedRetry;
//
// a flag used to determine whether need to perform Read Capacity command.
//
BOOLEAN NeedReadCapacity;
UINTN RetryNotReady;
UINTN SenseCount;
SENSE_RESULT SResult;
BOOLEAN WriteProtected;
//
// init
//
CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (OldMediaInfo));
// OldMediaInfo = *(IdeDev->BlkIo.Media);
CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (EFI_BLOCK_IO_MEDIA));
*MediaChange = FALSE;
ReadCapacityStatus = EFI_DEVICE_ERROR;
//
// Retry for SenseDeviceNotReadyNeedRetry.
// Each retry takes 1s and we limit the upper boundary to
// 120 times about 2 min.
//
RetryNotReady = 120;
//
// if there is no media, or media is not changed,
// the request sense command will detect faster than read capacity command.
// read capacity command can be bypassed, thus improve performance.
// Do Test Unit Ready
//
DoTUR:
//
// Retry 5 times
//
RetryTimes = 5;
while (RetryTimes != 0) {
//
// Test Unit Ready command is used to detect whether device is accessible,
// the device will produce corresponding Sense data.
//
for (RetryIndex = 0; RetryIndex < 2; RetryIndex++) {
Status = AtapiTestUnitReady (IdeDev);
if (!EFI_ERROR (Status)) {
//
// skip the loop if test unit command succeeds.
//
break;
}
Status = AtapiSoftReset (IdeDev);
Status = AtapiTestUnitReady (IdeDev, &SenseCount);
if (EFI_ERROR (Status)) {
AtaSoftReset (IdeDev);
//
// Test Unit Ready error without sense data.
// For some devices, this means there's extra data
// that has not been read, so we read these extra
// data out before going on.
//
CleanStateStatus = AtapiReadPendingData (IdeDev);
if (EFI_ERROR (CleanStateStatus)) {
//
// Busy wait failed, try again
//
RetryTimes--;
}
}
SenseCounts = 0;
NeedReadCapacity = TRUE;
//
// at most retry 5 times
// Try again without counting down RetryTimes
//
MaximumRetryTimes = 5;
RetryTimes = 1;
continue;
} else {
for (RetryIndex = 0;
(RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes);
RetryIndex++) {
Status = AtapiRequestSense (IdeDev, &SenseCounts);
if (!EFI_ERROR (Status)) {
//
// if first time there is no Sense Key, no need to read capacity any more
//
if (!HaveSenseKey (IdeDev->SenseData, SenseCounts) &&
(IdeDev->BlkIo.Media->MediaPresent)) {
if (RetryIndex == 0) {
NeedReadCapacity = FALSE;
}
ParseSenseData (IdeDev, SenseCount, &SResult);
switch (SResult) {
case SenseNoSenseKey:
if (IdeDev->BlkIo.Media->MediaPresent) {
goto Done;
} else {
//
// No Media
// Media present but the internal structure need refreshed.
// Try Read Capacity
//
if (IsNoMedia (IdeDev->SenseData, SenseCounts)) {
NeedReadCapacity = FALSE;
IdeDev->BlkIo.Media->MediaPresent = FALSE;
IdeDev->BlkIo.Media->LastBlock = 0;
} else {
//
// Media Changed
//
if (IsMediaChange (IdeDev->SenseData, SenseCounts)) {
NeedReadCapacity = TRUE;
IdeDev->BlkIo.Media->MediaId++;
goto DoRC;
}
//
// Media Error
//
if (IsMediaError (IdeDev->SenseData, SenseCounts)) {
return EFI_DEVICE_ERROR;
}
}
}
} else {
//
// retry once more, if request sense command met errors.
//
RetryTimes++;
}
}
if (NeedReadCapacity) {
//
// at most retry 5 times
//
MaximumRetryTimes = 5;
//
// initial retry twice
//
RetryTimes = 2;
ReadyWaitFactor = 2;
for (RetryIndex = 0;
(RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes);
RetryIndex++) {
ReadCapacityStatus = AtapiReadCapacity (IdeDev);
SenseCounts = 0;
if (!EFI_ERROR (ReadCapacityStatus)) {
//
// Read Capacity succeeded
//
break;
} else {
if (ReadCapacityStatus == EFI_NOT_READY) {
//
// If device not ready, wait here... waiting time increases by retry
// times.
//
gBS->Stall (ReadyWaitFactor * 2000 * STALL_1_MILLI_SECOND);
ReadyWaitFactor++;
//
// retry once more
//
RetryTimes++;
continue;
}
//
// Other errors returned, requery sense data
//
Status = AtapiRequestSense (IdeDev, &SenseCounts);
//
// If Request Sense data failed, reset the device and retry.
//
if (EFI_ERROR (Status)) {
Status = AtapiSoftReset (IdeDev);
//
// if ATAPI soft reset fail,
// use stronger reset mechanism -- ATA soft reset.
//
if (EFI_ERROR (Status)) {
AtaSoftReset (IdeDev);
}
//
// retry once more
//
RetryTimes++;
continue;
}
//
// No Media
//
if (IsNoMedia (IdeDev->SenseData, SenseCounts)) {
IdeDev->BlkIo.Media->MediaPresent = FALSE;
IdeDev->BlkIo.Media->LastBlock = 0;
return EFI_NO_MEDIA;
}
if (IsMediaError (IdeDev->SenseData, SenseCounts)) {
case SenseDeviceNotReadyNeedRetry:
if (--RetryNotReady == 0) {
return EFI_DEVICE_ERROR;
}
//
// Media Changed
//
if (IsMediaChange (IdeDev->SenseData, SenseCounts)) {
IdeDev->BlkIo.Media->MediaId++;
}
if (!IsDriveReady (IdeDev->SenseData, SenseCounts, &NeedRetry)) {
//
// Drive not ready: if NeedRetry, then retry once more;
// else return error
//
if (NeedRetry) {
//
// Stall 1 second to wait for drive becoming ready
//
gBS->Stall (1000 * STALL_1_MILLI_SECOND);
continue;
break;
case SenseNoMedia:
IdeDev->BlkIo.Media->MediaPresent = FALSE;
IdeDev->BlkIo.Media->LastBlock = 0;
goto Done;
break;
case SenseDeviceNotReadyNoRetry:
case SenseMediaError:
return EFI_DEVICE_ERROR;
case SenseMediaChange:
IdeDev->BlkIo.Media->MediaId++;
goto DoRC;
break;
default:
RetryTimes--;
break;
}
}
}
return EFI_DEVICE_ERROR;
//
// reset retry variable to zero,
// to make it retry for "drive in progress of becoming ready".
// Do Read Capacity
//
RetryIndex = 0;
DoRC:
RetryTimes = 5;
while (RetryTimes != 0) {
Status = AtapiReadCapacity (IdeDev, &SenseCount);
if (EFI_ERROR (Status)) {
RetryTimes--;
continue;
} else {
AtapiSoftReset (IdeDev);
ParseSenseData (IdeDev, SenseCount, &SResult);
switch (SResult) {
case SenseNoSenseKey:
goto Done;
break;
case SenseDeviceNotReadyNeedRetry:
//
// We use Test Unit Ready to retry which
// is faster.
//
goto DoTUR;
break;
case SenseNoMedia:
IdeDev->BlkIo.Media->MediaPresent = FALSE;
IdeDev->BlkIo.Media->LastBlock = 0;
goto Done;
break;
case SenseDeviceNotReadyNoRetry:
case SenseMediaError:
return EFI_DEVICE_ERROR;
case SenseMediaChange:
IdeDev->BlkIo.Media->MediaId++;
continue;
break;
default:
RetryTimes--;
break;
}
}
//
// if read capacity fail not for above reasons, retry once more
//
RetryTimes++;
}
}
//
// tell whether the readcapacity process is successful or not in the end
//
if (EFI_ERROR (ReadCapacityStatus)) {
return EFI_DEVICE_ERROR;
}
}
Done:
//
// the following code is to check the write-protected for LS120 media
//
@ -1423,8 +1370,11 @@ AtapiDetectMedia (
);
}
if (IdeDev->BlkIo.Media->MediaPresent) {
return EFI_SUCCESS;
} else {
return EFI_NO_MEDIA;
}
}
/**
@ -1490,7 +1440,7 @@ AtapiReadSectors (
//
// limit the data bytes that can be transferred by one Read(10) Command
//
MaxBlock = (UINT16) (65536 / BlockSize);
MaxBlock = 65535;
BlocksRemaining = NumberOfBlocks;
@ -2037,259 +1987,114 @@ AtapiBlkIoWriteBlocks (
}
//
// The following functions are a set of helper functions,
// which are used to parse sense key returned by the device.
//
/**
TODO: Add function description
This function is used to parse sense data. Only the first
sense data is honoured.
@param SenseData TODO: add argument description
@param SenseCounts TODO: add argument description
@param[in] IdeDev Indicates the calling context.
@param[in] SenseCount Count of sense data.
@param[out] Result The parsed result.
TODO: add return values
@retval EFI_SUCCESS Successfully parsed.
@retval EFI_INVALID_PARAMETER Count of sense data is zero.
**/
BOOLEAN
IsNoMedia (
IN REQUEST_SENSE_DATA *SenseData,
IN UINTN SenseCounts
EFI_STATUS
ParseSenseData (
IN IDE_BLK_IO_DEV *IdeDev,
IN UINTN SenseCount,
OUT SENSE_RESULT *Result
)
{
REQUEST_SENSE_DATA *SensePointer;
UINTN Index;
BOOLEAN NoMedia;
REQUEST_SENSE_DATA *SenseData;
NoMedia = FALSE;
SensePointer = SenseData;
if (SenseCount == 0) {
return EFI_INVALID_PARAMETER;
}
for (Index = 0; Index < SenseCounts; Index++) {
//
// Sense Key is SK_NOT_READY (0x2),
// Additional Sense Code is ASC_NO_MEDIA (0x3A)
// Only use the first sense data
//
if ((SensePointer->sense_key == SK_NOT_READY) &&
(SensePointer->addnl_sense_code == ASC_NO_MEDIA)) {
SenseData = IdeDev->SenseData;
*Result = SenseOtherSense;
NoMedia = TRUE;
switch (SenseData->sense_key) {
case SK_NO_SENSE:
*Result = SenseNoSenseKey;
break;
case SK_NOT_READY:
switch (SenseData->addnl_sense_code) {
case ASC_NO_MEDIA:
*Result = SenseNoMedia;
break;
case ASC_MEDIA_UPSIDE_DOWN:
*Result = SenseMediaError;
break;
case ASC_NOT_READY:
if (SenseData->addnl_sense_code_qualifier == ASCQ_IN_PROGRESS) {
*Result = SenseDeviceNotReadyNeedRetry;
} else {
*Result = SenseDeviceNotReadyNoRetry;
}
SensePointer++;
break;
}
return NoMedia;
break;
case SK_UNIT_ATTENTION:
if (SenseData->addnl_sense_code == ASC_MEDIA_CHANGE) {
*Result = SenseMediaChange;
}
/**
Test if the device meets a media error after media changed
@param[in] *SenseData
pointer pointing to ATAPI device sense data list.
@param[in] SenseCounts
sense data number of the list
@retval TRUE Device meets a media error
@retval FALSE No media error
**/
BOOLEAN
IsMediaError (
IN REQUEST_SENSE_DATA *SenseData,
IN UINTN SenseCounts
)
{
REQUEST_SENSE_DATA *SensePointer;
UINTN Index;
BOOLEAN IsError;
IsError = FALSE;
SensePointer = SenseData;
for (Index = 0; Index < SenseCounts; Index++) {
switch (SensePointer->sense_key) {
break;
case SK_MEDIUM_ERROR:
//
// Sense Key is SK_MEDIUM_ERROR (0x3)
//
switch (SensePointer->addnl_sense_code) {
switch (SenseData->addnl_sense_code) {
case ASC_MEDIA_ERR1:
case ASC_MEDIA_ERR2:
case ASC_MEDIA_ERR3:
case ASC_MEDIA_ERR4:
IsError = TRUE;
*Result = SenseMediaError;
break;
}
break;
default:
break;
}
break;
case SK_NOT_READY:
//
// Sense Key is SK_NOT_READY (0x2)
//
switch (SensePointer->addnl_sense_code) {
//
// Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
//
case ASC_MEDIA_UPSIDE_DOWN:
IsError = TRUE;
break;
default:
break;
}
break;
default:
break;
}
SensePointer++;
}
return IsError;
return EFI_SUCCESS;
}
/**
TODO: Add function description
This function reads the pending data in the device.
@param SenseData TODO: add argument description
@param SenseCounts TODO: add argument description
@param[in] IdeDev Indicates the calling context.
TODO: add return values
@retval EFI_SUCCESS Successfully read.
@retval EFI_NOT_READY The BSY is set avoiding reading.
**/
BOOLEAN
IsMediaChange (
IN REQUEST_SENSE_DATA *SenseData,
IN UINTN SenseCounts
EFI_STATUS
AtapiReadPendingData (
IN IDE_BLK_IO_DEV *IdeDev
)
{
REQUEST_SENSE_DATA *SensePointer;
UINTN Index;
BOOLEAN IsMediaChange;
UINT8 AltRegister;
UINT16 TempWordBuffer;
IsMediaChange = FALSE;
SensePointer = SenseData;
for (Index = 0; Index < SenseCounts; Index++) {
//
// Sense Key is SK_UNIT_ATTENTION (0x6)
//
if ((SensePointer->sense_key == SK_UNIT_ATTENTION) &&
(SensePointer->addnl_sense_code == ASC_MEDIA_CHANGE)) {
IsMediaChange = TRUE;
AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
if ((AltRegister & BSY) == BSY) {
return EFI_NOT_READY;
}
SensePointer++;
if ((AltRegister & (BSY | DRQ)) == DRQ) {
TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);
while ((TempWordBuffer & (BSY | DRQ)) == DRQ) {
IDEReadPortWMultiple (
IdeDev->PciIo,
IdeDev->IoPort->Data,
1,
&TempWordBuffer
);
TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);
}
return IsMediaChange;
}
/**
TODO: Add function description
@param SenseData TODO: add argument description
@param SenseCounts TODO: add argument description
@param NeedRetry TODO: add argument description
TODO: add return values
**/
BOOLEAN
IsDriveReady (
IN REQUEST_SENSE_DATA *SenseData,
IN UINTN SenseCounts,
OUT BOOLEAN *NeedRetry
)
{
REQUEST_SENSE_DATA *SensePointer;
UINTN Index;
BOOLEAN IsReady;
IsReady = TRUE;
*NeedRetry = FALSE;
SensePointer = SenseData;
for (Index = 0; Index < SenseCounts; Index++) {
switch (SensePointer->sense_key) {
case SK_NOT_READY:
//
// Sense Key is SK_NOT_READY (0x2)
//
switch (SensePointer->addnl_sense_code) {
case ASC_NOT_READY:
//
// Additional Sense Code is ASC_NOT_READY (0x4)
//
switch (SensePointer->addnl_sense_code_qualifier) {
case ASCQ_IN_PROGRESS:
//
// Additional Sense Code Qualifier is ASCQ_IN_PROGRESS (0x1)
//
IsReady = FALSE;
*NeedRetry = TRUE;
break;
default:
IsReady = FALSE;
*NeedRetry = FALSE;
break;
}
break;
default:
break;
}
break;
default:
break;
}
SensePointer++;
}
return IsReady;
}
/**
TODO: Add function description
@param SenseData TODO: add argument description
@param SenseCounts TODO: add argument description
TODO: add return values
**/
BOOLEAN
HaveSenseKey (
IN REQUEST_SENSE_DATA *SenseData,
IN UINTN SenseCounts
)
{
BOOLEAN Have;
Have = TRUE;
//
// if first sense key in the Sense Data Array is SK_NO_SENSE,
// it indicates there is no more sense key in the Sense Data Array.
//
if (SenseData->sense_key == SK_NO_SENSE) {
Have = FALSE;
}
return Have;
return EFI_SUCCESS;
}
/**

View File

@ -12,8 +12,11 @@
#include "idebus.h"
BOOLEAN ChannelDeviceDetected = FALSE;
BOOLEAN SlaveDeviceExist = FALSE;
UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE;
BOOLEAN MasterDeviceExist = FALSE;
UINT8 MasterDeviceType = INVALID_DEVICE_TYPE;
/**
TODO: Add function description
@ -464,57 +467,6 @@ ReassignIdeResources (
return EFI_SUCCESS;
}
/**
Read SATA registers to detect SATA disks
@param IdeDev The BLK_IO private data which specifies the IDE device
**/
EFI_STATUS
CheckPowerMode (
IDE_BLK_IO_DEV *IdeDev
)
// TODO: EFI_NOT_FOUND - add return value to function comment
// TODO: EFI_SUCCESS - add return value to function comment
// TODO: EFI_NOT_FOUND - add return value to function comment
{
UINT8 ErrorRegister;
EFI_STATUS Status;
IDEWritePortB (
IdeDev->PciIo,
IdeDev->IoPort->Head,
(UINT8) ((IdeDev->Device << 4) | 0xe0)
);
//
// Wait 31 seconds for BSY clear. BSY should be in clear state if there exists
// a device (initial state). Normally, BSY is also in clear state if there is
// no device
//
Status = WaitForBSYClear (IdeDev, 31000);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
//
// select device, read error register
//
IDEWritePortB (
IdeDev->PciIo,
IdeDev->IoPort->Head,
(UINT8) ((IdeDev->Device << 4) | 0xe0)
);
Status = DRDYReady (IdeDev, 200);
ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
if ((ErrorRegister == 0x01) || (ErrorRegister == 0x81)) {
return EFI_SUCCESS;
} else {
return EFI_NOT_FOUND;
}
}
//
// DiscoverIdeDevice
//
@ -533,44 +485,67 @@ DiscoverIdeDevice (
// TODO: EFI_SUCCESS - add return value to function comment
{
EFI_STATUS Status;
BOOLEAN SataFlag;
SataFlag = FALSE;
//
// This extra detection is for SATA disks
//
Status = CheckPowerMode (IdeDev);
if (Status == EFI_SUCCESS) {
SataFlag = TRUE;
}
//
// If a channel has not been checked, check it now. Then set it to "checked" state
// After this step, all devices in this channel have been checked.
//
if (ChannelDeviceDetected == FALSE) {
Status = DetectIDEController (IdeDev);
if ((EFI_ERROR (Status)) && !SataFlag) {
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
}
Status = EFI_NOT_FOUND;
//
// Device exists. test if it is an ATA device
// Device exists. test if it is an ATA device.
// Prefer the result from DetectIDEController,
// if failed, try another device type to handle
// devices that not follow the spec.
//
if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {
if (MasterDeviceType == ATA_DEVICE_TYPE) {
Status = ATAIdentify (IdeDev);
if (EFI_ERROR (Status)) {
//
// if not ATA device, test if it is an ATAPI device
//
Status = ATAPIIdentify (IdeDev);
if (!EFI_ERROR (Status)) {
MasterDeviceType = ATAPI_DEVICE_TYPE;
}
}
} else {
Status = ATAPIIdentify (IdeDev);
if (EFI_ERROR (Status)) {
//
// if not ATAPI device either, return error.
//
Status = ATAIdentify (IdeDev);
if (!EFI_ERROR (Status)) {
MasterDeviceType = ATA_DEVICE_TYPE;
}
}
}
}
if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {
if (SlaveDeviceType == ATA_DEVICE_TYPE) {
Status = ATAIdentify (IdeDev);
if (EFI_ERROR (Status)) {
Status = ATAPIIdentify (IdeDev);
if (!EFI_ERROR (Status)) {
SlaveDeviceType = ATAPI_DEVICE_TYPE;
}
}
} else {
Status = ATAPIIdentify (IdeDev);
if (EFI_ERROR (Status)) {
Status = ATAIdentify (IdeDev);
if (!EFI_ERROR (Status)) {
SlaveDeviceType = ATA_DEVICE_TYPE;
}
}
}
}
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
}
//
// Init Block I/O interface
//
@ -595,6 +570,26 @@ DiscoverIdeDevice (
return EFI_SUCCESS;
}
/**
This interface is used to initialize all state data related to the detection of one
channel.
@retval EFI_SUCCESS Completed Successfully.
**/
EFI_STATUS
InitializeIDEChannelData (
VOID
)
{
ChannelDeviceDetected = FALSE;
MasterDeviceExist = FALSE;
MasterDeviceType = 0xff;
SlaveDeviceExist = FALSE;
SlaveDeviceType = 0xff;
return EFI_SUCCESS;
}
/**
This function is called by DiscoverIdeDevice(). It is used for detect
whether the IDE device exists in the specified Channel as the specified
@ -633,31 +628,12 @@ DetectIDEController (
)
{
EFI_STATUS Status;
UINT8 ErrorReg;
UINT8 StatusReg;
UINT8 SectorCountReg;
UINT8 LBALowReg;
UINT8 LBAMidReg;
UINT8 LBAHighReg;
UINT8 InitStatusReg;
EFI_STATUS DeviceStatus;
//
// Slave device has been detected with master device.
//
if ((IdeDev->Device) == 1) {
if (SlaveDeviceExist) {
//
// If master not exists but slave exists, slave have to wait a while
//
if (!MasterDeviceExist) {
//
// if single slave can't be detected, add delay 4s here.
//
gBS->Stall (4000000);
}
return EFI_SUCCESS;
} else {
return EFI_NOT_FOUND;
}
}
UINT8 StatusReg;
//
// Select slave device
@ -675,7 +651,7 @@ DetectIDEController (
InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
//
// Select master back
// Select Master back
//
IDEWritePortB (
IdeDev->PciIo,
@ -683,6 +659,7 @@ DetectIDEController (
(UINT8) ((0 << 4) | 0xe0)
);
gBS->Stall (100);
//
// Send ATA Device Execut Diagnostic command.
// This command should work no matter DRDY is ready or not
@ -690,88 +667,124 @@ DetectIDEController (
IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);
Status = WaitForBSYClear (IdeDev, 3500);
ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
if (EFI_ERROR (Status)) {
DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));
return Status;
}
//
// Master Error register is 0x01. D0 passed, D1 passed or not present.
// Master Error register is 0x81. D0 passed, D1 failed. Return.
// Master Error register is other value. D0 failed, D1 passed or not present..
// Read device signature
//
if (ErrorReg == 0x01) {
//
// Select Master
//
IDEWritePortB (
IdeDev->PciIo,
IdeDev->IoPort->Head,
(UINT8) ((0 << 4) | 0xe0)
);
gBS->Stall (100);
SectorCountReg = IDEReadPortB (
IdeDev->PciIo,
IdeDev->IoPort->SectorCount
);
LBALowReg = IDEReadPortB (
IdeDev->PciIo,
IdeDev->IoPort->SectorNumber
);
LBAMidReg = IDEReadPortB (
IdeDev->PciIo,
IdeDev->IoPort->CylinderLsb
);
LBAHighReg = IDEReadPortB (
IdeDev->PciIo,
IdeDev->IoPort->CylinderMsb
);
if ((SectorCountReg == 0x1) &&
(LBALowReg == 0x1) &&
(LBAMidReg == 0x0) &&
(LBAHighReg == 0x0)) {
MasterDeviceExist = TRUE;
DeviceStatus = EFI_SUCCESS;
} else if (ErrorReg == 0x81) {
MasterDeviceExist = TRUE;
DeviceStatus = EFI_SUCCESS;
SlaveDeviceExist = FALSE;
return DeviceStatus;
MasterDeviceType = ATA_DEVICE_TYPE;
} else {
MasterDeviceExist = FALSE;
DeviceStatus = EFI_NOT_FOUND;
if ((LBAMidReg == 0x14) &&
(LBAHighReg == 0xeb)) {
MasterDeviceExist = TRUE;
MasterDeviceType = ATAPI_DEVICE_TYPE;
}
}
//
// Master Error register is not 0x81, Go on check Slave
//
//
// Stall 20ms to wait for slave device ready if master device not exists
// For some Hard Drive, it takes some time to get
// the right signature when operating in single slave mode.
// We stall 20ms to work around this.
//
if (!MasterDeviceExist) {
gBS->Stall (20000);
}
//
// select slave
// Select Slave
//
IDEWritePortB (
IdeDev->PciIo,
IdeDev->IoPort->Head,
(UINT8) ((1 << 4) | 0xe0)
);
gBS->Stall (300);
ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
//
// Slave Error register is not 0x01, D1 failed. Return.
//
if (ErrorReg != 0x01) {
SlaveDeviceExist = FALSE;
return DeviceStatus;
}
StatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
//
// Most ATAPI devices don't set DRDY bit, so test with a slow but accurate
// "ATAPI TEST UNIT READY" command
//
if (((StatusReg & DRDY) == 0) && ((InitStatusReg & DRDY) == 0)) {
Status = AtapiTestUnitReady (IdeDev);
//
// Still fail, Slave doesn't exist.
//
if (EFI_ERROR (Status)) {
SlaveDeviceExist = FALSE;
return DeviceStatus;
}
}
//
// Error reg is 0x01 and DRDY is ready,
// or ATAPI test unit ready success,
// or init Slave status DRDY is ready
// Slave exists.
//
gBS->Stall (100);
SectorCountReg = IDEReadPortB (
IdeDev->PciIo,
IdeDev->IoPort->SectorCount
);
LBALowReg = IDEReadPortB (
IdeDev->PciIo,
IdeDev->IoPort->SectorNumber
);
LBAMidReg = IDEReadPortB (
IdeDev->PciIo,
IdeDev->IoPort->CylinderLsb
);
LBAHighReg = IDEReadPortB (
IdeDev->PciIo,
IdeDev->IoPort->CylinderMsb
);
StatusReg = IDEReadPortB (
IdeDev->PciIo,
IdeDev->IoPort->Reg.Status
);
if ((SectorCountReg == 0x1) &&
(LBALowReg == 0x1) &&
(LBAMidReg == 0x0) &&
(LBAHighReg == 0x0)) {
SlaveDeviceExist = TRUE;
SlaveDeviceType = ATA_DEVICE_TYPE;
} else {
if ((LBAMidReg == 0x14) &&
(LBAHighReg == 0xeb)) {
SlaveDeviceExist = TRUE;
SlaveDeviceType = ATAPI_DEVICE_TYPE;
}
}
return DeviceStatus;
//
// When single master is plugged, slave device
// will be wrongly detected. Here's the workaround
// for ATA devices by detecting DRY bit in status
// register.
// NOTE: This workaround doesn't apply to ATAPI.
//
if (MasterDeviceExist && SlaveDeviceExist &&
(StatusReg & DRDY) == 0 &&
(InitStatusReg & DRDY) == 0 &&
MasterDeviceType == SlaveDeviceType &&
SlaveDeviceType != ATAPI_DEVICE_TYPE) {
SlaveDeviceExist = FALSE;
}
//
// Indicate this channel has been detected
//
ChannelDeviceDetected = TRUE;
return EFI_SUCCESS;
}
/**
@ -1251,7 +1264,7 @@ DRDYReady (
}
}
gBS->Stall (15);
gBS->Stall (30);
Delay--;
} while (Delay);
@ -1432,6 +1445,11 @@ ReleaseIdeResources (
gBS->FreePool (IdeBlkIoDevice->DevicePath);
}
if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {
gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);
IdeBlkIoDevice->ExitBootServiceEvent = NULL;
}
gBS->FreePool (IdeBlkIoDevice);
IdeBlkIoDevice = NULL;
@ -1553,8 +1571,14 @@ AtaNonDataCommandIn (
//
// Wait for command completion
// For ATA_SMART_CMD, we may need more timeout to let device
// adjust internal states.
//
if (AtaCommand == ATA_SMART_CMD) {
Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);
} else {
Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
}
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
@ -1716,12 +1740,11 @@ SetDriveParameters (
//
// Send Init drive parameters
//
Status = AtaPioDataIn (
Status = AtaNonDataCommandIn (
IdeDev,
NULL,
0,
INIT_DRIVE_PARAM_CMD,
(UINT8) (DeviceSelect + DriveParameters->Heads),
0,
DriveParameters->Sector,
0,
0,
@ -1731,18 +1754,16 @@ SetDriveParameters (
//
// Send Set Multiple parameters
//
Status = AtaPioDataIn (
Status = AtaNonDataCommandIn (
IdeDev,
NULL,
0,
SET_MULTIPLE_MODE_CMD,
DeviceSelect,
0,
DriveParameters->MultipleSector,
0,
0,
0
);
return Status;
}
@ -1769,13 +1790,13 @@ EnableInterrupt (
return EFI_SUCCESS;
}
/**
Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
@param[in] Event Pointer to this event
@param[in] Context Event hanlder private data
**/
VOID
EFIAPI

View File

@ -198,6 +198,19 @@ DiscoverIdeDevice (
)
;
/**
This interface is used to initialize all state data related to the
detection of one channel.
@retval EFI_SUCCESS Completed successfully.
**/
EFI_STATUS
InitializeIDEChannelData (
VOID
)
;
/**
TODO: Add function description
@ -661,6 +674,7 @@ PioReadWriteData (
/**
TODO: Add function description
@param IdeDev TODO: add argument description
@param IdeDev TODO: add argument description
TODO: add return values
@ -668,7 +682,8 @@ PioReadWriteData (
**/
EFI_STATUS
AtapiTestUnitReady (
IN IDE_BLK_IO_DEV *IdeDev
IN IDE_BLK_IO_DEV *IdeDev,
OUT UINTN *SenseCount
)
;
@ -691,6 +706,7 @@ AtapiRequestSense (
/**
TODO: Add function description
@param IdeDev TODO: add argument description
@param IdeDev TODO: add argument description
TODO: add return values
@ -698,7 +714,8 @@ AtapiRequestSense (
**/
EFI_STATUS
AtapiReadCapacity (
IN IDE_BLK_IO_DEV *IdeDev
IN IDE_BLK_IO_DEV *IdeDev,
OUT UINTN *SenseCount
)
;
@ -819,82 +836,32 @@ AtapiBlkIoWriteBlocks (
/**
TODO: Add function description
@param SenseData TODO: add argument description
@param SenseCounts TODO: add argument description
@param IdeDev TODO: add argument description
@param SenseCount TODO: add argument description
@param Result TODO: add argument description
TODO: add return values
**/
BOOLEAN
IsNoMedia (
IN REQUEST_SENSE_DATA *SenseData,
IN UINTN SenseCounts
EFI_STATUS
ParseSenseData (
IN IDE_BLK_IO_DEV *IdeDev,
IN UINTN SenseCount,
OUT SENSE_RESULT *Result
)
;
/**
TODO: Add function description
@param SenseData TODO: add argument description
@param SenseCounts TODO: add argument description
@param IdeDev TODO: add argument description
TODO: add return values
**/
BOOLEAN
IsMediaError (
IN REQUEST_SENSE_DATA *SenseData,
IN UINTN SenseCounts
)
;
/**
TODO: Add function description
@param SenseData TODO: add argument description
@param SenseCounts TODO: add argument description
TODO: add return values
**/
BOOLEAN
IsMediaChange (
IN REQUEST_SENSE_DATA *SenseData,
IN UINTN SenseCounts
)
;
/**
TODO: Add function description
@param SenseData TODO: add argument description
@param SenseCounts TODO: add argument description
@param NeedRetry TODO: add argument description
TODO: add return values
**/
BOOLEAN
IsDriveReady (
IN REQUEST_SENSE_DATA *SenseData,
IN UINTN SenseCounts,
OUT BOOLEAN *NeedRetry
)
;
/**
TODO: Add function description
@param SenseData TODO: add argument description
@param SenseCounts TODO: add argument description
TODO: add return values
**/
BOOLEAN
HaveSenseKey (
IN REQUEST_SENSE_DATA *SenseData,
IN UINTN SenseCounts
EFI_STATUS
AtapiReadPendingData (
IN IDE_BLK_IO_DEV *IdeDev
)
;
@ -1304,6 +1271,7 @@ EnableInterrupt (
IN IDE_BLK_IO_DEV *IdeDev
)
;
/**
Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.

View File

@ -183,7 +183,6 @@ IDEBusDriverBindingStart (
UINTN DataSize;
UINT32 Attributes;
IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData;
EFI_EVENT Event;
//
// Local variables declaration for IdeControllerInit support
@ -417,6 +416,12 @@ IDEBusDriverBindingStart (
EfiIdeBusBeforeDevicePresenceDetection,
IdeChannel
);
//
// Prepare to detect IDE device of this channel
//
InitializeIDEChannelData ();
//
// -- 1st inner loop --- Master/Slave ------------ Step14
//
@ -488,6 +493,15 @@ IDEBusDriverBindingStart (
IdeBlkIoDevicePtr->IdeBusDriverPrivateData = IdeBusDriverPrivateData;
IdeBlkIoDevicePtr->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeChannel].BusMasterBaseAddr;
//
// Report Status code: is about to detect IDE drive
//
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_PROGRESS_CODE,
(EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_PRESENCE_DETECT),
IdeBlkIoDevicePtr->DevicePath
);
//
// Discover device, now!
//
@ -523,7 +537,6 @@ IDEBusDriverBindingStart (
// Submit identify data to IDE controller init driver
//
CopyMem (&IdentifyData, IdeBlkIoDevicePtr->pIdData, sizeof (IdentifyData));
// IdentifyData = *IdeBlkIoDevicePtr->pIdData;
IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = TRUE;
IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, &IdentifyData);
} else {
@ -706,10 +719,9 @@ IDEBusDriverBindingStart (
EFI_TPL_NOTIFY,
ClearInterrupt,
IdeBlkIoDevicePtr,
&Event
&IdeBlkIoDevicePtr->ExitBootServiceEvent
);
//
// end of 2nd inner loop ----
//
@ -1028,7 +1040,8 @@ IDEBlkIoReset (
//
// for ATA device, using ATA reset method
//
if (IdeBlkIoDevice->Type == IdeHardDisk) {
if (IdeBlkIoDevice->Type == IdeHardDisk ||
IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
return AtaSoftReset (IdeBlkIoDevice);
}

View File

@ -28,6 +28,10 @@
#define MAX_IDE_CHANNELS 2
#define MAX_IDE_DRIVES 2
#define INVALID_DEVICE_TYPE 0xff
#define ATA_DEVICE_TYPE 0x00
#define ATAPI_DEVICE_TYPE 0x01
typedef struct {
BOOLEAN HaveScannedDevice[MAX_IDE_DEVICE];
BOOLEAN DeviceFound[MAX_IDE_DEVICE];
@ -67,6 +71,11 @@ typedef struct {
UINT8 SenseDataNumber;
UINT8 *Cache;
//
// ExitBootService Event, it is used to clear pending IDE interrupt
//
EFI_EVENT ExitBootServiceEvent;
EFI_UNICODE_STRING_TABLE *ControllerNameTable;
} IDE_BLK_IO_DEV;

View File

@ -76,6 +76,16 @@ typedef enum {
IdeUnknown
} IDE_DEVICE_TYPE;
typedef enum {
SenseNoSenseKey,
SenseDeviceNotReadyNoRetry,
SenseDeviceNotReadyNeedRetry,
SenseNoMedia,
SenseMediaChange,
SenseMediaError,
SenseOtherSense
} SENSE_RESULT;
//
// IDE Registers
//
@ -234,6 +244,11 @@ typedef struct {
//
#define ATAPILONGTIMEOUT 5000
//
// 10 seconds
//
#define ATASMARTTIMEOUT 10000
//
// ATA Commands Code
//