From nobody Mon Nov 25 20:24:19 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+67035+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+67035+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1604580101; cv=none; d=zohomail.com; s=zohoarc; b=ARxnPFLBEQi9s8On6uFyeQV3ciW/OVGz6HgxsJPG32Bnw1tV3plA2OWL+2M4Z+D2qdokJsqhU/a9Oz8txs4dVYyASJ6DC3/ZBLGFLOZpRz5ncQO7RYkSXxrIkRCcddsX/sgc6iiskN5Mn3VrrfeImhAxGXIQ+dR3V8SLE1MGOYA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1604580101; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To; bh=2I+Bprk0eKeLX+Kb/DyziXzJ5tOUwbGOGqzicfb+B38=; b=npMMRHjATqkfEsH6U7KnngwxAtGrB8lZPF/XDP+6HVV0VH28bqR70mcA8lwrSk+zy6HAF3LjbTsmr1qI3THWRQqZq8r7KHCmpiYhOc8793TeiW7iGaY68aBb6D7swhSRV1P5bdxaQV8xRW5LbqFOjauN76zoXPsbiGtOJQP6aEM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+67035+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1604580101357377.28950223821346; Thu, 5 Nov 2020 04:41:41 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id jG9nYY1788612xMrhDF8xivx; Thu, 05 Nov 2020 04:41:40 -0800 X-Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by mx.groups.io with SMTP id smtpd.web08.6941.1604580100503308618 for ; Thu, 05 Nov 2020 04:41:40 -0800 IronPort-SDR: dOu2FXVpBfac7QlKvnaCmEI3Ki7JZURjIFhZhuKDrXKkwE2JOaLjbFHzpGfVLrarXujAHZXzD3 mCZIw4HYzgcw== X-IronPort-AV: E=McAfee;i="6000,8403,9795"; a="254080655" X-IronPort-AV: E=Sophos;i="5.77,453,1596524400"; d="scan'208";a="254080655" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False X-Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Nov 2020 04:41:40 -0800 IronPort-SDR: 7qPFYJ6YwaxHOfwupyUyIRnpyNV3kzKRF8tiLmnoK/lV/FEd9ZXA8W4WkKAitDeCHmLtovxqlO zl5M9udwDrrw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,453,1596524400"; d="scan'208";a="527949746" X-Received: from gklab-27-32.ger.corp.intel.com ([10.102.28.45]) by fmsmga006.fm.intel.com with ESMTP; 05 Nov 2020 04:41:38 -0800 From: "Albecki, Mateusz" To: devel@edk2.groups.io Cc: Mateusz Albecki , Ray Ni , Hao A Wu Subject: [edk2-devel] [PATCH v2 2/4] MdeModulePkg/AtaAtapiPassThru: Add SATA error recovery flow Date: Thu, 5 Nov 2020 13:40:44 +0100 Message-Id: <20201105124046.3744-3-mateusz.albecki@intel.com> In-Reply-To: <20201105124046.3744-1-mateusz.albecki@intel.com> References: <20201105124046.3744-1-mateusz.albecki@intel.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,mateusz.albecki@intel.com X-Gm-Message-State: SXDeJqWx87wlGPSNJ1ZpfFE4x1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1604580100; bh=J6WVmoQB/FiD4jUVQ9OopUVQKh1jRaHDcADzBf2qVBo=; h=Cc:Date:From:Reply-To:Subject:To; b=Yk+8NAOfpI9FtgKKaW/dSkWgr4lz14X8NX99z/8dKn/UjumnUSRUEjZa9DJOFeHBCiw CRWQo6Xpka9LitzC2k48bScPsNwgPhAajC+Ff+uhgHAQWInXsgnwJvTghAlxUPrJfrVo0 7BXwGOSerD6IWArEyti04iTLSigzj4jWt/I= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This commit adds error recovery flow on SATA port when the error condition is reported. Commit only implements SATA port reset flow which is executed when PxTFD indicates BSY or DRQ. Commit does not implement HBA level reset. Signed-off-by: Mateusz Albecki Cc: Ray Ni Cc: Hao A Wu --- .../Bus/Ata/AtaAtapiPassThru/AhciMode.c | 178 +++++++++++++++--- .../Bus/Ata/AtaAtapiPassThru/AhciMode.h | 5 +- 2 files changed, 159 insertions(+), 24 deletions(-) diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c b/MdeModulePk= g/Bus/Ata/AtaAtapiPassThru/AhciMode.c index 180a60b5aa..0b7141c4f1 100644 --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c @@ -608,6 +608,148 @@ AhciBuildCommandFis ( CmdFis->AhciCFisDevHead =3D (UINT8) (AtaCommandBlock->AtaDeviceHead = | 0xE0); } =20 +/** + Wait until SATA device reports it is ready for operation. + + @param[in] PciIo Pointer to AHCI controller PciIo. + @param[in] Port SATA port index on which to reset. + + @retval EFI_SUCCESS Device ready for operation. + @retval EFI_TIMEOUT Device failed to get ready within required period. +**/ +EFI_STATUS +AhciWaitDeviceReady ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Port + ) +{ + UINT32 PhyDetectDelay; + UINT32 Data; + UINT32 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 defin= ed at ATA spec. + // + PhyDetectDelay =3D 16 * 1000; + do { + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_= AHCI_PORT_SERR; + if (AhciReadReg(PciIo, Offset) !=3D 0) { + AhciWriteReg (PciIo, Offset, AhciReadReg(PciIo, Offset)); + } + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_= AHCI_PORT_TFD; + + Data =3D AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK; + if (Data =3D=3D 0) { + break; + } + + MicroSecondDelay (1000); + PhyDetectDelay--; + } while (PhyDetectDelay > 0); + + if (PhyDetectDelay =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "Port %d Device not ready (TFD=3D0x%X)\n", Port, = Data)); + return EFI_TIMEOUT; + } else { + return EFI_SUCCESS; + } +} + + +/** + Reset the SATA port. Algorithm follows AHCI spec 1.3.1 section 10.4.2 + + @param[in] PciIo Pointer to AHCI controller PciIo. + @param[in] Port SATA port index on which to reset. + + @retval EFI_SUCCESS Port reset. + @retval Others Failed to reset the port. +**/ +EFI_STATUS +AhciResetPort ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Port + ) +{ + UINT32 Offset; + EFI_STATUS Status; + + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AH= CI_PORT_SCTL; + AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT); + // + // SW is required to keep DET set to 0x1 at least for 1 milisecond to en= sure that + // at least one COMRESET signal is sent. + // + MicroSecondDelay(1000); + AhciAndReg (PciIo, Offset, ~(UINT32)EFI_AHCI_PORT_SSTS_DET_MASK); + + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AH= CI_PORT_SSTS; + Status =3D AhciWaitMmioSet (PciIo, Offset, EFI_AHCI_PORT_SSTS_DET_MASK, = EFI_AHCI_PORT_SSTS_DET_PCE, ATA_ATAPI_TIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + return AhciWaitDeviceReady (PciIo, Port); +} + +/** + Recovers the SATA port from error condition. + This function implements algorithm described in + AHCI spec 1.3.1 section 6.2.2 + + @param[in] PciIo Pointer to AHCI controller PciIo. + @param[in] Port SATA port index on which to check. + + @retval EFI_SUCCESS Port recovered. + @retval Others Failed to recover port. +**/ +EFI_STATUS +AhciRecoverPortError ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Port + ) +{ + UINT32 Offset; + UINT32 PortInterrupt; + UINT32 PortTfd; + EFI_STATUS Status; + + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AH= CI_PORT_IS; + PortInterrupt =3D AhciReadReg (PciIo, Offset); + if ((PortInterrupt & EFI_AHCI_PORT_IS_FATAL_ERROR_MASK) =3D=3D 0) { + // + // No fatal error detected. Exit with success as port should still be = operational. + // No need to clear IS as it will be cleared when the next command sta= rts. + // + return EFI_SUCCESS; + } + + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AH= CI_PORT_CMD; + AhciAndReg (PciIo, Offset, ~(UINT32)EFI_AHCI_PORT_CMD_ST); + + Status =3D AhciWaitMmioSet (PciIo, Offset, EFI_AHCI_PORT_CMD_CR, 0, ATA_= ATAPI_TIMEOUT); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Ahci port %d is in hung state, aborting recovery= \n", Port)); + return Status; + } + + // + // If TFD.BSY or TFD.DRQ is still set it means that drive is hung and so= ftware has + // to reset it before sending any additional commands. + // + Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AH= CI_PORT_TFD; + PortTfd =3D AhciReadReg (PciIo, Offset); + if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) !=3D 0) { + Status =3D AhciResetPort (PciIo, Port); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to reset the port %d\n", Port)); + } + } + + return EFI_SUCCESS; +} + /** Checks if specified FIS has been received. =20 @@ -827,6 +969,10 @@ AhciPioTransfer ( Status =3D AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H); } =20 + if (Status =3D=3D EFI_DEVICE_ERROR) { + AhciRecoverPortError (PciIo, Port); + } + Exit: AhciStopCommand ( PciIo, @@ -1007,6 +1153,10 @@ AhciDmaTransfer ( Status =3D AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H); } =20 + if (Status =3D=3D EFI_DEVICE_ERROR) { + AhciRecoverPortError (PciIo, Port); + } + Exit: // // For Blocking mode, the command should be stopped, the Fis should be d= isabled @@ -1119,6 +1269,9 @@ AhciNonDataTransfer ( } =20 Status =3D AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H); + if (Status =3D=3D EFI_DEVICE_ERROR) { + AhciRecoverPortError (PciIo, Port); + } =20 Exit: AhciStopCommand ( @@ -2583,29 +2736,8 @@ AhciModeInitialization ( continue; } =20 - // - // 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 d= efined at ATA spec. - // - PhyDetectDelay =3D 16 * 1000; - do { - Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + = EFI_AHCI_PORT_SERR; - if (AhciReadReg(PciIo, Offset) !=3D 0) { - AhciWriteReg (PciIo, Offset, AhciReadReg(PciIo, Offset)); - } - Offset =3D EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + = EFI_AHCI_PORT_TFD; - - Data =3D AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK; - if (Data =3D=3D 0) { - break; - } - - MicroSecondDelay (1000); - PhyDetectDelay--; - } while (PhyDetectDelay > 0); - - if (PhyDetectDelay =3D=3D 0) { - DEBUG ((EFI_D_ERROR, "Port %d Device presence detected but phy not= ready (TFD=3D0x%X)\n", Port, Data)); + Status =3D AhciWaitDeviceReady (PciIo, Port); + if (EFI_ERROR (Status)) { continue; } =20 diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h b/MdeModulePk= g/Bus/Ata/AtaAtapiPassThru/AhciMode.h index 6bcff1bb7b..338447a55f 100644 --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h @@ -114,6 +114,7 @@ typedef union { #define EFI_AHCI_PORT_IS_CLEAR 0xFFFFFFFF #define EFI_AHCI_PORT_IS_FIS_CLEAR 0x0000000F #define EFI_AHCI_PORT_IS_ERROR_MASK (EFI_AHCI_PORT_IS_INFS | EF= I_AHCI_PORT_IS_IFS | EFI_AHCI_PORT_IS_HBDS | EFI_AHCI_PORT_IS_HBFS | EFI_AH= CI_PORT_IS_TFES) +#define EFI_AHCI_PORT_IS_FATAL_ERROR_MASK (EFI_AHCI_PORT_IS_IFS | EFI= _AHCI_PORT_IS_HBDS | EFI_AHCI_PORT_IS_HBFS | EFI_AHCI_PORT_IS_TFES) =20 #define EFI_AHCI_PORT_IE 0x0014 #define EFI_AHCI_PORT_CMD 0x0018 @@ -122,9 +123,11 @@ typedef union { #define EFI_AHCI_PORT_CMD_SUD BIT1 #define EFI_AHCI_PORT_CMD_POD BIT2 #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_CCS_MASK (BIT8 | BIT9 | BIT10 | BIT1= 1 | BIT12) +#define EFI_AHCI_PORT_CMD_CCS_SHIFT 8 #define EFI_AHCI_PORT_CMD_FR BIT14 +#define EFI_AHCI_PORT_CMD_CR BIT15 #define EFI_AHCI_PORT_CMD_MASK ~(EFI_AHCI_PORT_CMD_ST | EF= I_AHCI_PORT_CMD_FRE | EFI_AHCI_PORT_CMD_COL) #define EFI_AHCI_PORT_CMD_PMA BIT17 #define EFI_AHCI_PORT_CMD_HPCP BIT18 --=20 2.28.0.windows.1 --------------------------------------------------------------------- Intel Technology Poland sp. z o.o. ul. Sowackiego 173 | 80-298 Gdask | Sd Rejonowy Gdask Pnoc | VII Wydzia Gos= podarczy Krajowego Rejestru Sdowego - KRS 101882 | NIP 957-07-52-316 | Kapi= ta zakadowy 200.000 PLN. Ta wiadomo wraz z zacznikami jest przeznaczona dla okrelonego adresata i mo= e zawiera informacje poufne. W razie przypadkowego otrzymania tej wiadomoci= , prosimy o powiadomienie nadawcy oraz trwae jej usunicie; jakiekolwiek prz= egldanie lub rozpowszechnianie jest zabronione. This e-mail and any attachments may contain confidential material for the s= ole use of the intended recipient(s). If you are not the intended recipient= , please contact the sender and delete all copies; any review or distributi= on by others is strictly prohibited. =20 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#67035): https://edk2.groups.io/g/devel/message/67035 Mute This Topic: https://groups.io/mt/78049731/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-