mirror of https://github.com/acidanthera/audk.git
MdeModulePkg/ScsiDisk: Using back-off algorithm to dynamically adjust transfer length in a single SCSI/ATAPI transfer to reach best device compatibility.
Besides this, the patch also fixed: 1) Wrong return value in SenseDataLength field of packet field of EFI_EXT_SCSI_PASS_THRU protocol, it should reflect real sense data length we got. 2) Wrong logic in ScsiDiskRequestSenseKeys that the logic makes SenseData pointer unaligned compared with BlockIo.Media.IoAlign field. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Tian, Feng <feng.tian@intel.com> Reviewed-by: Zeng, Star <star.zeng@intel.com> Reviewed-by: Fu, Siyuan <siyuan.fu@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15491 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
56dea5e177
commit
73a9e82214
|
@ -2,7 +2,7 @@
|
||||||
This file implements ATA_PASSTHRU_PROCTOCOL and EXT_SCSI_PASSTHRU_PROTOCOL interfaces
|
This file implements ATA_PASSTHRU_PROCTOCOL and EXT_SCSI_PASSTHRU_PROTOCOL interfaces
|
||||||
for managed ATA controllers.
|
for managed ATA controllers.
|
||||||
|
|
||||||
Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
which accompanies this distribution. The full text of the license may be found at
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
@ -1831,6 +1831,57 @@ AtaPassThruResetDevice (
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sumbit ATAPI request sense command.
|
||||||
|
|
||||||
|
@param[in] This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
|
||||||
|
@param[in] Target The Target is an array of size TARGET_MAX_BYTES and it represents
|
||||||
|
the id of the SCSI device to send the SCSI Request Packet. Each
|
||||||
|
transport driver may choose to utilize a subset of this size to suit the needs
|
||||||
|
of transport target representation. For example, a Fibre Channel driver
|
||||||
|
may use only 8 bytes (WWN) to represent an FC target.
|
||||||
|
@param[in] Lun The LUN of the SCSI device to send the SCSI Request Packet.
|
||||||
|
@param[in] SenseData A pointer to store sense data.
|
||||||
|
@param[in] SenseDataLength The sense data length.
|
||||||
|
@param[in] Timeout The timeout value to execute this cmd, uses 100ns as a unit.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Send out the ATAPI packet command successfully.
|
||||||
|
@retval EFI_DEVICE_ERROR The device failed to send data.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
AtaPacketRequestSense (
|
||||||
|
IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
|
||||||
|
IN UINT8 *Target,
|
||||||
|
IN UINT64 Lun,
|
||||||
|
IN VOID *SenseData,
|
||||||
|
IN UINT8 SenseDataLength,
|
||||||
|
IN UINT64 Timeout
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;
|
||||||
|
UINT8 Cdb[12];
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
ZeroMem (&Packet, sizeof (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
|
||||||
|
ZeroMem (Cdb, 12);
|
||||||
|
|
||||||
|
Cdb[0] = ATA_CMD_REQUEST_SENSE;
|
||||||
|
Cdb[4] = SenseDataLength;
|
||||||
|
|
||||||
|
Packet.Timeout = Timeout;
|
||||||
|
Packet.Cdb = Cdb;
|
||||||
|
Packet.CdbLength = 12;
|
||||||
|
Packet.DataDirection = EFI_EXT_SCSI_DATA_DIRECTION_READ;
|
||||||
|
Packet.InDataBuffer = SenseData;
|
||||||
|
Packet.InTransferLength = SenseDataLength;
|
||||||
|
|
||||||
|
Status = ExtScsiPassThruPassThru (This, Target, Lun, &Packet, NULL);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. This function
|
Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. This function
|
||||||
supports both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the
|
supports both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the
|
||||||
|
@ -1889,8 +1940,13 @@ ExtScsiPassThruPassThru (
|
||||||
EFI_ATA_HC_WORK_MODE Mode;
|
EFI_ATA_HC_WORK_MODE Mode;
|
||||||
LIST_ENTRY *Node;
|
LIST_ENTRY *Node;
|
||||||
EFI_ATA_DEVICE_INFO *DeviceInfo;
|
EFI_ATA_DEVICE_INFO *DeviceInfo;
|
||||||
|
BOOLEAN SenseReq;
|
||||||
|
EFI_SCSI_SENSE_DATA *PtrSenseData;
|
||||||
|
UINTN SenseDataLen;
|
||||||
|
EFI_STATUS SenseStatus;
|
||||||
|
|
||||||
Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
|
SenseDataLen = 0;
|
||||||
|
Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
|
||||||
|
|
||||||
if ((Packet == NULL) || (Packet->Cdb == NULL)) {
|
if ((Packet == NULL) || (Packet->Cdb == NULL)) {
|
||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
|
@ -1904,6 +1960,10 @@ ExtScsiPassThruPassThru (
|
||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((Packet->SenseDataLength != 0) && (Packet->SenseData == NULL)) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
|
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
|
||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
@ -1951,6 +2011,10 @@ ExtScsiPassThruPassThru (
|
||||||
//
|
//
|
||||||
if (*((UINT8*)Packet->Cdb) == ATA_CMD_IDENTIFY_DEVICE) {
|
if (*((UINT8*)Packet->Cdb) == ATA_CMD_IDENTIFY_DEVICE) {
|
||||||
CopyMem (Packet->InDataBuffer, DeviceInfo->IdentifyData, sizeof (EFI_IDENTIFY_DATA));
|
CopyMem (Packet->InDataBuffer, DeviceInfo->IdentifyData, sizeof (EFI_IDENTIFY_DATA));
|
||||||
|
//
|
||||||
|
// For IDENTIFY DEVICE cmd, we don't need to get sense data.
|
||||||
|
//
|
||||||
|
Packet->SenseDataLength = 0;
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1976,6 +2040,46 @@ ExtScsiPassThruPassThru (
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// If the cmd doesn't get executed correctly, then check sense data.
|
||||||
|
//
|
||||||
|
if (EFI_ERROR (Status) && (Packet->SenseDataLength != 0) && (*((UINT8*)Packet->Cdb) != ATA_CMD_REQUEST_SENSE)) {
|
||||||
|
PtrSenseData = AllocateAlignedPages (EFI_SIZE_TO_PAGES (sizeof (EFI_SCSI_SENSE_DATA)), This->Mode->IoAlign);
|
||||||
|
if (PtrSenseData == NULL) {
|
||||||
|
return EFI_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SenseReq = TRUE; SenseReq;) {
|
||||||
|
SenseStatus = AtaPacketRequestSense (
|
||||||
|
This,
|
||||||
|
Target,
|
||||||
|
Lun,
|
||||||
|
PtrSenseData,
|
||||||
|
sizeof (EFI_SCSI_SENSE_DATA),
|
||||||
|
Packet->Timeout
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (SenseStatus)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyMem ((UINT8*)Packet->SenseData + SenseDataLen, PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
|
||||||
|
SenseDataLen += sizeof (EFI_SCSI_SENSE_DATA);
|
||||||
|
|
||||||
|
//
|
||||||
|
// no more sense key or number of sense keys exceeds predefined,
|
||||||
|
// skip the loop.
|
||||||
|
//
|
||||||
|
if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
|
||||||
|
(SenseDataLen + sizeof (EFI_SCSI_SENSE_DATA) > Packet->SenseDataLength)) {
|
||||||
|
SenseReq = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FreeAlignedPages (PtrSenseData, EFI_SIZE_TO_PAGES (sizeof (EFI_SCSI_SENSE_DATA)));
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Update the SenseDataLength field to the data length received.
|
||||||
|
//
|
||||||
|
Packet->SenseDataLength = (UINT8)SenseDataLen;
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/** @file
|
/** @file
|
||||||
Header file for AHCI mode of ATA host controller.
|
Header file for AHCI mode of ATA host controller.
|
||||||
|
|
||||||
Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
which accompanies this distribution. The full text of the license may be found at
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
@ -1941,56 +1941,6 @@ AtaPacketReadWrite (
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Sumbit ATAPI request sense command.
|
|
||||||
|
|
||||||
@param[in] PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
|
|
||||||
@param[in] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to
|
|
||||||
store the IDE i/o port registers' base addresses
|
|
||||||
@param[in] Channel The channel number of device.
|
|
||||||
@param[in] Device The device number of device.
|
|
||||||
@param[in] SenseData A pointer to store sense data.
|
|
||||||
@param[in] SenseDataLength The sense data length.
|
|
||||||
@param[in] Timeout The timeout value to execute this cmd, uses 100ns as a unit.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Send out the ATAPI packet command successfully.
|
|
||||||
@retval EFI_DEVICE_ERROR The device failed to send data.
|
|
||||||
|
|
||||||
**/
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
AtaPacketRequestSense (
|
|
||||||
IN EFI_PCI_IO_PROTOCOL *PciIo,
|
|
||||||
IN EFI_IDE_REGISTERS *IdeRegisters,
|
|
||||||
IN UINT8 Channel,
|
|
||||||
IN UINT8 Device,
|
|
||||||
IN VOID *SenseData,
|
|
||||||
IN UINT8 SenseDataLength,
|
|
||||||
IN UINT64 Timeout
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;
|
|
||||||
UINT8 Cdb[12];
|
|
||||||
EFI_STATUS Status;
|
|
||||||
|
|
||||||
ZeroMem (&Packet, sizeof (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
|
|
||||||
ZeroMem (Cdb, 12);
|
|
||||||
|
|
||||||
Cdb[0] = ATA_CMD_REQUEST_SENSE;
|
|
||||||
Cdb[4] = SenseDataLength;
|
|
||||||
|
|
||||||
Packet.Timeout = Timeout;
|
|
||||||
Packet.Cdb = Cdb;
|
|
||||||
Packet.CdbLength = 12;
|
|
||||||
Packet.DataDirection = EFI_EXT_SCSI_DATA_DIRECTION_READ;
|
|
||||||
Packet.InDataBuffer = SenseData;
|
|
||||||
Packet.InTransferLength = SenseDataLength;
|
|
||||||
|
|
||||||
Status = AtaPacketCommandExecute (PciIo, IdeRegisters, Channel, Device, &Packet);
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This function is used to send out ATAPI commands conforms to the Packet Command
|
This function is used to send out ATAPI commands conforms to the Packet Command
|
||||||
with PIO Data In Protocol.
|
with PIO Data In Protocol.
|
||||||
|
@ -2017,7 +1967,6 @@ AtaPacketCommandExecute (
|
||||||
IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
|
IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
EFI_STATUS PacketCommandStatus;
|
|
||||||
EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
|
EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
UINT8 Count;
|
UINT8 Count;
|
||||||
|
@ -2083,56 +2032,26 @@ AtaPacketCommandExecute (
|
||||||
// Read/Write the data of ATAPI Command
|
// Read/Write the data of ATAPI Command
|
||||||
//
|
//
|
||||||
if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
|
if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
|
||||||
PacketCommandStatus = AtaPacketReadWrite (
|
Status = AtaPacketReadWrite (
|
||||||
PciIo,
|
PciIo,
|
||||||
IdeRegisters,
|
IdeRegisters,
|
||||||
Packet->InDataBuffer,
|
Packet->InDataBuffer,
|
||||||
Packet->InTransferLength,
|
Packet->InTransferLength,
|
||||||
TRUE,
|
TRUE,
|
||||||
Packet->Timeout
|
Packet->Timeout
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
PacketCommandStatus = AtaPacketReadWrite (
|
Status = AtaPacketReadWrite (
|
||||||
PciIo,
|
PciIo,
|
||||||
IdeRegisters,
|
IdeRegisters,
|
||||||
Packet->OutDataBuffer,
|
Packet->OutDataBuffer,
|
||||||
Packet->OutTransferLength,
|
Packet->OutTransferLength,
|
||||||
FALSE,
|
FALSE,
|
||||||
Packet->Timeout
|
Packet->Timeout
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EFI_ERROR (PacketCommandStatus)) {
|
return Status;
|
||||||
return PacketCommandStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Return SenseData if PacketCommandStatus matches
|
|
||||||
// the following return codes.
|
|
||||||
//
|
|
||||||
if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||
|
|
||||||
(PacketCommandStatus == EFI_DEVICE_ERROR) ||
|
|
||||||
(PacketCommandStatus == EFI_TIMEOUT)) {
|
|
||||||
|
|
||||||
//
|
|
||||||
// avoid submit request sense command continuously.
|
|
||||||
//
|
|
||||||
if ((Packet->SenseData == NULL) || (((UINT8 *)Packet->Cdb)[0] == ATA_CMD_REQUEST_SENSE)) {
|
|
||||||
return PacketCommandStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
AtaPacketRequestSense (
|
|
||||||
PciIo,
|
|
||||||
IdeRegisters,
|
|
||||||
Channel,
|
|
||||||
Device,
|
|
||||||
Packet->SenseData,
|
|
||||||
Packet->SenseDataLength,
|
|
||||||
Packet->Timeout
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return PacketCommandStatus;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1279,40 +1279,46 @@ DetectMediaParsingSenseKeys (
|
||||||
ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
|
ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
|
||||||
ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
|
ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
|
||||||
*Action = ACTION_NO_ACTION;
|
*Action = ACTION_NO_ACTION;
|
||||||
|
DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
|
if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
|
||||||
ScsiDiskDevice->BlkIo.Media->MediaId++;
|
ScsiDiskDevice->BlkIo.Media->MediaId++;
|
||||||
|
DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
|
if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
|
||||||
*Action = ACTION_RETRY_COMMAND_LATER;
|
*Action = ACTION_RETRY_COMMAND_LATER;
|
||||||
|
DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
|
if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
|
||||||
ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
|
DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));
|
||||||
ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
|
*Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
|
||||||
*Action = ACTION_NO_ACTION;
|
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
|
if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
|
||||||
*Action = ACTION_NO_ACTION;
|
DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));
|
||||||
|
*Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
|
if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
|
||||||
if (RetryLater) {
|
if (RetryLater) {
|
||||||
*Action = ACTION_RETRY_COMMAND_LATER;
|
*Action = ACTION_RETRY_COMMAND_LATER;
|
||||||
|
DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
*Action = ACTION_NO_ACTION;
|
*Action = ACTION_NO_ACTION;
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
|
||||||
|
DEBUG ((EFI_D_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1618,9 +1624,14 @@ ScsiDiskRequestSenseKeys (
|
||||||
|
|
||||||
*NumberOfSenseKeys = 0;
|
*NumberOfSenseKeys = 0;
|
||||||
*SenseDataArray = ScsiDiskDevice->SenseData;
|
*SenseDataArray = ScsiDiskDevice->SenseData;
|
||||||
PtrSenseData = ScsiDiskDevice->SenseData;
|
Status = EFI_SUCCESS;
|
||||||
|
PtrSenseData = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));
|
||||||
|
if (PtrSenseData == NULL) {
|
||||||
|
return EFI_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
for (SenseReq = TRUE; SenseReq;) {
|
for (SenseReq = TRUE; SenseReq;) {
|
||||||
|
ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
|
||||||
Status = ScsiRequestSenseCommand (
|
Status = ScsiRequestSenseCommand (
|
||||||
ScsiDiskDevice->ScsiIo,
|
ScsiDiskDevice->ScsiIo,
|
||||||
SCSI_DISK_TIMEOUT,
|
SCSI_DISK_TIMEOUT,
|
||||||
|
@ -1651,12 +1662,15 @@ ScsiDiskRequestSenseKeys (
|
||||||
if (EFI_ERROR (FallStatus)) {
|
if (EFI_ERROR (FallStatus)) {
|
||||||
if (*NumberOfSenseKeys != 0) {
|
if (*NumberOfSenseKeys != 0) {
|
||||||
*NeedRetry = FALSE;
|
*NeedRetry = FALSE;
|
||||||
return EFI_SUCCESS;
|
Status = EFI_SUCCESS;
|
||||||
|
goto EXIT;
|
||||||
} else {
|
} else {
|
||||||
return EFI_DEVICE_ERROR;
|
Status = EFI_DEVICE_ERROR;
|
||||||
|
goto EXIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);
|
||||||
(*NumberOfSenseKeys) += 1;
|
(*NumberOfSenseKeys) += 1;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1667,9 +1681,11 @@ ScsiDiskRequestSenseKeys (
|
||||||
(*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
|
(*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
|
||||||
SenseReq = FALSE;
|
SenseReq = FALSE;
|
||||||
}
|
}
|
||||||
PtrSenseData += 1;
|
|
||||||
}
|
}
|
||||||
return EFI_SUCCESS;
|
|
||||||
|
EXIT:
|
||||||
|
FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1780,11 +1796,6 @@ ScsiDiskReadSectors (
|
||||||
UINT8 Index;
|
UINT8 Index;
|
||||||
UINT8 MaxRetry;
|
UINT8 MaxRetry;
|
||||||
BOOLEAN NeedRetry;
|
BOOLEAN NeedRetry;
|
||||||
EFI_SCSI_SENSE_DATA *SenseData;
|
|
||||||
UINTN NumberOfSenseKeys;
|
|
||||||
|
|
||||||
SenseData = NULL;
|
|
||||||
NumberOfSenseKeys = 0;
|
|
||||||
|
|
||||||
Status = EFI_SUCCESS;
|
Status = EFI_SUCCESS;
|
||||||
|
|
||||||
|
@ -1855,8 +1866,6 @@ ScsiDiskReadSectors (
|
||||||
Status = ScsiDiskRead10 (
|
Status = ScsiDiskRead10 (
|
||||||
ScsiDiskDevice,
|
ScsiDiskDevice,
|
||||||
&NeedRetry,
|
&NeedRetry,
|
||||||
&SenseData,
|
|
||||||
&NumberOfSenseKeys,
|
|
||||||
Timeout,
|
Timeout,
|
||||||
PtrBuffer,
|
PtrBuffer,
|
||||||
&ByteCount,
|
&ByteCount,
|
||||||
|
@ -1867,8 +1876,6 @@ ScsiDiskReadSectors (
|
||||||
Status = ScsiDiskRead16 (
|
Status = ScsiDiskRead16 (
|
||||||
ScsiDiskDevice,
|
ScsiDiskDevice,
|
||||||
&NeedRetry,
|
&NeedRetry,
|
||||||
&SenseData,
|
|
||||||
&NumberOfSenseKeys,
|
|
||||||
Timeout,
|
Timeout,
|
||||||
PtrBuffer,
|
PtrBuffer,
|
||||||
&ByteCount,
|
&ByteCount,
|
||||||
|
@ -1934,11 +1941,6 @@ ScsiDiskWriteSectors (
|
||||||
UINT8 Index;
|
UINT8 Index;
|
||||||
UINT8 MaxRetry;
|
UINT8 MaxRetry;
|
||||||
BOOLEAN NeedRetry;
|
BOOLEAN NeedRetry;
|
||||||
EFI_SCSI_SENSE_DATA *SenseData;
|
|
||||||
UINTN NumberOfSenseKeys;
|
|
||||||
|
|
||||||
SenseData = NULL;
|
|
||||||
NumberOfSenseKeys = 0;
|
|
||||||
|
|
||||||
Status = EFI_SUCCESS;
|
Status = EFI_SUCCESS;
|
||||||
|
|
||||||
|
@ -2008,8 +2010,6 @@ ScsiDiskWriteSectors (
|
||||||
Status = ScsiDiskWrite10 (
|
Status = ScsiDiskWrite10 (
|
||||||
ScsiDiskDevice,
|
ScsiDiskDevice,
|
||||||
&NeedRetry,
|
&NeedRetry,
|
||||||
&SenseData,
|
|
||||||
&NumberOfSenseKeys,
|
|
||||||
Timeout,
|
Timeout,
|
||||||
PtrBuffer,
|
PtrBuffer,
|
||||||
&ByteCount,
|
&ByteCount,
|
||||||
|
@ -2020,8 +2020,6 @@ ScsiDiskWriteSectors (
|
||||||
Status = ScsiDiskWrite16 (
|
Status = ScsiDiskWrite16 (
|
||||||
ScsiDiskDevice,
|
ScsiDiskDevice,
|
||||||
&NeedRetry,
|
&NeedRetry,
|
||||||
&SenseData,
|
|
||||||
&NumberOfSenseKeys,
|
|
||||||
Timeout,
|
Timeout,
|
||||||
PtrBuffer,
|
PtrBuffer,
|
||||||
&ByteCount,
|
&ByteCount,
|
||||||
|
@ -2060,13 +2058,11 @@ ScsiDiskWriteSectors (
|
||||||
|
|
||||||
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
||||||
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
||||||
@param SenseDataArray NOT used yet in this function
|
|
||||||
@param NumberOfSenseKeys The number of sense key
|
|
||||||
@param Timeout The time to complete the command
|
@param Timeout The time to complete the command
|
||||||
@param DataBuffer The buffer to fill with the read out data
|
@param DataBuffer The buffer to fill with the read out data
|
||||||
@param DataLength The length of buffer
|
@param DataLength The length of buffer
|
||||||
@param StartLba The start logic block address
|
@param StartLba The start logic block address
|
||||||
@param SectorSize The size of sector
|
@param SectorCount The number of blocks to read
|
||||||
|
|
||||||
@return EFI_STATUS is returned by calling ScsiRead10Command().
|
@return EFI_STATUS is returned by calling ScsiRead10Command().
|
||||||
**/
|
**/
|
||||||
|
@ -2074,13 +2070,11 @@ EFI_STATUS
|
||||||
ScsiDiskRead10 (
|
ScsiDiskRead10 (
|
||||||
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
||||||
OUT BOOLEAN *NeedRetry,
|
OUT BOOLEAN *NeedRetry,
|
||||||
OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
|
|
||||||
OUT UINTN *NumberOfSenseKeys,
|
|
||||||
IN UINT64 Timeout,
|
IN UINT64 Timeout,
|
||||||
OUT UINT8 *DataBuffer,
|
OUT UINT8 *DataBuffer,
|
||||||
IN OUT UINT32 *DataLength,
|
IN OUT UINT32 *DataLength,
|
||||||
IN UINT32 StartLba,
|
IN UINT32 StartLba,
|
||||||
IN UINT32 SectorSize
|
IN UINT32 SectorCount
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UINT8 SenseDataLength;
|
UINT8 SenseDataLength;
|
||||||
|
@ -2090,8 +2084,16 @@ ScsiDiskRead10 (
|
||||||
UINT8 TargetStatus;
|
UINT8 TargetStatus;
|
||||||
UINTN Action;
|
UINTN Action;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Implement a backoff algorithem to resolve some compatibility issues that
|
||||||
|
// some SCSI targets or ATAPI devices couldn't correctly response reading/writing
|
||||||
|
// big data in a single operation.
|
||||||
|
// This algorithem will at first try to execute original request. If the request fails
|
||||||
|
// with media error sense data or else, it will reduce the transfer length to half and
|
||||||
|
// try again till the operation succeeds or fails with one sector transfer length.
|
||||||
|
//
|
||||||
|
BackOff:
|
||||||
*NeedRetry = FALSE;
|
*NeedRetry = FALSE;
|
||||||
*NumberOfSenseKeys = 0;
|
|
||||||
Action = ACTION_NO_ACTION;
|
Action = ACTION_NO_ACTION;
|
||||||
SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
|
SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
|
||||||
ReturnStatus = ScsiRead10Command (
|
ReturnStatus = ScsiRead10Command (
|
||||||
|
@ -2104,7 +2106,7 @@ ScsiDiskRead10 (
|
||||||
DataBuffer,
|
DataBuffer,
|
||||||
DataLength,
|
DataLength,
|
||||||
StartLba,
|
StartLba,
|
||||||
SectorSize
|
SectorCount
|
||||||
);
|
);
|
||||||
|
|
||||||
if (ReturnStatus == EFI_NOT_READY) {
|
if (ReturnStatus == EFI_NOT_READY) {
|
||||||
|
@ -2145,14 +2147,26 @@ ScsiDiskRead10 (
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
|
if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
|
||||||
DEBUG ((EFI_D_VERBOSE, "ScsiDiskRead10: Check Condition happened!\n"));
|
DEBUG ((EFI_D_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));
|
||||||
Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
|
Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
|
||||||
if (EFI_ERROR (Status)) {
|
if (Action == ACTION_RETRY_COMMAND_LATER) {
|
||||||
return Status;
|
|
||||||
} else if (Action == ACTION_RETRY_COMMAND_LATER) {
|
|
||||||
*NeedRetry = TRUE;
|
*NeedRetry = TRUE;
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
|
} else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
|
||||||
|
if (SectorCount <= 1) {
|
||||||
|
//
|
||||||
|
// Jump out if the operation still fails with one sector transfer length.
|
||||||
|
//
|
||||||
|
*NeedRetry = FALSE;
|
||||||
|
return EFI_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Try again with half length if the sense data shows we need to retry.
|
||||||
|
//
|
||||||
|
SectorCount >>= 1;
|
||||||
|
*DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
|
||||||
|
goto BackOff;
|
||||||
} else {
|
} else {
|
||||||
*NeedRetry = FALSE;
|
*NeedRetry = FALSE;
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
|
@ -2168,13 +2182,11 @@ ScsiDiskRead10 (
|
||||||
|
|
||||||
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
||||||
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
||||||
@param SenseDataArray NOT used yet in this function
|
|
||||||
@param NumberOfSenseKeys The number of sense key
|
|
||||||
@param Timeout The time to complete the command
|
@param Timeout The time to complete the command
|
||||||
@param DataBuffer The buffer to fill with the read out data
|
@param DataBuffer The buffer to fill with the read out data
|
||||||
@param DataLength The length of buffer
|
@param DataLength The length of buffer
|
||||||
@param StartLba The start logic block address
|
@param StartLba The start logic block address
|
||||||
@param SectorSize The size of sector
|
@param SectorCount The number of blocks to write
|
||||||
|
|
||||||
@return EFI_STATUS is returned by calling ScsiWrite10Command().
|
@return EFI_STATUS is returned by calling ScsiWrite10Command().
|
||||||
|
|
||||||
|
@ -2183,13 +2195,11 @@ EFI_STATUS
|
||||||
ScsiDiskWrite10 (
|
ScsiDiskWrite10 (
|
||||||
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
||||||
OUT BOOLEAN *NeedRetry,
|
OUT BOOLEAN *NeedRetry,
|
||||||
OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
|
|
||||||
OUT UINTN *NumberOfSenseKeys,
|
|
||||||
IN UINT64 Timeout,
|
IN UINT64 Timeout,
|
||||||
IN UINT8 *DataBuffer,
|
IN UINT8 *DataBuffer,
|
||||||
IN OUT UINT32 *DataLength,
|
IN OUT UINT32 *DataLength,
|
||||||
IN UINT32 StartLba,
|
IN UINT32 StartLba,
|
||||||
IN UINT32 SectorSize
|
IN UINT32 SectorCount
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
|
@ -2199,8 +2209,16 @@ ScsiDiskWrite10 (
|
||||||
UINT8 TargetStatus;
|
UINT8 TargetStatus;
|
||||||
UINTN Action;
|
UINTN Action;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Implement a backoff algorithem to resolve some compatibility issues that
|
||||||
|
// some SCSI targets or ATAPI devices couldn't correctly response reading/writing
|
||||||
|
// big data in a single operation.
|
||||||
|
// This algorithem will at first try to execute original request. If the request fails
|
||||||
|
// with media error sense data or else, it will reduce the transfer length to half and
|
||||||
|
// try again till the operation succeeds or fails with one sector transfer length.
|
||||||
|
//
|
||||||
|
BackOff:
|
||||||
*NeedRetry = FALSE;
|
*NeedRetry = FALSE;
|
||||||
*NumberOfSenseKeys = 0;
|
|
||||||
Action = ACTION_NO_ACTION;
|
Action = ACTION_NO_ACTION;
|
||||||
SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
|
SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
|
||||||
ReturnStatus = ScsiWrite10Command (
|
ReturnStatus = ScsiWrite10Command (
|
||||||
|
@ -2213,7 +2231,7 @@ ScsiDiskWrite10 (
|
||||||
DataBuffer,
|
DataBuffer,
|
||||||
DataLength,
|
DataLength,
|
||||||
StartLba,
|
StartLba,
|
||||||
SectorSize
|
SectorCount
|
||||||
);
|
);
|
||||||
if (ReturnStatus == EFI_NOT_READY) {
|
if (ReturnStatus == EFI_NOT_READY) {
|
||||||
*NeedRetry = TRUE;
|
*NeedRetry = TRUE;
|
||||||
|
@ -2253,14 +2271,26 @@ ScsiDiskWrite10 (
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
|
if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
|
||||||
DEBUG ((EFI_D_VERBOSE, "ScsiDiskWrite10: Check Condition happened!\n"));
|
DEBUG ((EFI_D_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));
|
||||||
Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
|
Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
|
||||||
if (EFI_ERROR (Status)) {
|
if (Action == ACTION_RETRY_COMMAND_LATER) {
|
||||||
return Status;
|
|
||||||
} else if (Action == ACTION_RETRY_COMMAND_LATER) {
|
|
||||||
*NeedRetry = TRUE;
|
*NeedRetry = TRUE;
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
|
} else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
|
||||||
|
if (SectorCount <= 1) {
|
||||||
|
//
|
||||||
|
// Jump out if the operation still fails with one sector transfer length.
|
||||||
|
//
|
||||||
|
*NeedRetry = FALSE;
|
||||||
|
return EFI_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Try again with half length if the sense data shows we need to retry.
|
||||||
|
//
|
||||||
|
SectorCount >>= 1;
|
||||||
|
*DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
|
||||||
|
goto BackOff;
|
||||||
} else {
|
} else {
|
||||||
*NeedRetry = FALSE;
|
*NeedRetry = FALSE;
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
|
@ -2276,27 +2306,23 @@ ScsiDiskWrite10 (
|
||||||
|
|
||||||
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
||||||
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
||||||
@param SenseDataArray NOT used yet in this function
|
|
||||||
@param NumberOfSenseKeys The number of sense key
|
|
||||||
@param Timeout The time to complete the command
|
@param Timeout The time to complete the command
|
||||||
@param DataBuffer The buffer to fill with the read out data
|
@param DataBuffer The buffer to fill with the read out data
|
||||||
@param DataLength The length of buffer
|
@param DataLength The length of buffer
|
||||||
@param StartLba The start logic block address
|
@param StartLba The start logic block address
|
||||||
@param SectorSize The size of sector
|
@param SectorCount The number of blocks to read
|
||||||
|
|
||||||
@return EFI_STATUS is returned by calling ScsiRead10Command().
|
@return EFI_STATUS is returned by calling ScsiRead16Command().
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
ScsiDiskRead16 (
|
ScsiDiskRead16 (
|
||||||
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
||||||
OUT BOOLEAN *NeedRetry,
|
OUT BOOLEAN *NeedRetry,
|
||||||
OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
|
|
||||||
OUT UINTN *NumberOfSenseKeys,
|
|
||||||
IN UINT64 Timeout,
|
IN UINT64 Timeout,
|
||||||
OUT UINT8 *DataBuffer,
|
OUT UINT8 *DataBuffer,
|
||||||
IN OUT UINT32 *DataLength,
|
IN OUT UINT32 *DataLength,
|
||||||
IN UINT64 StartLba,
|
IN UINT64 StartLba,
|
||||||
IN UINT32 SectorSize
|
IN UINT32 SectorCount
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UINT8 SenseDataLength;
|
UINT8 SenseDataLength;
|
||||||
|
@ -2306,8 +2332,16 @@ ScsiDiskRead16 (
|
||||||
UINT8 TargetStatus;
|
UINT8 TargetStatus;
|
||||||
UINTN Action;
|
UINTN Action;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Implement a backoff algorithem to resolve some compatibility issues that
|
||||||
|
// some SCSI targets or ATAPI devices couldn't correctly response reading/writing
|
||||||
|
// big data in a single operation.
|
||||||
|
// This algorithem will at first try to execute original request. If the request fails
|
||||||
|
// with media error sense data or else, it will reduce the transfer length to half and
|
||||||
|
// try again till the operation succeeds or fails with one sector transfer length.
|
||||||
|
//
|
||||||
|
BackOff:
|
||||||
*NeedRetry = FALSE;
|
*NeedRetry = FALSE;
|
||||||
*NumberOfSenseKeys = 0;
|
|
||||||
Action = ACTION_NO_ACTION;
|
Action = ACTION_NO_ACTION;
|
||||||
SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
|
SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
|
||||||
ReturnStatus = ScsiRead16Command (
|
ReturnStatus = ScsiRead16Command (
|
||||||
|
@ -2320,7 +2354,7 @@ ScsiDiskRead16 (
|
||||||
DataBuffer,
|
DataBuffer,
|
||||||
DataLength,
|
DataLength,
|
||||||
StartLba,
|
StartLba,
|
||||||
SectorSize
|
SectorCount
|
||||||
);
|
);
|
||||||
if (ReturnStatus == EFI_NOT_READY) {
|
if (ReturnStatus == EFI_NOT_READY) {
|
||||||
*NeedRetry = TRUE;
|
*NeedRetry = TRUE;
|
||||||
|
@ -2360,14 +2394,26 @@ ScsiDiskRead16 (
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
|
if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
|
||||||
DEBUG ((EFI_D_VERBOSE, "ScsiDiskRead16: Check Condition happened!\n"));
|
DEBUG ((EFI_D_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));
|
||||||
Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
|
Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
|
||||||
if (EFI_ERROR (Status)) {
|
if (Action == ACTION_RETRY_COMMAND_LATER) {
|
||||||
return Status;
|
|
||||||
} else if (Action == ACTION_RETRY_COMMAND_LATER) {
|
|
||||||
*NeedRetry = TRUE;
|
*NeedRetry = TRUE;
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
|
} else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
|
||||||
|
if (SectorCount <= 1) {
|
||||||
|
//
|
||||||
|
// Jump out if the operation still fails with one sector transfer length.
|
||||||
|
//
|
||||||
|
*NeedRetry = FALSE;
|
||||||
|
return EFI_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Try again with half length if the sense data shows we need to retry.
|
||||||
|
//
|
||||||
|
SectorCount >>= 1;
|
||||||
|
*DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
|
||||||
|
goto BackOff;
|
||||||
} else {
|
} else {
|
||||||
*NeedRetry = FALSE;
|
*NeedRetry = FALSE;
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
|
@ -2383,28 +2429,24 @@ ScsiDiskRead16 (
|
||||||
|
|
||||||
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
||||||
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
||||||
@param SenseDataArray NOT used yet in this function
|
|
||||||
@param NumberOfSenseKeys The number of sense key
|
|
||||||
@param Timeout The time to complete the command
|
@param Timeout The time to complete the command
|
||||||
@param DataBuffer The buffer to fill with the read out data
|
@param DataBuffer The buffer to fill with the read out data
|
||||||
@param DataLength The length of buffer
|
@param DataLength The length of buffer
|
||||||
@param StartLba The start logic block address
|
@param StartLba The start logic block address
|
||||||
@param SectorSize The size of sector
|
@param SectorCount The number of blocks to write
|
||||||
|
|
||||||
@return EFI_STATUS is returned by calling ScsiWrite10Command().
|
@return EFI_STATUS is returned by calling ScsiWrite16Command().
|
||||||
|
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
ScsiDiskWrite16 (
|
ScsiDiskWrite16 (
|
||||||
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
||||||
OUT BOOLEAN *NeedRetry,
|
OUT BOOLEAN *NeedRetry,
|
||||||
OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
|
|
||||||
OUT UINTN *NumberOfSenseKeys,
|
|
||||||
IN UINT64 Timeout,
|
IN UINT64 Timeout,
|
||||||
IN UINT8 *DataBuffer,
|
IN UINT8 *DataBuffer,
|
||||||
IN OUT UINT32 *DataLength,
|
IN OUT UINT32 *DataLength,
|
||||||
IN UINT64 StartLba,
|
IN UINT64 StartLba,
|
||||||
IN UINT32 SectorSize
|
IN UINT32 SectorCount
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
|
@ -2414,8 +2456,16 @@ ScsiDiskWrite16 (
|
||||||
UINT8 TargetStatus;
|
UINT8 TargetStatus;
|
||||||
UINTN Action;
|
UINTN Action;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Implement a backoff algorithem to resolve some compatibility issues that
|
||||||
|
// some SCSI targets or ATAPI devices couldn't correctly response reading/writing
|
||||||
|
// big data in a single operation.
|
||||||
|
// This algorithem will at first try to execute original request. If the request fails
|
||||||
|
// with media error sense data or else, it will reduce the transfer length to half and
|
||||||
|
// try again till the operation succeeds or fails with one sector transfer length.
|
||||||
|
//
|
||||||
|
BackOff:
|
||||||
*NeedRetry = FALSE;
|
*NeedRetry = FALSE;
|
||||||
*NumberOfSenseKeys = 0;
|
|
||||||
Action = ACTION_NO_ACTION;
|
Action = ACTION_NO_ACTION;
|
||||||
SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
|
SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
|
||||||
ReturnStatus = ScsiWrite16Command (
|
ReturnStatus = ScsiWrite16Command (
|
||||||
|
@ -2428,7 +2478,7 @@ ScsiDiskWrite16 (
|
||||||
DataBuffer,
|
DataBuffer,
|
||||||
DataLength,
|
DataLength,
|
||||||
StartLba,
|
StartLba,
|
||||||
SectorSize
|
SectorCount
|
||||||
);
|
);
|
||||||
if (ReturnStatus == EFI_NOT_READY) {
|
if (ReturnStatus == EFI_NOT_READY) {
|
||||||
*NeedRetry = TRUE;
|
*NeedRetry = TRUE;
|
||||||
|
@ -2468,14 +2518,26 @@ ScsiDiskWrite16 (
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
|
if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
|
||||||
DEBUG ((EFI_D_VERBOSE, "ScsiDiskWrite16: Check Condition happened!\n"));
|
DEBUG ((EFI_D_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));
|
||||||
Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
|
Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
|
||||||
if (EFI_ERROR (Status)) {
|
if (Action == ACTION_RETRY_COMMAND_LATER) {
|
||||||
return Status;
|
|
||||||
} else if (Action == ACTION_RETRY_COMMAND_LATER) {
|
|
||||||
*NeedRetry = TRUE;
|
*NeedRetry = TRUE;
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
|
} else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
|
||||||
|
if (SectorCount <= 1) {
|
||||||
|
//
|
||||||
|
// Jump out if the operation still fails with one sector transfer length.
|
||||||
|
//
|
||||||
|
*NeedRetry = FALSE;
|
||||||
|
return EFI_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Try again with half length if the sense data shows we need to retry.
|
||||||
|
//
|
||||||
|
SectorCount >>= 1;
|
||||||
|
*DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
|
||||||
|
goto BackOff;
|
||||||
} else {
|
} else {
|
||||||
*NeedRetry = FALSE;
|
*NeedRetry = FALSE;
|
||||||
return EFI_DEVICE_ERROR;
|
return EFI_DEVICE_ERROR;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/** @file
|
/** @file
|
||||||
Header file for SCSI Disk Driver.
|
Header file for SCSI Disk Driver.
|
||||||
|
|
||||||
Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
which accompanies this distribution. The full text of the license may be found at
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
@ -90,9 +90,10 @@ extern EFI_COMPONENT_NAME2_PROTOCOL gScsiDiskComponentName2;
|
||||||
//
|
//
|
||||||
// action code used in detect media process
|
// action code used in detect media process
|
||||||
//
|
//
|
||||||
#define ACTION_NO_ACTION 0x00
|
#define ACTION_NO_ACTION 0x00
|
||||||
#define ACTION_READ_CAPACITY 0x01
|
#define ACTION_READ_CAPACITY 0x01
|
||||||
#define ACTION_RETRY_COMMAND_LATER 0x02
|
#define ACTION_RETRY_COMMAND_LATER 0x02
|
||||||
|
#define ACTION_RETRY_WITH_BACKOFF_ALGO 0x03
|
||||||
|
|
||||||
#define SCSI_COMMAND_VERSION_1 0x01
|
#define SCSI_COMMAND_VERSION_1 0x01
|
||||||
#define SCSI_COMMAND_VERSION_2 0x02
|
#define SCSI_COMMAND_VERSION_2 0x02
|
||||||
|
@ -717,17 +718,15 @@ ScsiDiskWriteSectors (
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Submit Read command.
|
Submit Read(10) command.
|
||||||
|
|
||||||
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
||||||
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
||||||
@param SenseDataArray NOT used yet in this function
|
|
||||||
@param NumberOfSenseKeys The number of sense key
|
|
||||||
@param Timeout The time to complete the command
|
@param Timeout The time to complete the command
|
||||||
@param DataBuffer The buffer to fill with the read out data
|
@param DataBuffer The buffer to fill with the read out data
|
||||||
@param DataLength The length of buffer
|
@param DataLength The length of buffer
|
||||||
@param StartLba The start logic block address
|
@param StartLba The start logic block address
|
||||||
@param SectorSize The size of sector
|
@param SectorCount The number of blocks to read
|
||||||
|
|
||||||
@return EFI_STATUS is returned by calling ScsiRead10Command().
|
@return EFI_STATUS is returned by calling ScsiRead10Command().
|
||||||
**/
|
**/
|
||||||
|
@ -735,27 +734,23 @@ EFI_STATUS
|
||||||
ScsiDiskRead10 (
|
ScsiDiskRead10 (
|
||||||
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
||||||
OUT BOOLEAN *NeedRetry,
|
OUT BOOLEAN *NeedRetry,
|
||||||
OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
|
|
||||||
OUT UINTN *NumberOfSenseKeys,
|
|
||||||
IN UINT64 Timeout,
|
IN UINT64 Timeout,
|
||||||
OUT UINT8 *DataBuffer,
|
OUT UINT8 *DataBuffer,
|
||||||
IN OUT UINT32 *DataLength,
|
IN OUT UINT32 *DataLength,
|
||||||
IN UINT32 StartLba,
|
IN UINT32 StartLba,
|
||||||
IN UINT32 SectorSize
|
IN UINT32 SectorCount
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Submit Write Command.
|
Submit Write(10) Command.
|
||||||
|
|
||||||
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
||||||
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
||||||
@param SenseDataArray NOT used yet in this function
|
|
||||||
@param NumberOfSenseKeys The number of sense key
|
|
||||||
@param Timeout The time to complete the command
|
@param Timeout The time to complete the command
|
||||||
@param DataBuffer The buffer to fill with the read out data
|
@param DataBuffer The buffer to fill with the read out data
|
||||||
@param DataLength The length of buffer
|
@param DataLength The length of buffer
|
||||||
@param StartLba The start logic block address
|
@param StartLba The start logic block address
|
||||||
@param SectorSize The size of sector
|
@param SectorCount The number of blocks to write
|
||||||
|
|
||||||
@return EFI_STATUS is returned by calling ScsiWrite10Command().
|
@return EFI_STATUS is returned by calling ScsiWrite10Command().
|
||||||
|
|
||||||
|
@ -764,13 +759,11 @@ EFI_STATUS
|
||||||
ScsiDiskWrite10 (
|
ScsiDiskWrite10 (
|
||||||
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
||||||
OUT BOOLEAN *NeedRetry,
|
OUT BOOLEAN *NeedRetry,
|
||||||
OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
|
|
||||||
OUT UINTN *NumberOfSenseKeys,
|
|
||||||
IN UINT64 Timeout,
|
IN UINT64 Timeout,
|
||||||
IN UINT8 *DataBuffer,
|
IN UINT8 *DataBuffer,
|
||||||
IN OUT UINT32 *DataLength,
|
IN OUT UINT32 *DataLength,
|
||||||
IN UINT32 StartLba,
|
IN UINT32 StartLba,
|
||||||
IN UINT32 SectorSize
|
IN UINT32 SectorCount
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -778,27 +771,23 @@ ScsiDiskWrite10 (
|
||||||
|
|
||||||
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
||||||
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
||||||
@param SenseDataArray NOT used yet in this function
|
|
||||||
@param NumberOfSenseKeys The number of sense key
|
|
||||||
@param Timeout The time to complete the command
|
@param Timeout The time to complete the command
|
||||||
@param DataBuffer The buffer to fill with the read out data
|
@param DataBuffer The buffer to fill with the read out data
|
||||||
@param DataLength The length of buffer
|
@param DataLength The length of buffer
|
||||||
@param StartLba The start logic block address
|
@param StartLba The start logic block address
|
||||||
@param SectorSize The size of sector
|
@param SectorCount The number of blocks to read
|
||||||
|
|
||||||
@return EFI_STATUS is returned by calling ScsiRead10Command().
|
@return EFI_STATUS is returned by calling ScsiRead16Command().
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
ScsiDiskRead16 (
|
ScsiDiskRead16 (
|
||||||
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
||||||
OUT BOOLEAN *NeedRetry,
|
OUT BOOLEAN *NeedRetry,
|
||||||
OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
|
|
||||||
OUT UINTN *NumberOfSenseKeys,
|
|
||||||
IN UINT64 Timeout,
|
IN UINT64 Timeout,
|
||||||
OUT UINT8 *DataBuffer,
|
OUT UINT8 *DataBuffer,
|
||||||
IN OUT UINT32 *DataLength,
|
IN OUT UINT32 *DataLength,
|
||||||
IN UINT64 StartLba,
|
IN UINT64 StartLba,
|
||||||
IN UINT32 SectorSize
|
IN UINT32 SectorCount
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -806,28 +795,24 @@ ScsiDiskRead16 (
|
||||||
|
|
||||||
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
@param ScsiDiskDevice The pointer of ScsiDiskDevice
|
||||||
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
@param NeedRetry The pointer of flag indicates if needs retry if error happens
|
||||||
@param SenseDataArray NOT used yet in this function
|
|
||||||
@param NumberOfSenseKeys The number of sense key
|
|
||||||
@param Timeout The time to complete the command
|
@param Timeout The time to complete the command
|
||||||
@param DataBuffer The buffer to fill with the read out data
|
@param DataBuffer The buffer to fill with the read out data
|
||||||
@param DataLength The length of buffer
|
@param DataLength The length of buffer
|
||||||
@param StartLba The start logic block address
|
@param StartLba The start logic block address
|
||||||
@param SectorSize The size of sector
|
@param SectorCount The number of blocks to write
|
||||||
|
|
||||||
@return EFI_STATUS is returned by calling ScsiWrite10Command().
|
@return EFI_STATUS is returned by calling ScsiWrite16Command().
|
||||||
|
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
ScsiDiskWrite16 (
|
ScsiDiskWrite16 (
|
||||||
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
IN SCSI_DISK_DEV *ScsiDiskDevice,
|
||||||
OUT BOOLEAN *NeedRetry,
|
OUT BOOLEAN *NeedRetry,
|
||||||
OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL
|
|
||||||
OUT UINTN *NumberOfSenseKeys,
|
|
||||||
IN UINT64 Timeout,
|
IN UINT64 Timeout,
|
||||||
IN UINT8 *DataBuffer,
|
IN UINT8 *DataBuffer,
|
||||||
IN OUT UINT32 *DataLength,
|
IN OUT UINT32 *DataLength,
|
||||||
IN UINT64 StartLba,
|
IN UINT64 StartLba,
|
||||||
IN UINT32 SectorSize
|
IN UINT32 SectorCount
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue