From nobody Mon May 6 12:14:07 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zoho.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1496805446494786.04034869583; Tue, 6 Jun 2017 20:17:26 -0700 (PDT) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id EEBFA20082E6B; Tue, 6 Jun 2017 20:16:15 -0700 (PDT) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 0E4E120082E66 for ; Tue, 6 Jun 2017 20:16:15 -0700 (PDT) Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga105.jf.intel.com with ESMTP; 06 Jun 2017 20:17:22 -0700 Received: from shwdeopenpsi014.ccr.corp.intel.com ([10.239.9.13]) by orsmga004.jf.intel.com with ESMTP; 06 Jun 2017 20:17:21 -0700 X-Original-To: edk2-devel@lists.01.org X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.39,309,1493708400"; d="scan'208";a="95409518" From: Hao Wu To: edk2-devel@lists.01.org Date: Wed, 7 Jun 2017 11:17:18 +0800 Message-Id: <20170607031718.12132-1-hao.a.wu@intel.com> X-Mailer: git-send-email 2.12.0.windows.1 Subject: [edk2] [PATCH] MdeModulePkg/NvmExpressDxe: Handle timeout for blocking PassThru req X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Hao Wu , Michael Turner , Star Zeng MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" https://bugzilla.tianocore.org/show_bug.cgi?id=3D433 When a blocking NVMe PassThru request experiences timeout, the current codes in function NvmExpressPassThru() do not abort the timeout request while advancing synchronous Submission Queue tail. Therefore, it is possible to submit a new blocking PassThru request when the synchronous Submission Queue is full. The commit adds logic to abort the timeout request by resetting the NVMe controller when a timeout occurs for a blocking PassThru request. Cc: Star Zeng Cc: Michael Turner Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu Reviewed-by: Star Zeng --- .../Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c | 134 +++++++++++++++++= +++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c b/MdeM= odulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c index fb80f39ce8..c33038f0e9 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c +++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c @@ -3,7 +3,7 @@ NVM Express specification. =20 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
- Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
+ Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BS= D License which accompanies this distribution. The full text of the license may b= e found at @@ -317,6 +317,100 @@ EXIT: =20 =20 /** + Aborts the asynchronous PassThru requests. + + @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA + data structure. + + @retval EFI_SUCCESS The asynchronous PassThru requests have been a= borted. + @return EFI_DEVICE_ERROR Fail to abort all the asynchronous PassThru re= quests. + +**/ +EFI_STATUS +AbortAsyncPassThruTasks ( + IN NVME_CONTROLLER_PRIVATE_DATA *Private + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + NVME_BLKIO2_SUBTASK *Subtask; + NVME_BLKIO2_REQUEST *BlkIo2Request; + NVME_PASS_THRU_ASYNC_REQ *AsyncRequest; + EFI_BLOCK_IO2_TOKEN *Token; + EFI_TPL OldTpl; + EFI_STATUS Status; + + PciIo =3D Private->PciIo; + OldTpl =3D gBS->RaiseTPL (TPL_NOTIFY); + + // + // Cancel the unsubmitted subtasks. + // + for (Link =3D GetFirstNode (&Private->UnsubmittedSubtasks); + !IsNull (&Private->UnsubmittedSubtasks, Link); + Link =3D NextLink) { + NextLink =3D GetNextNode (&Private->UnsubmittedSubtasks, Link); + Subtask =3D NVME_BLKIO2_SUBTASK_FROM_LINK (Link); + BlkIo2Request =3D Subtask->BlockIo2Request; + Token =3D BlkIo2Request->Token; + + BlkIo2Request->UnsubmittedSubtaskNum--; + if (Subtask->IsLast) { + BlkIo2Request->LastSubtaskSubmitted =3D TRUE; + } + Token->TransactionStatus =3D EFI_ABORTED; + + RemoveEntryList (Link); + InsertTailList (&BlkIo2Request->SubtasksQueue, Link); + gBS->SignalEvent (Subtask->Event); + } + + // + // Cleanup the resources for the asynchronous PassThru requests. + // + for (Link =3D GetFirstNode (&Private->AsyncPassThruQueue); + !IsNull (&Private->AsyncPassThruQueue, Link); + Link =3D NextLink) { + NextLink =3D GetNextNode (&Private->AsyncPassThruQueue, Link); + AsyncRequest =3D NVME_PASS_THRU_ASYNC_REQ_FROM_THIS (Link); + + if (AsyncRequest->MapData !=3D NULL) { + PciIo->Unmap (PciIo, AsyncRequest->MapData); + } + if (AsyncRequest->MapMeta !=3D NULL) { + PciIo->Unmap (PciIo, AsyncRequest->MapMeta); + } + if (AsyncRequest->MapPrpList !=3D NULL) { + PciIo->Unmap (PciIo, AsyncRequest->MapPrpList); + } + if (AsyncRequest->PrpListHost !=3D NULL) { + PciIo->FreeBuffer ( + PciIo, + AsyncRequest->PrpListNo, + AsyncRequest->PrpListHost + ); + } + + RemoveEntryList (Link); + gBS->SignalEvent (AsyncRequest->CallerEvent); + FreePool (AsyncRequest); + } + + if (IsListEmpty (&Private->AsyncPassThruQueue) && + IsListEmpty (&Private->UnsubmittedSubtasks)) { + Status =3D EFI_SUCCESS; + } else { + Status =3D EFI_DEVICE_ERROR; + } + + gBS->RestoreTPL (OldTpl); + + return Status; +} + + +/** Sends an NVM Express Command Packet to an NVM Express controller or name= space. This function supports both blocking I/O and non-blocking I/O. The blocking I/O functionality i= s required, and the non-blocking I/O functionality is optional. @@ -692,6 +786,44 @@ NvmExpressPassThru ( NvmeDumpStatus(Cq); DEBUG_CODE_END(); } + } else { + // + // Timeout occurs for an NVMe command. Reset the controller to abort t= he + // outstanding commands. + // + DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: Timeout occurs for an NVMe c= ommand.\n")); + + // + // Disable the timer to trigger the process of async transfers tempora= rily. + // + Status =3D gBS->SetTimer (Private->TimerEvent, TimerCancel, 0); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + // + // Reset the NVMe controller. + // + Status =3D NvmeControllerInit (Private); + if (!EFI_ERROR (Status)) { + Status =3D AbortAsyncPassThruTasks (Private); + if (!EFI_ERROR (Status)) { + // + // Re-enable the timer to trigger the process of async transfers. + // + Status =3D gBS->SetTimer (Private->TimerEvent, TimerPeriodic, NVME= _HC_ASYNC_TIMER); + if (!EFI_ERROR (Status)) { + // + // Return EFI_TIMEOUT to indicate a timeout occurs for NVMe Pass= Thru command. + // + Status =3D EFI_TIMEOUT; + } + } + } else { + Status =3D EFI_DEVICE_ERROR; + } + + goto EXIT; } =20 if ((Private->CqHdbl[QueueId].Cqh ^=3D 1) =3D=3D 0) { --=20 2.12.0.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel