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:
@@ -2,7 +2,7 @@
|
||||
This file implements ATA_PASSTHRU_PROCTOCOL and EXT_SCSI_PASSTHRU_PROTOCOL interfaces
|
||||
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
|
||||
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
|
||||
@@ -1831,6 +1831,57 @@ AtaPassThruResetDevice (
|
||||
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
|
||||
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;
|
||||
LIST_ENTRY *Node;
|
||||
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)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
@@ -1904,6 +1960,10 @@ ExtScsiPassThruPassThru (
|
||||
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)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
@@ -1951,6 +2011,10 @@ ExtScsiPassThruPassThru (
|
||||
//
|
||||
if (*((UINT8*)Packet->Cdb) == ATA_CMD_IDENTIFY_DEVICE) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1976,6 +2040,46 @@ ExtScsiPassThruPassThru (
|
||||
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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user