From 73a9e82214f3b0935c8f05efa00a0997763f7294 Mon Sep 17 00:00:00 2001 From: "Tian, Feng" Date: Wed, 30 Apr 2014 03:36:14 +0000 Subject: 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 Reviewed-by: Zeng, Star Reviewed-by: Fu, Siyuan git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15491 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c | 108 ++++++++++++++++++- MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c | 117 ++++----------------- 2 files changed, 124 insertions(+), 101 deletions(-) (limited to 'MdeModulePkg/Bus/Ata') diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c index c397a04..a3b9ccd 100644 --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c @@ -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.
+ Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.
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 @@ -1832,6 +1832,57 @@ AtaPassThruResetDevice ( } /** + 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 nonblocking I/O functionality is optional. @@ -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; } diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c index b9d1614..5f362d1 100644 --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c @@ -1,7 +1,7 @@ /** @file Header file for AHCI mode of ATA host controller. - Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.
+ Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.
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 @@ -1942,56 +1942,6 @@ AtaPacketReadWrite ( } /** - 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 with PIO Data In Protocol. @@ -2017,7 +1967,6 @@ AtaPacketCommandExecute ( IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet ) { - EFI_STATUS PacketCommandStatus; EFI_ATA_COMMAND_BLOCK AtaCommandBlock; EFI_STATUS Status; UINT8 Count; @@ -2083,56 +2032,26 @@ AtaPacketCommandExecute ( // Read/Write the data of ATAPI Command // if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) { - PacketCommandStatus = AtaPacketReadWrite ( - PciIo, - IdeRegisters, - Packet->InDataBuffer, - Packet->InTransferLength, - TRUE, - Packet->Timeout - ); + Status = AtaPacketReadWrite ( + PciIo, + IdeRegisters, + Packet->InDataBuffer, + Packet->InTransferLength, + TRUE, + Packet->Timeout + ); } else { - PacketCommandStatus = AtaPacketReadWrite ( - PciIo, - IdeRegisters, - Packet->OutDataBuffer, - Packet->OutTransferLength, - FALSE, - Packet->Timeout - ); - } - - if (!EFI_ERROR (PacketCommandStatus)) { - return PacketCommandStatus; + Status = AtaPacketReadWrite ( + PciIo, + IdeRegisters, + Packet->OutDataBuffer, + Packet->OutTransferLength, + FALSE, + Packet->Timeout + ); } - // - // 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; + return Status; } -- cgit v1.1