summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus
diff options
context:
space:
mode:
authorerictian <erictian@6f19259b-4bc3-4df7-8a09-765794883524>2011-06-14 02:11:34 +0000
committererictian <erictian@6f19259b-4bc3-4df7-8a09-765794883524>2011-06-14 02:11:34 +0000
commitcbd2a4b3628d3242620bb5353e4b466bc435ca87 (patch)
treed8fc4d6f4d7d16b5ab7a179e8eef7a41cca71f44 /MdeModulePkg/Bus
parente118a40b9d1c1f06c96eda16fbb96a0d000f8a11 (diff)
downloadedk2-platforms-cbd2a4b3628d3242620bb5353e4b466bc435ca87.tar.xz
ScsiBus/ScsiDisk enhancement for no_media state.
Ahci enumeration logic tuning for boot performance. Signed-off-by:erictian Reviewed-by:qianouyang, hhuan13 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11820 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Bus')
-rw-r--r--MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c392
-rw-r--r--MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h17
-rw-r--r--MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c191
-rw-r--r--MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c40
4 files changed, 367 insertions, 273 deletions
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
index a36d03e827..b83babf081 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
@@ -1273,12 +1273,12 @@ AhciStartCommand (
if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {
if ((Capability & BIT24) != 0) {
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_COL);
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_CLO);
AhciWaitMemSet (
PciIo,
Offset,
- EFI_AHCI_PORT_CMD_COL,
+ EFI_AHCI_PORT_CMD_CLO,
0,
Timeout
);
@@ -1816,7 +1816,6 @@ AhciPacketCommandExecute (
EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
EFI_ATA_STATUS_BLOCK AtaStatusBlock;
BOOLEAN Read;
- UINT8 Retry;
if (Packet == NULL || Packet->Cdb == NULL) {
return EFI_INVALID_PARAMETER;
@@ -1860,35 +1859,21 @@ AhciPacketCommandExecute (
NULL
);
} else {
- //
- // READ_CAPACITY cmd may execute failure. Retry 5 times
- //
- if (((UINT8 *)Packet->Cdb)[0] == ATA_CMD_READ_CAPACITY) {
- Retry = 5;
- } else {
- Retry = 1;
- }
- do {
- Status = AhciPioTransfer (
- PciIo,
- AhciRegisters,
- Port,
- PortMultiplier,
- Packet->Cdb,
- Packet->CdbLength,
- Read,
- &AtaCommandBlock,
- &AtaStatusBlock,
- Buffer,
- Length,
- Packet->Timeout,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- break;
- }
- Retry--;
- } while (Retry != 0);
+ Status = AhciPioTransfer (
+ PciIo,
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ Packet->Cdb,
+ Packet->CdbLength,
+ Read,
+ &AtaCommandBlock,
+ &AtaStatusBlock,
+ Buffer,
+ Length,
+ Packet->Timeout,
+ NULL
+ );
}
return Status;
}
@@ -2165,7 +2150,8 @@ AhciModeInitialization (
EFI_ATA_DEVICE_TYPE DeviceType;
EFI_ATA_COLLECTIVE_MODE *SupportedModes;
EFI_ATA_TRANSFER_MODE TransferMode;
-
+ UINT32 PhyDetectDelay;
+
if (Instance == NULL) {
return EFI_INVALID_PARAMETER;
}
@@ -2173,7 +2159,7 @@ AhciModeInitialization (
PciIo = Instance->PciIo;
IdeInit = Instance->IdeControllerInit;
- Status = AhciReset (PciIo, ATA_ATAPI_TIMEOUT);
+ Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
@@ -2193,14 +2179,14 @@ AhciModeInitialization (
// Get the number of command slots per port supported by this HBA.
//
MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);
- Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);
+ MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);
+ Support64Bit = (BOOLEAN) (((Capability & EFI_AHCI_CAP_S64A) != 0) ? TRUE : FALSE);
//
// Get the bit map of those ports exposed by this HBA.
// It indicates which ports that the HBA supports are available for software to use.
//
PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);
- MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);
AhciRegisters = &Instance->AhciRegisters;
Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);
@@ -2210,191 +2196,227 @@ AhciModeInitialization (
}
for (Port = 0; Port < MaxPortNumber; Port ++) {
- Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
- AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
- AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);
-
- //
- // Single task envrionment, we only use one command table for all port
- //
- Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
- AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
- AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);
-
if ((PortImplementBitMap & (BIT0 << Port)) != 0) {
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);
+
+ //
+ // Initialize FIS Base Address Register and Command List Base Address Register for use.
+ //
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);
+
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
+ AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);
+
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
-
- if ((Capability & EFI_AHCI_PORT_CMD_ASP) != 0) {
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);
- }
Data = AhciReadReg (PciIo, Offset);
if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {
AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);
}
-
- AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE|EFI_AHCI_PORT_CMD_COL|EFI_AHCI_PORT_CMD_ST));
- }
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;
- AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_MASK));
-
- AhciAndReg (PciIo, Offset,(UINT32) ~(EFI_AHCI_PORT_SCTL_IPM_PSD));
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_PSD);
-
- AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_SSD));
- AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_SSD);
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;
- AhciAndReg (PciIo, Offset, 0);
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
- AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));
- }
- //
- // Stall for 100 milliseconds.
- //
- MicroSecondDelay(100000);
-
- IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);
-
- for (Port = 0; Port < MaxPortNumber; Port ++) {
- if ((PortImplementBitMap & (BIT0 << Port)) != 0) {
-
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;
- Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;
+ if ((Capability & EFI_AHCI_CAP_SSS) != 0) {
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);
+ }
+
+ //
+ // Disable aggressive power management.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);
+ //
+ // Disable the reporting of the corresponding interrupt to system software.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;
+ AhciAndReg (PciIo, Offset, 0);
- if (Data == 0) {
+ //
+ // Now inform the IDE Controller Init Module.
+ //
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);
+
+ //
+ // Enable FIS Receive DMA engine for the first D2H FIS.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);
+ Status = AhciWaitMemSet (
+ PciIo,
+ Offset,
+ EFI_AHCI_PORT_CMD_FR,
+ EFI_AHCI_PORT_CMD_FR,
+ EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
continue;
}
+
//
- // Found device in the port
+ // Wait no longer than 10 ms to wait the Phy to detect the presence of a device.
+ // It's the requirment from SATA1.0a spec section 5.2.
//
- if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;
-
- Status = AhciWaitMemSet (
- PciIo,
- Offset,
- 0x0000FFFF,
- 0x00000101,
- ATA_ATAPI_TIMEOUT
- );
- if (EFI_ERROR (Status)) {
- continue;
+ PhyDetectDelay = EFI_AHCI_BUS_PHY_DETECT_TIMEOUT;
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;
+ do {
+ Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;
+ if ((Data == EFI_AHCI_PORT_SSTS_DET_PCE) || (Data == EFI_AHCI_PORT_SSTS_DET)) {
+ break;
}
+ MicroSecondDelay (1000);
+ PhyDetectDelay--;
+ } while (PhyDetectDelay > 0);
+
+ if (PhyDetectDelay == 0) {
//
- // Now inform the IDE Controller Init Module.
+ // No device detected at this port.
//
- IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);
+ continue;
+ }
- Data = AhciReadReg (PciIo, Offset);
+ //
+ // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
+ // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
+ //
+ PhyDetectDelay = 16 * 1000;
+ do {
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
+ if (AhciReadReg(PciIo, Offset) != 0) {
+ AhciWriteReg (PciIo, Offset, AhciReadReg(PciIo, Offset));
+ }
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
- if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {
- Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);
+ Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK;
+ if (Data == 0) {
+ break;
+ }
- if (EFI_ERROR (Status)) {
- continue;
- }
+ MicroSecondDelay (1000);
+ PhyDetectDelay--;
+ } while (PhyDetectDelay > 0);
+
+ if (PhyDetectDelay == 0) {
+ continue;
+ }
- DeviceType = EfiIdeCdrom;
- } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {
- Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);
+ //
+ // When the first D2H register FIS is received, the content of PxSIG register is updated.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;
+ Status = AhciWaitMemSet (
+ PciIo,
+ Offset,
+ 0x0000FFFF,
+ 0x00000101,
+ EFI_TIMER_PERIOD_SECONDS(16)
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
- if (EFI_ERROR (Status)) {
- REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));
- continue;
- }
+ Data = AhciReadReg (PciIo, Offset);
+ if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {
+ Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);
- DeviceType = EfiIdeHarddisk;
- } else {
+ if (EFI_ERROR (Status)) {
continue;
}
- DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n",
- Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));
-
- //
- // If the device is a hard disk, then try to enable S.M.A.R.T feature
- //
- if (DeviceType == EfiIdeHarddisk) {
- AhciAtaSmartSupport (
- PciIo,
- AhciRegisters,
- Port,
- 0,
- &Buffer,
- NULL
- );
- }
-
- //
- // Submit identify data to IDE controller init driver
- //
- IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);
+ DeviceType = EfiIdeCdrom;
+ } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {
+ Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);
- //
- // Now start to config ide device parameter and transfer mode.
- //
- Status = IdeInit->CalculateMode (
- IdeInit,
- Port,
- 0,
- &SupportedModes
- );
if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));
continue;
}
- //
- // Set best supported PIO mode on this IDE device
- //
- if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {
- TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;
- } else {
- TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;
- }
+ DeviceType = EfiIdeHarddisk;
+ } else {
+ continue;
+ }
+ DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n",
+ Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));
- TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);
-
- //
- // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
- // be set together. Only one DMA mode can be set to a device. If setting
- // DMA mode operation fails, we can continue moving on because we only use
- // PIO mode at boot time. DMA modes are used by certain kind of OS booting
- //
- if (SupportedModes->UdmaMode.Valid) {
- TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;
- TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);
- } else if (SupportedModes->MultiWordDmaMode.Valid) {
- TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;
- TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;
- }
+ //
+ // If the device is a hard disk, then try to enable S.M.A.R.T feature
+ //
+ if (DeviceType == EfiIdeHarddisk) {
+ AhciAtaSmartSupport (
+ PciIo,
+ AhciRegisters,
+ Port,
+ 0,
+ &Buffer,
+ NULL
+ );
+ }
- Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));
+ //
+ // Submit identify data to IDE controller init driver
+ //
+ IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));
- continue;
- }
- //
- // Found a ATA or ATAPI device, add it into the device list.
- //
- CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);
- if (DeviceType == EfiIdeHarddisk) {
- REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));
- }
+ //
+ // Now start to config ide device parameter and transfer mode.
+ //
+ Status = IdeInit->CalculateMode (
+ IdeInit,
+ Port,
+ 0,
+ &SupportedModes
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));
+ continue;
+ }
+
+ //
+ // Set best supported PIO mode on this IDE device
+ //
+ if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {
+ TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;
+ } else {
+ TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;
+ }
+
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);
+
+ //
+ // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
+ // be set together. Only one DMA mode can be set to a device. If setting
+ // DMA mode operation fails, we can continue moving on because we only use
+ // PIO mode at boot time. DMA modes are used by certain kind of OS booting
+ //
+ if (SupportedModes->UdmaMode.Valid) {
+ TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);
+ } else if (SupportedModes->MultiWordDmaMode.Valid) {
+ TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;
+ TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;
+ }
+
+ Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));
+ continue;
+ }
+
+ //
+ // Found a ATA or ATAPI device, add it into the device list.
+ //
+ CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);
+ if (DeviceType == EfiIdeHarddisk) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));
}
}
}
+
return EFI_SUCCESS;
}
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
index 9c4a9397e9..032b97cd2f 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
@@ -17,6 +17,8 @@
#define EFI_AHCI_BAR_INDEX 0x05
#define EFI_AHCI_CAPABILITY_OFFSET 0x0000
+#define EFI_AHCI_CAP_SSS BIT27
+#define EFI_AHCI_CAP_S64A BIT31
#define EFI_AHCI_GHC_OFFSET 0x0004
#define EFI_AHCI_GHC_RESET BIT0
#define EFI_AHCI_GHC_IE BIT1
@@ -34,6 +36,19 @@ typedef union {
UINT64 Uint64;
} DATA_64;
+//
+// Refer SATA1.0a spec section 5.2, the Phy detection time should be less than 10ms.
+//
+#define EFI_AHCI_BUS_PHY_DETECT_TIMEOUT 10
+//
+// Refer SATA1.0a spec, the FIS enable time should be less than 500ms.
+//
+#define EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT EFI_TIMER_PERIOD_MILLISECONDS(500)
+//
+// Refer SATA1.0a spec, the bus reset time should be less than 1s.
+//
+#define EFI_AHCI_BUS_RESET_TIMEOUT EFI_TIMER_PERIOD_SECONDS(1)
+
#define EFI_AHCI_ATAPI_DEVICE_SIG 0xEB140000
#define EFI_AHCI_ATA_DEVICE_SIG 0x00000000
#define EFI_AHCI_PORT_MULTIPLIER_SIG 0x96690000
@@ -103,7 +118,7 @@ typedef union {
#define EFI_AHCI_PORT_CMD_ST BIT0
#define EFI_AHCI_PORT_CMD_SUD BIT1
#define EFI_AHCI_PORT_CMD_POD BIT2
-#define EFI_AHCI_PORT_CMD_COL BIT3
+#define EFI_AHCI_PORT_CMD_CLO BIT3
#define EFI_AHCI_PORT_CMD_CR BIT15
#define EFI_AHCI_PORT_CMD_FRE BIT4
#define EFI_AHCI_PORT_CMD_FR BIT14
diff --git a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
index e6d963672e..bfb36df828 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
+++ b/MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
@@ -1026,10 +1026,63 @@ ScsiScanCreateDevice (
EFI_STATUS Status;
SCSI_IO_DEV *ScsiIoDevice;
EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_HANDLE DeviceHandle;
+
+ DevicePath = NULL;
+ RemainingDevicePath = NULL;
+ ScsiDevicePath = NULL;
+ ScsiIoDevice = NULL;
+
+ //
+ // Build Device Path
+ //
+ if (ScsiBusDev->ExtScsiSupport){
+ Status = ScsiBusDev->ExtScsiInterface->BuildDevicePath (
+ ScsiBusDev->ExtScsiInterface,
+ &TargetId->ScsiId.ExtScsi[0],
+ Lun,
+ &ScsiDevicePath
+ );
+ } else {
+ Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath (
+ ScsiBusDev->ScsiInterface,
+ TargetId->ScsiId.Scsi,
+ Lun,
+ &ScsiDevicePath
+ );
+ }
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ DevicePath = AppendDevicePathNode (
+ ScsiBusDev->DevicePath,
+ ScsiDevicePath
+ );
+
+ if (DevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ DeviceHandle = NULL;
+ RemainingDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
+ if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
+ //
+ // The device has been started, directly return to fast boot.
+ //
+ Status = EFI_ALREADY_STARTED;
+ goto ErrorExit;
+ }
ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV));
if (ScsiIoDevice == NULL) {
- return EFI_OUT_OF_RESOURCES;
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
}
ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE;
@@ -1053,52 +1106,12 @@ ScsiScanCreateDevice (
ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice;
ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand;
-
if (!DiscoverScsiDevice (ScsiIoDevice)) {
- FreePool (ScsiIoDevice);
- return EFI_OUT_OF_RESOURCES;
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
}
- //
- // Set Device Path
- //
- ScsiDevicePath = NULL;
- if (ScsiIoDevice->ExtScsiSupport){
- Status = ScsiIoDevice->ExtScsiPassThru->BuildDevicePath (
- ScsiIoDevice->ExtScsiPassThru,
- &ScsiIoDevice->Pun.ScsiId.ExtScsi[0],
- ScsiIoDevice->Lun,
- &ScsiDevicePath
- );
- } else {
- Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath (
- ScsiIoDevice->ScsiPassThru,
- ScsiIoDevice->Pun.ScsiId.Scsi,
- ScsiIoDevice->Lun,
- &ScsiDevicePath
- );
- }
-
- if (EFI_ERROR(Status)) {
- FreePool (ScsiIoDevice);
- return Status;
- }
-
- ScsiIoDevice->DevicePath = AppendDevicePathNode (
- ScsiBusDev->DevicePath,
- ScsiDevicePath
- );
- //
- // The memory space for ScsiDevicePath is allocated in
- // ScsiPassThru->BuildDevicePath() function; It is no longer used
- // after EfiAppendDevicePathNode,so free the memory it occupies.
- //
- FreePool (ScsiDevicePath);
-
- if (ScsiIoDevice->DevicePath == NULL) {
- FreePool (ScsiIoDevice);
- return EFI_OUT_OF_RESOURCES;
- }
+ ScsiIoDevice->DevicePath = DevicePath;
Status = gBS->InstallMultipleProtocolInterfaces (
&ScsiIoDevice->Handle,
@@ -1109,31 +1122,48 @@ ScsiScanCreateDevice (
NULL
);
if (EFI_ERROR (Status)) {
- FreePool (ScsiIoDevice->DevicePath);
- FreePool (ScsiIoDevice);
- return EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
} else {
if (ScsiBusDev->ExtScsiSupport) {
gBS->OpenProtocol (
- Controller,
- &gEfiExtScsiPassThruProtocolGuid,
- (VOID **) &(ScsiBusDev->ExtScsiInterface),
- This->DriverBindingHandle,
- ScsiIoDevice->Handle,
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
- );
+ Controller,
+ &gEfiExtScsiPassThruProtocolGuid,
+ (VOID **) &(ScsiBusDev->ExtScsiInterface),
+ This->DriverBindingHandle,
+ ScsiIoDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
} else {
gBS->OpenProtocol (
- Controller,
- &gEfiScsiPassThruProtocolGuid,
- (VOID **) &(ScsiBusDev->ScsiInterface),
- This->DriverBindingHandle,
- ScsiIoDevice->Handle,
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
- );
+ Controller,
+ &gEfiScsiPassThruProtocolGuid,
+ (VOID **) &(ScsiBusDev->ScsiInterface),
+ This->DriverBindingHandle,
+ ScsiIoDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
}
}
return EFI_SUCCESS;
+
+ErrorExit:
+
+ //
+ // The memory space for ScsiDevicePath is allocated in
+ // ScsiPassThru->BuildDevicePath() function; It is no longer used
+ // after AppendDevicePathNode,so free the memory it occupies.
+ //
+ FreePool (ScsiDevicePath);
+
+ if (DevicePath != NULL) {
+ FreePool (DevicePath);
+ }
+
+ if (ScsiIoDevice != NULL) {
+ FreePool (ScsiIoDevice);
+ }
+
+ return Status;
}
@@ -1158,6 +1188,8 @@ DiscoverScsiDevice (
UINT8 TargetStatus;
EFI_SCSI_SENSE_DATA SenseData;
EFI_SCSI_INQUIRY_DATA InquiryData;
+ UINT8 MaxRetry;
+ UINT8 Index;
HostAdapterStatus = 0;
TargetStatus = 0;
@@ -1166,21 +1198,34 @@ DiscoverScsiDevice (
//
InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA);
+ ZeroMem (&InquiryData, InquiryDataLength);
+
+ MaxRetry = 2;
+ for (Index = 0; Index < MaxRetry; Index++) {
+ Status = ScsiInquiryCommand (
+ &ScsiIoDevice->ScsiIo,
+ EFI_TIMER_PERIOD_SECONDS (1),
+ (VOID *) &SenseData,
+ &SenseDataLength,
+ &HostAdapterStatus,
+ &TargetStatus,
+ (VOID *) &InquiryData,
+ &InquiryDataLength,
+ FALSE
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ } else if ((Status == EFI_BAD_BUFFER_SIZE) ||
+ (Status == EFI_INVALID_PARAMETER) ||
+ (Status == EFI_UNSUPPORTED)) {
+ return FALSE;
+ }
+ }
- Status = ScsiInquiryCommand (
- &ScsiIoDevice->ScsiIo,
- EFI_TIMER_PERIOD_SECONDS (1),
- (VOID *) &SenseData,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- (VOID *) &InquiryData,
- &InquiryDataLength,
- FALSE
- );
- if (EFI_ERROR (Status) && Status != EFI_BAD_BUFFER_SIZE) {
+ if (Index == MaxRetry) {
return FALSE;
}
+
//
// Retrieved inquiry data successfully
//
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
index f0e10997da..e9a7788faf 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
@@ -166,6 +166,9 @@ ScsiDiskDriverBindingStart (
UINT8 Index;
UINT8 MaxRetry;
BOOLEAN NeedRetry;
+ BOOLEAN MustReadCapacity;
+
+ MustReadCapacity = TRUE;
ScsiDiskDevice = (SCSI_DISK_DEV *) AllocateZeroPool (sizeof (SCSI_DISK_DEV));
if (ScsiDiskDevice == NULL) {
@@ -199,10 +202,12 @@ ScsiDiskDriverBindingStart (
switch (ScsiDiskDevice->DeviceType) {
case EFI_SCSI_TYPE_DISK:
ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
+ MustReadCapacity = TRUE;
break;
case EFI_SCSI_TYPE_CDROM:
ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
+ MustReadCapacity = FALSE;
break;
}
//
@@ -249,7 +254,7 @@ ScsiDiskDriverBindingStart (
// The second parameter "TRUE" means must
// retrieve media capacity
//
- Status = ScsiDiskDetectMedia (ScsiDiskDevice, TRUE, &Temp);
+ Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);
if (!EFI_ERROR (Status)) {
//
// Determine if Block IO should be produced on this controller handle
@@ -710,6 +715,7 @@ ScsiDiskDetectMedia (
CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
*MediaChange = FALSE;
MaxRetry = 3;
+ Action = ACTION_NO_ACTION;
for (Index = 0; Index < MaxRetry; Index++) {
Status = ScsiDiskTestUnitReady (
@@ -719,7 +725,19 @@ ScsiDiskDetectMedia (
&NumberOfSenseKeys
);
if (!EFI_ERROR (Status)) {
- break;
+ Status = DetectMediaParsingSenseKeys (
+ ScsiDiskDevice,
+ SenseData,
+ NumberOfSenseKeys,
+ &Action
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ } else if (Action == ACTION_RETRY_COMMAND_LATER) {
+ continue;
+ } else {
+ break;
+ }
}
if (!NeedRetry) {
@@ -731,22 +749,11 @@ ScsiDiskDetectMedia (
return EFI_DEVICE_ERROR;
}
- Status = DetectMediaParsingSenseKeys (
- ScsiDiskDevice,
- SenseData,
- NumberOfSenseKeys,
- &Action
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
//
// ACTION_NO_ACTION: need not read capacity
// other action code: need read capacity
//
- if (Action == ACTION_NO_ACTION) {
- NeedReadCapacity = FALSE;
- } else {
+ if (Action == ACTION_READ_CAPACITY) {
NeedReadCapacity = TRUE;
}
@@ -1205,6 +1212,11 @@ DetectMediaParsingSenseKeys (
return EFI_SUCCESS;
}
+ if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
+ *Action = ACTION_RETRY_COMMAND_LATER;
+ return EFI_SUCCESS;
+ }
+
if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
ScsiDiskDevice->BlkIo.Media->LastBlock = 0;