From patchwork Tue Mar 16 21:47:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 1454317 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=irrelevant.dk header.i=@irrelevant.dk header.a=rsa-sha256 header.s=fm2 header.b=riHQgwbs; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=WErqX+CJ; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F0Rx13lRkz9sRR for ; Wed, 17 Mar 2021 08:57:57 +1100 (AEDT) Received: from localhost ([::1]:52022 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMHhL-00068E-CS for incoming@patchwork.ozlabs.org; Tue, 16 Mar 2021 17:57:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60372) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXl-0006q7-GM; Tue, 16 Mar 2021 17:48:02 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:36441) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXj-0000tW-Ux; Tue, 16 Mar 2021 17:48:01 -0400 Received: from compute2.internal (compute2.nyi.internal [10.202.2.42]) by mailout.nyi.internal (Postfix) with ESMTP id 06B875C00DC; Tue, 16 Mar 2021 17:47:59 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Tue, 16 Mar 2021 17:47:59 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=iAi3qmkcqzM56 LB69+5lI6StgzEvbzX2I5PvFLGx1IM=; b=riHQgwbsTp2x2FmnEkV80+pa7Z6cG GFDV01GjTRtnj81bsUSHbiIQ/e7e/ijZLuvANZL5dCs8W20OvFBIyw39a9PBs41u 8ukPQa1yPzrHP/O5OztJydqmw7KwXkvP/TYgivznG5qk5uwdXvbkjnYX1fxDAScJ EH4GbqsOewMZdKw77zmAsF5nyIefTet3vitLAPqNrys3/0h6Xe4JkaAhW9Vxia3Z nRAcTDDKiycpE8Mm0tekQGeIs5qLpgG4p6ecHDDU4mbo9gSBzXhAKYCUmNMF2z/n AC84JoFGRFhx+yAmdTl2CfLYH7PYfYCe15pHCEzayszfIZDblotQpcVRA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=iAi3qmkcqzM56LB69+5lI6StgzEvbzX2I5PvFLGx1IM=; b=WErqX+CJ KuttYkO+zogQSavXoCG3DKBx0XnZ/+UFqhgUStsgDl1SNkUOgR1GFRFAgwRntMiz 0GJzREgFuKQV4/rq+t7H17QSje3ICD386Ba6a425ZXEg38N3kVxhPavTmtyjzj/z wKsn0Gs2/3YOBbs6qFvk7/i6BNXUzcAMhdIpcQGvxn/aUIF7OeK0pMPBsalrIwZm zrZ1Mbw6otd0P1kGBRhY9dDtbBrQ/fMYH1a9ItAcStfKwtQ57QlNJsy+W4AmzpL0 6r8a8258+lIzBcD5Y9gCxo2PQ5buwu+gTDKWJVxgsZA155qeZT33WasW4CAufVdK wwr+Eywo9y0Mlg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrudefvddgudehhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecukfhppeektddrudeijedrleekrdduledtnecuvehluhhsthgvrhfuihiivgeptd enucfrrghrrghmpehmrghilhhfrhhomhepihhtshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: from apples.local (80-167-98-190-cable.dk.customer.tdc.net [80.167.98.190]) by mail.messagingengine.com (Postfix) with ESMTPA id 1ED831080064; Tue, 16 Mar 2021 17:47:57 -0400 (EDT) From: Klaus Jensen To: Peter Maydell , qemu-devel@nongnu.org Subject: [PULL 01/11] hw/block/nvme: fix potential overflow Date: Tue, 16 Mar 2021 22:47:43 +0100 Message-Id: <20210316214753.399389-2-its@irrelevant.dk> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210316214753.399389-1-its@irrelevant.dk> References: <20210316214753.399389-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.29; envelope-from=its@irrelevant.dk; helo=out5-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Stefan Hajnoczi , Klaus Jensen Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen page_size is a uint32_t, and zasl is a uint8_t, so the expression `page_size << zasl` is done using 32-bit arithmetic and might overflow. Since we then compare this against a 64 bit data_size value, Coverity complains that we might overflow unintentionally. An MDTS/ZASL value in excess of 4GiB is probably impractical, but it is not entirely unrealistic, so add a cast such that we handle that case properly. Fixes: 578d914b263c ("hw/block/nvme: align zoned.zasl with mdts") Fixes: CID 1450756 Signed-off-by: Klaus Jensen --- hw/block/nvme.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index d439e44db839..0d9b980151ae 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -2188,7 +2188,8 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, goto invalid; } - if (n->params.zasl && data_size > n->page_size << n->params.zasl) { + if (n->params.zasl && + data_size > (uint64_t)n->page_size << n->params.zasl) { trace_pci_nvme_err_zasl(data_size); return NVME_INVALID_FIELD | NVME_DNR; } From patchwork Tue Mar 16 21:47:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 1454311 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=irrelevant.dk header.i=@irrelevant.dk header.a=rsa-sha256 header.s=fm2 header.b=3DDHjzc9; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=YYkMEPBz; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F0RmW1v7qz9sRR for ; Wed, 17 Mar 2021 08:50:35 +1100 (AEDT) Received: from localhost ([::1]:36960 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMHaD-00081X-6e for incoming@patchwork.ozlabs.org; Tue, 16 Mar 2021 17:50:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60384) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXm-0006qo-RZ; Tue, 16 Mar 2021 17:48:02 -0400 Received: from new1-smtp.messagingengine.com ([66.111.4.221]:58527) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXl-0000tf-0s; Tue, 16 Mar 2021 17:48:02 -0400 Received: from compute2.internal (compute2.nyi.internal [10.202.2.42]) by mailnew.nyi.internal (Postfix) with ESMTP id 3303D580A4C; Tue, 16 Mar 2021 17:48:00 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Tue, 16 Mar 2021 17:48:00 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s=fm2; bh= UWWgnQyChWBaw1mvtIyB0g1GBGLDjeCNtfB6wtj9s7Y=; b=3DDHjzc9rYZmxemg VUUCA11YJW81DFmuWqvs01JUtjpKglEyfUIWkR0oaiO2tOPHvmleFd2/8JhLnPsh DxxURVRpX44gF3alsOyL8hSGf2YljqXBdyzHues4o7J2xVvSWuWtlxQK2KWToot7 F7MnChHo9gaqG7i9sggAetfgr95Z1jVFxxZwh9IYZ27zeAr9sDtBTZJ4X01wt788 A1NnXMds/Vt/SHtw1xYCGQ4qDaDw8EskNYL39Wn4TA+WdgR6ZJ7O4ckUZVN5Ua1L f/C9jTgOAmoDwjPu7SXifL/rqoFcq005TbbPLTJSQWRhzcpaVq/6tHhNUJULYW8L uLZEXA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm2; bh=UWWgnQyChWBaw1mvtIyB0g1GBGLDjeCNtfB6wtj9s 7Y=; b=YYkMEPBzp3RVTOJam9RZA9HszD/y1dDG2hwUjS+qXVm/trmF3eFpvx0/X sYyJPchE+s8vBmLSBKmKD/jKcgZmW6pIL97/1RtY00RlJKzwsorBpG0uY1W2ykqx efQW7wruH2/qha7e+O4yZxIStTh6KDZq7pRs/haQ5HFL0dPdpmzONNXh+ezYyOps gvbLvF00XXM50CX4q1o68ijiRnt0gdOjKa5zjsqPyxxScso9s6GMVJlLLfJVpiL4 0lwUJMU2R+BVayVx6PLGlC5L4oi3fxtxx0GAajpVKMKVy4R1encTHtRFqL8QzKuy qqowAqCDfOS3kqrPzQMUipcld4Buw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrudefvddgudehhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpefmlhgr uhhsucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrg htthgvrhhnpeetveeuudegveeiheegieelueeftedvtdekteefleegheduhfejueelvdfh ffdtgeenucfkphepkedtrdduieejrdelkedrudeltdenucevlhhushhtvghrufhiiigvpe dtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirhhrvghlvghvrghnthdrughk X-ME-Proxy: Received: from apples.local (80-167-98-190-cable.dk.customer.tdc.net [80.167.98.190]) by mail.messagingengine.com (Postfix) with ESMTPA id 94BEE108005C; Tue, 16 Mar 2021 17:47:58 -0400 (EDT) From: Klaus Jensen To: Peter Maydell , qemu-devel@nongnu.org Subject: [PULL 02/11] hw/block/nvme: assert namespaces array indices Date: Tue, 16 Mar 2021 22:47:44 +0100 Message-Id: <20210316214753.399389-3-its@irrelevant.dk> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210316214753.399389-1-its@irrelevant.dk> References: <20210316214753.399389-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.221; envelope-from=its@irrelevant.dk; helo=new1-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Minwoo Im , Stefan Hajnoczi , Klaus Jensen , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Coverity complains about a possible memory corruption in the nvme_ns_attach and _detach functions. While we should not (famous last words) be able to reach this function without nsid having previously been validated, this is still an open door for future misuse. Make Coverity and maintainers happy by asserting that the index into the array is valid. Also, while not detected by Coverity (yet), add an assert in nvme_subsys_ns and nvme_subsys_register_ns as well since a similar issue is exists there. Fixes: 037953b5b299 ("hw/block/nvme: support namespace detach") Fixes: CID 1450757 Fixes: CID 1450758 Cc: Minwoo Im Signed-off-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé --- hw/block/nvme-subsys.h | 2 ++ hw/block/nvme.h | 10 ++++++++-- hw/block/nvme-subsys.c | 7 +++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/hw/block/nvme-subsys.h b/hw/block/nvme-subsys.h index fb66ae752ad5..aafa04b84829 100644 --- a/hw/block/nvme-subsys.h +++ b/hw/block/nvme-subsys.h @@ -54,6 +54,8 @@ static inline NvmeNamespace *nvme_subsys_ns(NvmeSubsystem *subsys, return NULL; } + assert(nsid && nsid <= NVME_SUBSYS_MAX_NAMESPACES); + return subsys->namespaces[nsid]; } diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 4955d649c7d4..5ba2efaedfd2 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -236,12 +236,18 @@ static inline bool nvme_ns_is_attached(NvmeCtrl *n, NvmeNamespace *ns) static inline void nvme_ns_attach(NvmeCtrl *n, NvmeNamespace *ns) { - n->namespaces[nvme_nsid(ns) - 1] = ns; + uint32_t nsid = nvme_nsid(ns); + assert(nsid && nsid <= NVME_MAX_NAMESPACES); + + n->namespaces[nsid - 1] = ns; } static inline void nvme_ns_detach(NvmeCtrl *n, NvmeNamespace *ns) { - n->namespaces[nvme_nsid(ns) - 1] = NULL; + uint32_t nsid = nvme_nsid(ns); + assert(nsid && nsid <= NVME_MAX_NAMESPACES); + + n->namespaces[nsid - 1] = NULL; } static inline NvmeCQueue *nvme_cq(NvmeRequest *req) diff --git a/hw/block/nvme-subsys.c b/hw/block/nvme-subsys.c index af4804a819ee..9fadef8cec99 100644 --- a/hw/block/nvme-subsys.c +++ b/hw/block/nvme-subsys.c @@ -47,15 +47,18 @@ int nvme_subsys_register_ns(NvmeNamespace *ns, Error **errp) { NvmeSubsystem *subsys = ns->subsys; NvmeCtrl *n; + uint32_t nsid = nvme_nsid(ns); int i; - if (subsys->namespaces[nvme_nsid(ns)]) { + assert(nsid && nsid <= NVME_SUBSYS_MAX_NAMESPACES); + + if (subsys->namespaces[nsid]) { error_setg(errp, "namespace %d already registerd to subsy %s", nvme_nsid(ns), subsys->parent_obj.id); return -1; } - subsys->namespaces[nvme_nsid(ns)] = ns; + subsys->namespaces[nsid] = ns; for (i = 0; i < ARRAY_SIZE(subsys->ctrls); i++) { n = subsys->ctrls[i]; From patchwork Tue Mar 16 21:47:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 1454316 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=irrelevant.dk header.i=@irrelevant.dk header.a=rsa-sha256 header.s=fm2 header.b=T/er1Uk1; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=kqGQ2btC; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F0Rtz603cz9sRR for ; Wed, 17 Mar 2021 08:56:11 +1100 (AEDT) Received: from localhost ([::1]:49094 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMHfd-0004rS-OC for incoming@patchwork.ozlabs.org; Tue, 16 Mar 2021 17:56:09 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60400) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXo-0006s1-Ac; Tue, 16 Mar 2021 17:48:04 -0400 Received: from new1-smtp.messagingengine.com ([66.111.4.221]:57931) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXm-0000vE-Pr; Tue, 16 Mar 2021 17:48:04 -0400 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailnew.nyi.internal (Postfix) with ESMTP id DFA3D580A76; Tue, 16 Mar 2021 17:48:01 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Tue, 16 Mar 2021 17:48:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=aQ/+o2Jwoa4rt CJsgP6cUiDm6q/wU6aNweqx4+nber4=; b=T/er1Uk1tDwIjolXJdO7AYGyGNgP3 6nxlxnsJO9CN+Ba7HN99Fq6Ecso5yXPxSLasB7UcGYbvAOdebNYsIOuKlSq3zn9K wG7Anh4kEkSRxfxlqxR73l8i5fSPuxC1dSoLtk2qf1bciPKHzHkqtouOkNQxbIo+ 0+1ufwK17RRqL+ysRYfTqF0PqMySt2WPEP1b+EcBezL1upina18gqhXNperDAmM1 ctzB+zH10cuK7plSeSLv/lSrRUwDngtaN4hg5tj2gm+oukbAUH37OY/fEQqWxvoW 3FclxBod9U2tVnXcbHaXwKTUI/kdeSIqSFCXHrKTlP0HdpPZRqZyHZEpQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=aQ/+o2Jwoa4rtCJsgP6cUiDm6q/wU6aNweqx4+nber4=; b=kqGQ2btC SVNiH24IMwiZUB7Pi5PJllKlpLz3iQ7/Eii3e+Sfl775Y0kS6hdcpSkfFvJFAxC3 +sODFS+48gOELxbH12xt17+nRvPvG8bzjVHnHLeV/e1k2+ynQFNFnCjdt6RtuYmz F9Ln+9pQ+OQDjWUzGRdZMNvggOzWrquXi4pr9gIvjT1h4MHP8MeFhn7jm4NAvdXL WUzmT0WVWi+Hbrk0xrkxkWxQx8EVVGDWkjA37GC0AwNeScMT+zHhXKs+EOUO4GIO Hp2YLi+Htk6hKgCLfi0gDsR6Ju5y/QAtAvti50xcLs3JSXSnM05UM3v45rIHsBWP wfVi5XZgqqwN4g== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrudefvddgudehhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecukfhppeektddrudeijedrleekrdduledtnecuvehluhhsthgvrhfuihiivgeptd enucfrrghrrghmpehmrghilhhfrhhomhepihhtshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: from apples.local (80-167-98-190-cable.dk.customer.tdc.net [80.167.98.190]) by mail.messagingengine.com (Postfix) with ESMTPA id 4A90F108005C; Tue, 16 Mar 2021 17:48:00 -0400 (EDT) From: Klaus Jensen To: Peter Maydell , qemu-devel@nongnu.org Subject: [PULL 03/11] hw/block/nvme: fix zone management receive reporting too many zones Date: Tue, 16 Mar 2021 22:47:45 +0100 Message-Id: <20210316214753.399389-4-its@irrelevant.dk> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210316214753.399389-1-its@irrelevant.dk> References: <20210316214753.399389-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.221; envelope-from=its@irrelevant.dk; helo=new1-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Dmitry Fomichev , Klaus Jensen , Max Reitz , Keith Busch , Stefan Hajnoczi , Klaus Jensen Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen nvme_zone_mgmt_recv uses nvme_ns_nlbas() to get the number of LBAs in the namespace and then calculates the number of zones to report by incrementing slba with ZSZE until exceeding the number of LBAs as returned by nvme_ns_nlbas(). This is bad because the namespace might be of such as size that some LBAs are valid, but are not part of any zone, causing zone management receive to report one additional (but non-existing) zone. Fix this with a conventional loop on i < ns->num_zones instead. Fixes: a479335bfaf3 ("hw/block/nvme: Support Zoned Namespace Command Set") Cc: Dmitry Fomichev Signed-off-by: Klaus Jensen --- hw/block/nvme.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 0d9b980151ae..9a14c5f7035e 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -2620,12 +2620,13 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req) uint32_t zone_idx, zra, zrasf, partial; uint64_t max_zones, nr_zones = 0; uint16_t status; - uint64_t slba, capacity = nvme_ns_nlbas(ns); + uint64_t slba; NvmeZoneDescr *z; NvmeZone *zone; NvmeZoneReportHeader *header; void *buf, *buf_p; size_t zone_entry_sz; + int i; req->status = NVME_SUCCESS; @@ -2667,7 +2668,7 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req) buf = g_malloc0(data_size); zone = &ns->zone_array[zone_idx]; - for (; slba < capacity; slba += ns->zone_size) { + for (i = zone_idx; i < ns->num_zones; i++) { if (partial && nr_zones >= max_zones) { break; } From patchwork Tue Mar 16 21:47:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 1454320 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=irrelevant.dk header.i=@irrelevant.dk header.a=rsa-sha256 header.s=fm2 header.b=goDu6Z7X; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=ei2oWCjp; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F0S4267ffz9sRR for ; Wed, 17 Mar 2021 09:04:02 +1100 (AEDT) Received: from localhost ([::1]:60258 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMHnE-00021P-NQ for incoming@patchwork.ozlabs.org; Tue, 16 Mar 2021 18:04:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60434) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXt-0006xY-2O; Tue, 16 Mar 2021 17:48:09 -0400 Received: from new1-smtp.messagingengine.com ([66.111.4.221]:47877) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXp-0000wo-Bf; Tue, 16 Mar 2021 17:48:08 -0400 Received: from compute6.internal (compute6.nyi.internal [10.202.2.46]) by mailnew.nyi.internal (Postfix) with ESMTP id 8B09E580A7B; Tue, 16 Mar 2021 17:48:04 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute6.internal (MEProxy); Tue, 16 Mar 2021 17:48:04 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=JJP+0ALvDpT9Q NJblrhSttnVX2fPxLRVr57+T/XeMEY=; b=goDu6Z7XuNu7KgIlnJLkyPQ42bmnv ydEffXyZPwISbFDSLILqiE7WLYAWIJjhljCoHmrGiLFhr5gH6qLTMdMzH7fD4L8y OdwTTT32Ja1Mn3YDoB5Nc8Z7caGzZxrFyo5Kvb48MwjicfYLI2ThIg0blNKeBiz1 IHnfyeXEmbDoyNsOPsS1eh4B42C3AdM5QpveDM3E44q9Itvt8gQVYtaNXkFdq/Ec niJzOiwRRtWFeWPXG+k8bXiR4tuyWBXFaZyi9XXofKCcbobuvTy+JXHBWkHZMyxW oE7Tb9K0OyLWkDeKl0K14opyvSGjFPCqQ3YsiHoS4s4J+9viq9dgXL+fA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=JJP+0ALvDpT9QNJblrhSttnVX2fPxLRVr57+T/XeMEY=; b=ei2oWCjp qevYePK4eN06Y+vrzGwQ8YKyKhGVCO5B4t/y8uy9TMLCvX+FaBH+dTH4Nma7EEry gHhJrkQJXyiXwG8ZlcuUCUwlY6Iz5FiyZc+BubeJRkb9o8QvbjC6HXLcHY3tqzKe ZQNiTi7nTaNf/lepTi2c3zdXkHvNoSvyUpi6nQJrhH3b21MJ8moovDDvAy8f5vml PHFnA2RU7K9AgHtXQm4LPFn9VSGkwudWiOvLcTTURX/Wp7Zs5njGWiUxSP5fmh14 Vj/lq5qoYRjs16Kp07T89DFxLgYXPN8odYs8zgaFe9l2lB5bIewFQ6d10DPvCDiG MnHZ2f9C8I3ZnA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrudefvddgudehhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecukfhppeektddrudeijedrleekrdduledtnecuvehluhhsthgvrhfuihiivgeptd enucfrrghrrghmpehmrghilhhfrhhomhepihhtshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: from apples.local (80-167-98-190-cable.dk.customer.tdc.net [80.167.98.190]) by mail.messagingengine.com (Postfix) with ESMTPA id E17981080068; Tue, 16 Mar 2021 17:48:01 -0400 (EDT) From: Klaus Jensen To: Peter Maydell , qemu-devel@nongnu.org Subject: [PULL 04/11] hw/block/nvme: add metadata support Date: Tue, 16 Mar 2021 22:47:46 +0100 Message-Id: <20210316214753.399389-5-its@irrelevant.dk> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210316214753.399389-1-its@irrelevant.dk> References: <20210316214753.399389-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.221; envelope-from=its@irrelevant.dk; helo=new1-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Klaus Jensen , Gollu Appalanaidu , Max Reitz , Keith Busch , Stefan Hajnoczi , Klaus Jensen Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Add support for metadata in the form of extended logical blocks as well as a separate buffer of data. The new `ms` nvme-ns device parameter specifies the size of metadata per logical block in bytes. The `mset` nvme-ns device parameter controls whether metadata is transfered as part of an extended lba (set to '1') or in a separate buffer (set to '0', the default). Regardsless of the scheme chosen with `mset`, metadata is stored at the end of the namespace backing block device. This requires the user provided PRP/SGLs to be walked and "split" into data and metadata scatter/gather lists if the extended logical block scheme is used, but has the advantage of not breaking the deallocated blocks support. Co-authored-by: Gollu Appalanaidu Signed-off-by: Gollu Appalanaidu Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme-ns.h | 39 ++- hw/block/nvme-ns.c | 20 +- hw/block/nvme.c | 661 ++++++++++++++++++++++++++++++++++++------ hw/block/trace-events | 5 +- 4 files changed, 632 insertions(+), 93 deletions(-) diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index 318d3aebe1a8..983df95265b9 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -30,6 +30,9 @@ typedef struct NvmeNamespaceParams { uint32_t nsid; QemuUUID uuid; + uint16_t ms; + uint8_t mset; + uint16_t mssrl; uint32_t mcl; uint8_t msrc; @@ -48,6 +51,7 @@ typedef struct NvmeNamespace { BlockConf blkconf; int32_t bootindex; int64_t size; + int64_t mdata_offset; NvmeIdNs id_ns; const uint32_t *iocs; uint8_t csi; @@ -101,18 +105,41 @@ static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns) return nvme_ns_lbaf(ns)->ds; } -/* calculate the number of LBAs that the namespace can accomodate */ -static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns) -{ - return ns->size >> nvme_ns_lbads(ns); -} - /* convert an LBA to the equivalent in bytes */ static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba) { return lba << nvme_ns_lbads(ns); } +static inline size_t nvme_lsize(NvmeNamespace *ns) +{ + return 1 << nvme_ns_lbads(ns); +} + +static inline uint16_t nvme_msize(NvmeNamespace *ns) +{ + return nvme_ns_lbaf(ns)->ms; +} + +static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba) +{ + return nvme_msize(ns) * lba; +} + +static inline bool nvme_ns_ext(NvmeNamespace *ns) +{ + return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas); +} + +/* calculate the number of LBAs that the namespace can accomodate */ +static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns) +{ + if (ns->params.ms) { + return ns->size / (nvme_lsize(ns) + nvme_msize(ns)); + } + return ns->size >> nvme_ns_lbads(ns); +} + typedef struct NvmeCtrl NvmeCtrl; static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone) diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index eda6a0c003a4..2e6bffc8e64d 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -37,13 +37,25 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp) BlockDriverInfo bdi; NvmeIdNs *id_ns = &ns->id_ns; int lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas); - int npdg; + int npdg, nlbas; ns->id_ns.dlfeat = 0x9; id_ns->lbaf[lba_index].ds = 31 - clz32(ns->blkconf.logical_block_size); + id_ns->lbaf[lba_index].ms = ns->params.ms; - id_ns->nsze = cpu_to_le64(nvme_ns_nlbas(ns)); + if (ns->params.ms) { + id_ns->mc = 0x3; + + if (ns->params.mset) { + id_ns->flbas |= 0x10; + } + } + + nlbas = nvme_ns_nlbas(ns); + + id_ns->nsze = cpu_to_le64(nlbas); + ns->mdata_offset = nvme_l2b(ns, nlbas); ns->csi = NVME_CSI_NVM; @@ -140,7 +152,7 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp) */ ns->zone_size = zone_size / lbasz; ns->zone_capacity = zone_cap / lbasz; - ns->num_zones = ns->size / lbasz / ns->zone_size; + ns->num_zones = nvme_ns_nlbas(ns) / ns->zone_size; /* Do a few more sanity checks of ZNS properties */ if (!ns->num_zones) { @@ -402,6 +414,8 @@ static Property nvme_ns_props[] = { DEFINE_PROP_BOOL("detached", NvmeNamespace, params.detached, false), DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0), DEFINE_PROP_UUID("uuid", NvmeNamespace, params.uuid), + DEFINE_PROP_UINT16("ms", NvmeNamespace, params.ms, 0), + DEFINE_PROP_UINT8("mset", NvmeNamespace, params.mset, 0), DEFINE_PROP_UINT16("mssrl", NvmeNamespace, params.mssrl, 128), DEFINE_PROP_UINT32("mcl", NvmeNamespace, params.mcl, 128), DEFINE_PROP_UINT8("msrc", NvmeNamespace, params.msrc, 127), diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 9a14c5f7035e..2c4757ae46a7 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -360,6 +360,26 @@ static int nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) return pci_dma_read(&n->parent_obj, addr, buf, size); } +static int nvme_addr_write(NvmeCtrl *n, hwaddr addr, void *buf, int size) +{ + hwaddr hi = addr + size - 1; + if (hi < addr) { + return 1; + } + + if (n->bar.cmbsz && nvme_addr_is_cmb(n, addr) && nvme_addr_is_cmb(n, hi)) { + memcpy(nvme_addr_to_cmb(n, addr), buf, size); + return 0; + } + + if (nvme_addr_is_pmr(n, addr) && nvme_addr_is_pmr(n, hi)) { + memcpy(nvme_addr_to_pmr(n, addr), buf, size); + return 0; + } + + return pci_dma_write(&n->parent_obj, addr, buf, size); +} + static bool nvme_nsid_valid(NvmeCtrl *n, uint32_t nsid) { return nsid && (nsid == NVME_NSID_BROADCAST || nsid <= n->num_namespaces); @@ -476,6 +496,59 @@ static inline void nvme_sg_unmap(NvmeSg *sg) memset(sg, 0x0, sizeof(*sg)); } +/* + * When metadata is transfered as extended LBAs, the DPTR mapped into `sg` + * holds both data and metadata. This function splits the data and metadata + * into two separate QSG/IOVs. + */ +static void nvme_sg_split(NvmeSg *sg, NvmeNamespace *ns, NvmeSg *data, + NvmeSg *mdata) +{ + NvmeSg *dst = data; + size_t size = nvme_lsize(ns); + size_t msize = nvme_msize(ns); + uint32_t trans_len, count = size; + uint64_t offset = 0; + bool dma = sg->flags & NVME_SG_DMA; + size_t sge_len; + size_t sg_len = dma ? sg->qsg.size : sg->iov.size; + int sg_idx = 0; + + assert(sg->flags & NVME_SG_ALLOC); + + while (sg_len) { + sge_len = dma ? sg->qsg.sg[sg_idx].len : sg->iov.iov[sg_idx].iov_len; + + trans_len = MIN(sg_len, count); + trans_len = MIN(trans_len, sge_len - offset); + + if (dst) { + if (dma) { + qemu_sglist_add(&dst->qsg, sg->qsg.sg[sg_idx].base + offset, + trans_len); + } else { + qemu_iovec_add(&dst->iov, + sg->iov.iov[sg_idx].iov_base + offset, + trans_len); + } + } + + sg_len -= trans_len; + count -= trans_len; + offset += trans_len; + + if (count == 0) { + dst = (dst == data) ? mdata : data; + count = (dst == data) ? size : msize; + } + + if (sge_len == offset) { + offset = 0; + sg_idx++; + } + } +} + static uint16_t nvme_map_addr_cmb(NvmeCtrl *n, QEMUIOVector *iov, hwaddr addr, size_t len) { @@ -879,11 +952,156 @@ static uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len, } } +static uint16_t nvme_map_mptr(NvmeCtrl *n, NvmeSg *sg, size_t len, + NvmeCmd *cmd) +{ + int psdt = NVME_CMD_FLAGS_PSDT(cmd->flags); + hwaddr mptr = le64_to_cpu(cmd->mptr); + uint16_t status; + + if (psdt == NVME_PSDT_SGL_MPTR_SGL) { + NvmeSglDescriptor sgl; + + if (nvme_addr_read(n, mptr, &sgl, sizeof(sgl))) { + return NVME_DATA_TRAS_ERROR; + } + + status = nvme_map_sgl(n, sg, sgl, len, cmd); + if (status && (status & 0x7ff) == NVME_DATA_SGL_LEN_INVALID) { + status = NVME_MD_SGL_LEN_INVALID | NVME_DNR; + } + + return status; + } + + nvme_sg_init(n, sg, nvme_addr_is_dma(n, mptr)); + status = nvme_map_addr(n, sg, mptr, len); + if (status) { + nvme_sg_unmap(sg); + } + + return status; +} + +static uint16_t nvme_map_data(NvmeCtrl *n, uint32_t nlb, NvmeRequest *req) +{ + NvmeNamespace *ns = req->ns; + size_t len = nvme_l2b(ns, nlb); + uint16_t status; + + if (nvme_ns_ext(ns)) { + NvmeSg sg; + + len += nvme_m2b(ns, nlb); + + status = nvme_map_dptr(n, &sg, len, &req->cmd); + if (status) { + return status; + } + + nvme_sg_init(n, &req->sg, sg.flags & NVME_SG_DMA); + nvme_sg_split(&sg, ns, &req->sg, NULL); + nvme_sg_unmap(&sg); + + return NVME_SUCCESS; + } + + return nvme_map_dptr(n, &req->sg, len, &req->cmd); +} + +static uint16_t nvme_map_mdata(NvmeCtrl *n, uint32_t nlb, NvmeRequest *req) +{ + NvmeNamespace *ns = req->ns; + size_t len = nvme_m2b(ns, nlb); + uint16_t status; + + if (nvme_ns_ext(ns)) { + NvmeSg sg; + + len += nvme_l2b(ns, nlb); + + status = nvme_map_dptr(n, &sg, len, &req->cmd); + if (status) { + return status; + } + + nvme_sg_init(n, &req->sg, sg.flags & NVME_SG_DMA); + nvme_sg_split(&sg, ns, NULL, &req->sg); + nvme_sg_unmap(&sg); + + return NVME_SUCCESS; + } + + return nvme_map_mptr(n, &req->sg, len, &req->cmd); +} + typedef enum NvmeTxDirection { NVME_TX_DIRECTION_TO_DEVICE = 0, NVME_TX_DIRECTION_FROM_DEVICE = 1, } NvmeTxDirection; +static uint16_t nvme_tx_interleaved(NvmeCtrl *n, NvmeSg *sg, uint8_t *ptr, + uint32_t len, uint32_t bytes, + int32_t skip_bytes, int64_t offset, + NvmeTxDirection dir) +{ + hwaddr addr; + uint32_t trans_len, count = bytes; + bool dma = sg->flags & NVME_SG_DMA; + int64_t sge_len; + int sg_idx = 0; + int ret; + + assert(sg->flags & NVME_SG_ALLOC); + + while (len) { + sge_len = dma ? sg->qsg.sg[sg_idx].len : sg->iov.iov[sg_idx].iov_len; + + if (sge_len - offset < 0) { + offset -= sge_len; + sg_idx++; + continue; + } + + if (sge_len == offset) { + offset = 0; + sg_idx++; + continue; + } + + trans_len = MIN(len, count); + trans_len = MIN(trans_len, sge_len - offset); + + if (dma) { + addr = sg->qsg.sg[sg_idx].base + offset; + } else { + addr = (hwaddr)(uintptr_t)sg->iov.iov[sg_idx].iov_base + offset; + } + + if (dir == NVME_TX_DIRECTION_TO_DEVICE) { + ret = nvme_addr_read(n, addr, ptr, trans_len); + } else { + ret = nvme_addr_write(n, addr, ptr, trans_len); + } + + if (ret) { + return NVME_DATA_TRAS_ERROR; + } + + ptr += trans_len; + len -= trans_len; + count -= trans_len; + offset += trans_len; + + if (count == 0) { + count = bytes; + offset += skip_bytes; + } + } + + return NVME_SUCCESS; +} + static uint16_t nvme_tx(NvmeCtrl *n, NvmeSg *sg, uint8_t *ptr, uint32_t len, NvmeTxDirection dir) { @@ -946,6 +1164,46 @@ static inline uint16_t nvme_h2c(NvmeCtrl *n, uint8_t *ptr, uint32_t len, return nvme_tx(n, &req->sg, ptr, len, NVME_TX_DIRECTION_TO_DEVICE); } +static uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + NvmeTxDirection dir, NvmeRequest *req) +{ + NvmeNamespace *ns = req->ns; + + if (nvme_ns_ext(ns)) { + size_t lsize = nvme_lsize(ns); + size_t msize = nvme_msize(ns); + + return nvme_tx_interleaved(n, &req->sg, ptr, len, lsize, msize, 0, + dir); + } + + return nvme_tx(n, &req->sg, ptr, len, dir); +} + +static uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + NvmeTxDirection dir, NvmeRequest *req) +{ + NvmeNamespace *ns = req->ns; + uint16_t status; + + if (nvme_ns_ext(ns)) { + size_t lsize = nvme_lsize(ns); + size_t msize = nvme_msize(ns); + + return nvme_tx_interleaved(n, &req->sg, ptr, len, msize, lsize, lsize, + dir); + } + + nvme_sg_unmap(&req->sg); + + status = nvme_map_mptr(n, &req->sg, len, &req->cmd); + if (status) { + return status; + } + + return nvme_tx(n, &req->sg, ptr, len, dir); +} + static inline void nvme_blk_read(BlockBackend *blk, int64_t offset, BlockCompletionFunc *cb, NvmeRequest *req) { @@ -1498,7 +1756,7 @@ static inline bool nvme_is_write(NvmeRequest *req) rw->opcode == NVME_CMD_WRITE_ZEROES; } -static void nvme_rw_cb(void *opaque, int ret) +static void nvme_misc_cb(void *opaque, int ret) { NvmeRequest *req = opaque; NvmeNamespace *ns = req->ns; @@ -1507,20 +1765,90 @@ static void nvme_rw_cb(void *opaque, int ret) BlockAcctCookie *acct = &req->acct; BlockAcctStats *stats = blk_get_stats(blk); - trace_pci_nvme_rw_cb(nvme_cid(req), blk_name(blk)); + trace_pci_nvme_misc_cb(nvme_cid(req), blk_name(blk)); + + if (ret) { + block_acct_failed(stats, acct); + nvme_aio_err(req, ret); + } else { + block_acct_done(stats, acct); + } + + nvme_enqueue_req_completion(nvme_cq(req), req); +} + +static void nvme_rw_complete_cb(void *opaque, int ret) +{ + NvmeRequest *req = opaque; + NvmeNamespace *ns = req->ns; + BlockBackend *blk = ns->blkconf.blk; + BlockAcctCookie *acct = &req->acct; + BlockAcctStats *stats = blk_get_stats(blk); + + trace_pci_nvme_rw_complete_cb(nvme_cid(req), blk_name(blk)); + + if (ret) { + block_acct_failed(stats, acct); + nvme_aio_err(req, ret); + } else { + block_acct_done(stats, acct); + } if (ns->params.zoned && nvme_is_write(req)) { nvme_finalize_zoned_write(ns, req); } - if (!ret) { - block_acct_done(stats, acct); - } else { - block_acct_failed(stats, acct); - nvme_aio_err(req, ret); + nvme_enqueue_req_completion(nvme_cq(req), req); +} + +static void nvme_rw_cb(void *opaque, int ret) +{ + NvmeRequest *req = opaque; + NvmeNamespace *ns = req->ns; + + BlockBackend *blk = ns->blkconf.blk; + + trace_pci_nvme_rw_cb(nvme_cid(req), blk_name(blk)); + + if (ret) { + goto out; } - nvme_enqueue_req_completion(nvme_cq(req), req); + if (nvme_msize(ns)) { + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + uint64_t slba = le64_to_cpu(rw->slba); + uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; + uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + + if (req->cmd.opcode == NVME_CMD_WRITE_ZEROES) { + size_t mlen = nvme_m2b(ns, nlb); + + req->aiocb = blk_aio_pwrite_zeroes(blk, offset, mlen, + BDRV_REQ_MAY_UNMAP, + nvme_rw_complete_cb, req); + return; + } + + if (nvme_ns_ext(ns) || req->cmd.mptr) { + uint16_t status; + + nvme_sg_unmap(&req->sg); + status = nvme_map_mdata(nvme_ctrl(req), nlb, req); + if (status) { + ret = -EFAULT; + goto out; + } + + if (req->cmd.opcode == NVME_CMD_READ) { + return nvme_blk_read(blk, offset, nvme_rw_complete_cb, req); + } + + return nvme_blk_write(blk, offset, nvme_rw_complete_cb, req); + } + } + +out: + nvme_rw_complete_cb(req, ret); } struct nvme_aio_flush_ctx { @@ -1583,7 +1911,7 @@ struct nvme_zone_reset_ctx { NvmeZone *zone; }; -static void nvme_aio_zone_reset_cb(void *opaque, int ret) +static void nvme_aio_zone_reset_complete_cb(void *opaque, int ret) { struct nvme_zone_reset_ctx *ctx = opaque; NvmeRequest *req = ctx->req; @@ -1591,31 +1919,31 @@ static void nvme_aio_zone_reset_cb(void *opaque, int ret) NvmeZone *zone = ctx->zone; uintptr_t *resets = (uintptr_t *)&req->opaque; - g_free(ctx); - - trace_pci_nvme_aio_zone_reset_cb(nvme_cid(req), zone->d.zslba); - - if (!ret) { - switch (nvme_get_zone_state(zone)) { - case NVME_ZONE_STATE_EXPLICITLY_OPEN: - case NVME_ZONE_STATE_IMPLICITLY_OPEN: - nvme_aor_dec_open(ns); - /* fall through */ - case NVME_ZONE_STATE_CLOSED: - nvme_aor_dec_active(ns); - /* fall through */ - case NVME_ZONE_STATE_FULL: - zone->w_ptr = zone->d.zslba; - zone->d.wp = zone->w_ptr; - nvme_assign_zone_state(ns, zone, NVME_ZONE_STATE_EMPTY); - /* fall through */ - default: - break; - } - } else { + if (ret) { nvme_aio_err(req, ret); + goto out; } + switch (nvme_get_zone_state(zone)) { + case NVME_ZONE_STATE_EXPLICITLY_OPEN: + case NVME_ZONE_STATE_IMPLICITLY_OPEN: + nvme_aor_dec_open(ns); + /* fall through */ + case NVME_ZONE_STATE_CLOSED: + nvme_aor_dec_active(ns); + /* fall through */ + case NVME_ZONE_STATE_FULL: + zone->w_ptr = zone->d.zslba; + zone->d.wp = zone->w_ptr; + nvme_assign_zone_state(ns, zone, NVME_ZONE_STATE_EMPTY); + /* fall through */ + default: + break; + } + +out: + g_free(ctx); + (*resets)--; if (*resets) { @@ -1625,9 +1953,36 @@ static void nvme_aio_zone_reset_cb(void *opaque, int ret) nvme_enqueue_req_completion(nvme_cq(req), req); } +static void nvme_aio_zone_reset_cb(void *opaque, int ret) +{ + struct nvme_zone_reset_ctx *ctx = opaque; + NvmeRequest *req = ctx->req; + NvmeNamespace *ns = req->ns; + NvmeZone *zone = ctx->zone; + + trace_pci_nvme_aio_zone_reset_cb(nvme_cid(req), zone->d.zslba); + + if (ret) { + goto out; + } + + if (nvme_msize(ns)) { + int64_t offset = ns->mdata_offset + nvme_m2b(ns, zone->d.zslba); + + blk_aio_pwrite_zeroes(ns->blkconf.blk, offset, + nvme_m2b(ns, ns->zone_size), BDRV_REQ_MAY_UNMAP, + nvme_aio_zone_reset_complete_cb, ctx); + return; + } + +out: + nvme_aio_zone_reset_complete_cb(opaque, ret); +} + struct nvme_copy_ctx { int copies; uint8_t *bounce; + uint8_t *mbounce; uint32_t nlb; }; @@ -1636,6 +1991,36 @@ struct nvme_copy_in_ctx { QEMUIOVector iov; }; +static void nvme_copy_complete_cb(void *opaque, int ret) +{ + NvmeRequest *req = opaque; + NvmeNamespace *ns = req->ns; + struct nvme_copy_ctx *ctx = req->opaque; + + if (ret) { + block_acct_failed(blk_get_stats(ns->blkconf.blk), &req->acct); + nvme_aio_err(req, ret); + goto out; + } + + block_acct_done(blk_get_stats(ns->blkconf.blk), &req->acct); + +out: + if (ns->params.zoned) { + NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd; + uint64_t sdlba = le64_to_cpu(copy->sdlba); + NvmeZone *zone = nvme_get_zone_by_slba(ns, sdlba); + + __nvme_advance_zone_wp(ns, zone, ctx->nlb); + } + + g_free(ctx->bounce); + g_free(ctx->mbounce); + g_free(ctx); + + nvme_enqueue_req_completion(nvme_cq(req), req); +} + static void nvme_copy_cb(void *opaque, int ret) { NvmeRequest *req = opaque; @@ -1644,25 +2029,25 @@ static void nvme_copy_cb(void *opaque, int ret) trace_pci_nvme_copy_cb(nvme_cid(req)); - if (ns->params.zoned) { + if (ret) { + goto out; + } + + if (nvme_msize(ns)) { NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd; uint64_t sdlba = le64_to_cpu(copy->sdlba); - NvmeZone *zone = nvme_get_zone_by_slba(ns, sdlba); + int64_t offset = ns->mdata_offset + nvme_m2b(ns, sdlba); - __nvme_advance_zone_wp(ns, zone, ctx->nlb); + qemu_iovec_reset(&req->sg.iov); + qemu_iovec_add(&req->sg.iov, ctx->mbounce, nvme_m2b(ns, ctx->nlb)); + + req->aiocb = blk_aio_pwritev(ns->blkconf.blk, offset, &req->sg.iov, 0, + nvme_copy_complete_cb, req); + return; } - if (!ret) { - block_acct_done(blk_get_stats(ns->blkconf.blk), &req->acct); - } else { - block_acct_failed(blk_get_stats(ns->blkconf.blk), &req->acct); - nvme_aio_err(req, ret); - } - - g_free(ctx->bounce); - g_free(ctx); - - nvme_enqueue_req_completion(nvme_cq(req), req); +out: + nvme_copy_complete_cb(opaque, ret); } static void nvme_copy_in_complete(NvmeRequest *req) @@ -1745,6 +2130,7 @@ static void nvme_aio_copy_in_cb(void *opaque, int ret) block_acct_failed(blk_get_stats(ns->blkconf.blk), &req->acct); g_free(ctx->bounce); + g_free(ctx->mbounce); g_free(ctx); nvme_enqueue_req_completion(nvme_cq(req), req); @@ -1756,43 +2142,110 @@ static void nvme_aio_copy_in_cb(void *opaque, int ret) } struct nvme_compare_ctx { - QEMUIOVector iov; - uint8_t *bounce; + struct { + QEMUIOVector iov; + uint8_t *bounce; + } data; + + struct { + QEMUIOVector iov; + uint8_t *bounce; + } mdata; }; -static void nvme_compare_cb(void *opaque, int ret) +static void nvme_compare_mdata_cb(void *opaque, int ret) { NvmeRequest *req = opaque; - NvmeNamespace *ns = req->ns; + NvmeCtrl *n = nvme_ctrl(req); struct nvme_compare_ctx *ctx = req->opaque; g_autofree uint8_t *buf = NULL; - uint16_t status; + uint16_t status = NVME_SUCCESS; - trace_pci_nvme_compare_cb(nvme_cid(req)); + trace_pci_nvme_compare_mdata_cb(nvme_cid(req)); - if (!ret) { - block_acct_done(blk_get_stats(ns->blkconf.blk), &req->acct); - } else { - block_acct_failed(blk_get_stats(ns->blkconf.blk), &req->acct); - nvme_aio_err(req, ret); - goto out; - } + buf = g_malloc(ctx->mdata.iov.size); - buf = g_malloc(ctx->iov.size); - - status = nvme_h2c(nvme_ctrl(req), buf, ctx->iov.size, req); + status = nvme_bounce_mdata(n, buf, ctx->mdata.iov.size, + NVME_TX_DIRECTION_TO_DEVICE, req); if (status) { req->status = status; goto out; } - if (memcmp(buf, ctx->bounce, ctx->iov.size)) { + if (memcmp(buf, ctx->mdata.bounce, ctx->mdata.iov.size)) { req->status = NVME_CMP_FAILURE; + goto out; } out: - qemu_iovec_destroy(&ctx->iov); - g_free(ctx->bounce); + qemu_iovec_destroy(&ctx->data.iov); + g_free(ctx->data.bounce); + + qemu_iovec_destroy(&ctx->mdata.iov); + g_free(ctx->mdata.bounce); + + g_free(ctx); + + nvme_enqueue_req_completion(nvme_cq(req), req); +} + +static void nvme_compare_data_cb(void *opaque, int ret) +{ + NvmeRequest *req = opaque; + NvmeCtrl *n = nvme_ctrl(req); + NvmeNamespace *ns = req->ns; + BlockBackend *blk = ns->blkconf.blk; + BlockAcctCookie *acct = &req->acct; + BlockAcctStats *stats = blk_get_stats(blk); + + struct nvme_compare_ctx *ctx = req->opaque; + g_autofree uint8_t *buf = NULL; + uint16_t status; + + trace_pci_nvme_compare_data_cb(nvme_cid(req)); + + if (ret) { + block_acct_failed(stats, acct); + nvme_aio_err(req, ret); + goto out; + } + + buf = g_malloc(ctx->data.iov.size); + + status = nvme_bounce_data(n, buf, ctx->data.iov.size, + NVME_TX_DIRECTION_TO_DEVICE, req); + if (status) { + req->status = status; + goto out; + } + + if (memcmp(buf, ctx->data.bounce, ctx->data.iov.size)) { + req->status = NVME_CMP_FAILURE; + goto out; + } + + if (nvme_msize(ns)) { + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + uint64_t slba = le64_to_cpu(rw->slba); + uint32_t nlb = le16_to_cpu(rw->nlb) + 1; + size_t mlen = nvme_m2b(ns, nlb); + uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + + ctx->mdata.bounce = g_malloc(mlen); + + qemu_iovec_init(&ctx->mdata.iov, 1); + qemu_iovec_add(&ctx->mdata.iov, ctx->mdata.bounce, mlen); + + req->aiocb = blk_aio_preadv(blk, offset, &ctx->mdata.iov, 0, + nvme_compare_mdata_cb, req); + return; + } + + block_acct_done(stats, acct); + +out: + qemu_iovec_destroy(&ctx->data.iov); + g_free(ctx->data.bounce); g_free(ctx); nvme_enqueue_req_completion(nvme_cq(req), req); @@ -1885,6 +2338,7 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) uint32_t nlb = 0; uint8_t *bounce = NULL, *bouncep = NULL; + uint8_t *mbounce = NULL, *mbouncep = NULL; struct nvme_copy_ctx *ctx; uint16_t status; int i; @@ -1944,6 +2398,9 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) } bounce = bouncep = g_malloc(nvme_l2b(ns, nlb)); + if (nvme_msize(ns)) { + mbounce = mbouncep = g_malloc(nvme_m2b(ns, nlb)); + } block_acct_start(blk_get_stats(ns->blkconf.blk), &req->acct, 0, BLOCK_ACCT_READ); @@ -1951,6 +2408,7 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) ctx = g_new(struct nvme_copy_ctx, 1); ctx->bounce = bounce; + ctx->mbounce = mbounce; ctx->nlb = nlb; ctx->copies = 1; @@ -1977,6 +2435,24 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) nvme_aio_copy_in_cb, in_ctx); bouncep += len; + + if (nvme_msize(ns)) { + len = nvme_m2b(ns, nlb); + offset = ns->mdata_offset + nvme_m2b(ns, slba); + + in_ctx = g_new(struct nvme_copy_in_ctx, 1); + in_ctx->req = req; + + qemu_iovec_init(&in_ctx->iov, 1); + qemu_iovec_add(&in_ctx->iov, mbouncep, len); + + ctx->copies++; + + blk_aio_preadv(ns->blkconf.blk, offset, &in_ctx->iov, 0, + nvme_aio_copy_in_cb, in_ctx); + + mbouncep += len; + } } /* account for the 1-initialization */ @@ -1996,14 +2472,18 @@ static uint16_t nvme_compare(NvmeCtrl *n, NvmeRequest *req) BlockBackend *blk = ns->blkconf.blk; uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = le16_to_cpu(rw->nlb) + 1; - size_t len = nvme_l2b(ns, nlb); + size_t data_len = nvme_l2b(ns, nlb); + size_t len = data_len; int64_t offset = nvme_l2b(ns, slba); - uint8_t *bounce = NULL; struct nvme_compare_ctx *ctx = NULL; uint16_t status; trace_pci_nvme_compare(nvme_cid(req), nvme_nsid(ns), slba, nlb); + if (nvme_ns_ext(ns)) { + len += nvme_m2b(ns, nlb); + } + status = nvme_check_mdts(n, len); if (status) { return status; @@ -2022,18 +2502,22 @@ static uint16_t nvme_compare(NvmeCtrl *n, NvmeRequest *req) } } - bounce = g_malloc(len); + status = nvme_map_dptr(n, &req->sg, len, &req->cmd); + if (status) { + return status; + } ctx = g_new(struct nvme_compare_ctx, 1); - ctx->bounce = bounce; + ctx->data.bounce = g_malloc(data_len); req->opaque = ctx; - qemu_iovec_init(&ctx->iov, 1); - qemu_iovec_add(&ctx->iov, bounce, len); + qemu_iovec_init(&ctx->data.iov, 1); + qemu_iovec_add(&ctx->data.iov, ctx->data.bounce, data_len); - block_acct_start(blk_get_stats(blk), &req->acct, len, BLOCK_ACCT_READ); - blk_aio_preadv(blk, offset, &ctx->iov, 0, nvme_compare_cb, req); + block_acct_start(blk_get_stats(blk), &req->acct, data_len, + BLOCK_ACCT_READ); + blk_aio_preadv(blk, offset, &ctx->data.iov, 0, nvme_compare_data_cb, req); return NVME_NO_COMPLETE; } @@ -2056,7 +2540,7 @@ static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req) block_acct_start(blk_get_stats(req->ns->blkconf.blk), &req->acct, 0, BLOCK_ACCT_FLUSH); - req->aiocb = blk_aio_flush(req->ns->blkconf.blk, nvme_rw_cb, req); + req->aiocb = blk_aio_flush(req->ns->blkconf.blk, nvme_misc_cb, req); return NVME_NO_COMPLETE; } @@ -2099,13 +2583,18 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req) uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; uint64_t data_size = nvme_l2b(ns, nlb); + uint64_t mapped_size = data_size; uint64_t data_offset; BlockBackend *blk = ns->blkconf.blk; uint16_t status; - trace_pci_nvme_read(nvme_cid(req), nvme_nsid(ns), nlb, data_size, slba); + if (nvme_ns_ext(ns)) { + mapped_size += nvme_m2b(ns, nlb); + } - status = nvme_check_mdts(n, data_size); + trace_pci_nvme_read(nvme_cid(req), nvme_nsid(ns), nlb, mapped_size, slba); + + status = nvme_check_mdts(n, mapped_size); if (status) { goto invalid; } @@ -2124,11 +2613,6 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req) } } - status = nvme_map_dptr(n, &req->sg, data_size, &req->cmd); - if (status) { - goto invalid; - } - if (NVME_ERR_REC_DULBE(ns->features.err_rec)) { status = nvme_check_dulbe(ns, slba, nlb); if (status) { @@ -2136,6 +2620,11 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req) } } + status = nvme_map_data(n, nlb, req); + if (status) { + goto invalid; + } + data_offset = nvme_l2b(ns, slba); block_acct_start(blk_get_stats(blk), &req->acct, data_size, @@ -2156,17 +2645,22 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; uint64_t data_size = nvme_l2b(ns, nlb); + uint64_t mapped_size = data_size; uint64_t data_offset; NvmeZone *zone; NvmeZonedResult *res = (NvmeZonedResult *)&req->cqe; BlockBackend *blk = ns->blkconf.blk; uint16_t status; + if (nvme_ns_ext(ns)) { + mapped_size += nvme_m2b(ns, nlb); + } + trace_pci_nvme_write(nvme_cid(req), nvme_io_opc_str(rw->opcode), - nvme_nsid(ns), nlb, data_size, slba); + nvme_nsid(ns), nlb, mapped_size, slba); if (!wrz) { - status = nvme_check_mdts(n, data_size); + status = nvme_check_mdts(n, mapped_size); if (status) { goto invalid; } @@ -2214,7 +2708,7 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, data_offset = nvme_l2b(ns, slba); if (!wrz) { - status = nvme_map_dptr(n, &req->sg, data_size, &req->cmd); + status = nvme_map_data(n, nlb, req); if (status) { goto invalid; } @@ -2227,6 +2721,7 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, BDRV_REQ_MAY_UNMAP, nvme_rw_cb, req); } + return NVME_NO_COMPLETE; invalid: diff --git a/hw/block/trace-events b/hw/block/trace-events index ef06d2ea7470..62780f43d8e4 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -44,16 +44,19 @@ pci_nvme_flush(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" pci_nvme_read(uint16_t cid, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" pci_nvme_write(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_misc_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" pci_nvme_copy(uint16_t cid, uint32_t nsid, uint16_t nr, uint8_t format) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu16" format 0x%"PRIx8"" pci_nvme_copy_source_range(uint64_t slba, uint32_t nlb) "slba 0x%"PRIx64" nlb %"PRIu32"" pci_nvme_copy_in_complete(uint16_t cid) "cid %"PRIu16"" pci_nvme_copy_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_rw_complete_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" pci_nvme_block_status(int64_t offset, int64_t bytes, int64_t pnum, int ret, bool zeroed) "offset %"PRId64" bytes %"PRId64" pnum %"PRId64" ret 0x%x zeroed %d" pci_nvme_dsm(uint16_t cid, uint32_t nsid, uint32_t nr, uint32_t attr) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu32" attr 0x%"PRIx32"" pci_nvme_dsm_deallocate(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba %"PRIu64" nlb %"PRIu32"" pci_nvme_dsm_single_range_limit_exceeded(uint32_t nlb, uint32_t dmrsl) "nlb %"PRIu32" dmrsl %"PRIu32"" pci_nvme_compare(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" -pci_nvme_compare_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_compare_data_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_compare_mdata_cb(uint16_t cid) "cid %"PRIu16"" pci_nvme_aio_discard_cb(uint16_t cid) "cid %"PRIu16"" pci_nvme_aio_copy_in_cb(uint16_t cid) "cid %"PRIu16"" pci_nvme_aio_zone_reset_cb(uint16_t cid, uint64_t zslba) "cid %"PRIu16" zslba 0x%"PRIx64"" From patchwork Tue Mar 16 21:47:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 1454322 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=irrelevant.dk header.i=@irrelevant.dk header.a=rsa-sha256 header.s=fm2 header.b=etRwhmQF; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=uXCld/VJ; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F0S8G4mzHz9sRR for ; Wed, 17 Mar 2021 09:07:42 +1100 (AEDT) Received: from localhost ([::1]:38022 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMHqm-0004lG-Fm for incoming@patchwork.ozlabs.org; Tue, 16 Mar 2021 18:07:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60474) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXv-00070Q-Sa; Tue, 16 Mar 2021 17:48:12 -0400 Received: from new1-smtp.messagingengine.com ([66.111.4.221]:35973) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXq-0000x2-KK; Tue, 16 Mar 2021 17:48:10 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailnew.nyi.internal (Postfix) with ESMTP id D5DE5580A4C; Tue, 16 Mar 2021 17:48:05 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Tue, 16 Mar 2021 17:48:05 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=s/wN3yjWyzPhb 3cEidbxUhpr65EFDGRYgBSzvvkvKrg=; b=etRwhmQFK8FxHDeAHj6prNWvjutNP Fh81+2tBIIWS9X+FAHf6juEy/e5GJfK3RPph3QkvIPNvbNNcLki7AQbZbilL4qyF 22iSdhWrO1/bYXO31tsEp6WaeODx7wAPo7b09Yw1UevmMk+kQMds6wlswI+KEzZZ /eQqZ14U+MizEg0tsylNoxXPan+qlHW80hUKAXmGzP8RqmhW3P/6yEA4xBt4aUvy Rx/Z1aw8mqiGWnYj6OBoEOVYEsHQdkJqahJ5KgsaWFam3w0d9uPd5koVcjkH9eRH bjKGIKUevPeTFYbsktxeqJUe4DxCgo2S0slmDqhmUOJqd+ISkHAAjjo4Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=s/wN3yjWyzPhb3cEidbxUhpr65EFDGRYgBSzvvkvKrg=; b=uXCld/VJ UVje4YzH/YhcJBo6Acd9xs//fZfdqlPtIrgVwHj6mN/+5ST1QpEuI2eeXfXmCPsA Wkb9mIIvO70wuFFUqVM9Y4D132LsaU6azAa4U+Yf4/MCdPfL3XdOlNxxzeYlcV2u xxWNRuv1lYQvAFwd+wrIq8LsNC/do0dToyCAlACJThUuGaLzpggh4HRHUSNbtVsy J32LLeUqa6yPjk7+M1SBuP/HVAkO/BpmaXbFz/tadQFwjtiIBGFTZ98YxO72xIQw /GiTuEznyTnuLzoklZcE1gBvOjPCgsqdFXa64TLyvQUE7FOtI7fzpnXXdSlnfBAz 1ulYMJkiin5rng== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrudefvddgudehhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecukfhppeektddrudeijedrleekrdduledtnecuvehluhhsthgvrhfuihiivgeptd enucfrrghrrghmpehmrghilhhfrhhomhepihhtshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: from apples.local (80-167-98-190-cable.dk.customer.tdc.net [80.167.98.190]) by mail.messagingengine.com (Postfix) with ESMTPA id A17751080066; Tue, 16 Mar 2021 17:48:03 -0400 (EDT) From: Klaus Jensen To: Peter Maydell , qemu-devel@nongnu.org Subject: [PULL 05/11] hw/block/nvme: end-to-end data protection Date: Tue, 16 Mar 2021 22:47:47 +0100 Message-Id: <20210316214753.399389-6-its@irrelevant.dk> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210316214753.399389-1-its@irrelevant.dk> References: <20210316214753.399389-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.221; envelope-from=its@irrelevant.dk; helo=new1-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Klaus Jensen , Gollu Appalanaidu , Max Reitz , Keith Busch , Stefan Hajnoczi , Klaus Jensen Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Add support for namespaces formatted with protection information. The type of end-to-end data protection (i.e. Type 1, Type 2 or Type 3) is selected with the `pi` nvme-ns device parameter. If the number of metadata bytes is larger than 8, the `pil` nvme-ns device parameter may be used to control the location of the 8-byte DIF tuple. The default `pil` value of '0', causes the DIF tuple to be transferred as the last 8 bytes of the metadata. Set to 1 to store this in the first eight bytes instead. Co-authored-by: Gollu Appalanaidu Signed-off-by: Gollu Appalanaidu Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme-dif.h | 51 +++++ hw/block/nvme-ns.h | 4 + hw/block/nvme.h | 31 +++ include/block/nvme.h | 26 ++- hw/block/nvme-dif.c | 508 ++++++++++++++++++++++++++++++++++++++++++ hw/block/nvme-ns.c | 13 +- hw/block/nvme.c | 258 +++++++++++++++++---- hw/block/meson.build | 2 +- hw/block/trace-events | 11 + 9 files changed, 857 insertions(+), 47 deletions(-) create mode 100644 hw/block/nvme-dif.h create mode 100644 hw/block/nvme-dif.c diff --git a/hw/block/nvme-dif.h b/hw/block/nvme-dif.h new file mode 100644 index 000000000000..793829782c9d --- /dev/null +++ b/hw/block/nvme-dif.h @@ -0,0 +1,51 @@ +#ifndef HW_NVME_DIF_H +#define HW_NVME_DIF_H + +/* from Linux kernel (crypto/crct10dif_common.c) */ +static const uint16_t t10_dif_crc_table[256] = { + 0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B, + 0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6, + 0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6, + 0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B, + 0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1, + 0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C, + 0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C, + 0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781, + 0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8, + 0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255, + 0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925, + 0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698, + 0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472, + 0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF, + 0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF, + 0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02, + 0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA, + 0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067, + 0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17, + 0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA, + 0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640, + 0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD, + 0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D, + 0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30, + 0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759, + 0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4, + 0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394, + 0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29, + 0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3, + 0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E, + 0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E, + 0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3 +}; + +uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba, + uint32_t reftag); +void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len, + uint8_t *mbuf, size_t mlen, uint16_t apptag, + uint32_t reftag); +uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len, + uint8_t *mbuf, size_t mlen, uint16_t ctrl, + uint64_t slba, uint16_t apptag, + uint16_t appmask, uint32_t reftag); +uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req); + +#endif /* HW_NVME_DIF_H */ diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index 983df95265b9..e2f53d999699 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -15,6 +15,8 @@ #ifndef NVME_NS_H #define NVME_NS_H +#include "qemu/uuid.h" + #define TYPE_NVME_NS "nvme-ns" #define NVME_NS(obj) \ OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS) @@ -32,6 +34,8 @@ typedef struct NvmeNamespaceParams { uint16_t ms; uint8_t mset; + uint8_t pi; + uint8_t pil; uint16_t mssrl; uint32_t mcl; diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 5ba2efaedfd2..115d0177654d 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -2,6 +2,7 @@ #define HW_NVME_H #include "block/nvme.h" +#include "hw/pci/pci.h" #include "nvme-subsys.h" #include "nvme-ns.h" @@ -62,6 +63,15 @@ typedef struct NvmeRequest { QTAILQ_ENTRY(NvmeRequest)entry; } NvmeRequest; +typedef struct NvmeBounceContext { + NvmeRequest *req; + + struct { + QEMUIOVector iov; + uint8_t *bounce; + } data, mdata; +} NvmeBounceContext; + static inline const char *nvme_adm_opc_str(uint8_t opc) { switch (opc) { @@ -264,6 +274,27 @@ static inline NvmeCtrl *nvme_ctrl(NvmeRequest *req) return sq->ctrl; } +static inline uint16_t nvme_cid(NvmeRequest *req) +{ + if (!req) { + return 0xffff; + } + + return le16_to_cpu(req->cqe.cid); +} + +typedef enum NvmeTxDirection { + NVME_TX_DIRECTION_TO_DEVICE = 0, + NVME_TX_DIRECTION_FROM_DEVICE = 1, +} NvmeTxDirection; + int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp); +uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + NvmeTxDirection dir, NvmeRequest *req); +uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + NvmeTxDirection dir, NvmeRequest *req); +void nvme_rw_complete_cb(void *opaque, int ret); +uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len, + NvmeCmd *cmd); #endif /* HW_NVME_H */ diff --git a/include/block/nvme.h b/include/block/nvme.h index 372d0f2799fb..288038dc9562 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -696,12 +696,17 @@ enum { NVME_RW_DSM_LATENCY_LOW = 3 << 4, NVME_RW_DSM_SEQ_REQ = 1 << 6, NVME_RW_DSM_COMPRESSED = 1 << 7, + NVME_RW_PIREMAP = 1 << 9, NVME_RW_PRINFO_PRACT = 1 << 13, NVME_RW_PRINFO_PRCHK_GUARD = 1 << 12, NVME_RW_PRINFO_PRCHK_APP = 1 << 11, NVME_RW_PRINFO_PRCHK_REF = 1 << 10, + NVME_RW_PRINFO_PRCHK_MASK = 7 << 10, + }; +#define NVME_RW_PRINFO(control) ((control >> 10) & 0xf) + typedef struct QEMU_PACKED NvmeDsmCmd { uint8_t opcode; uint8_t flags; @@ -1324,14 +1329,22 @@ typedef struct QEMU_PACKED NvmeIdNsZoned { #define NVME_ID_NS_DPC_TYPE_MASK 0x7 enum NvmeIdNsDps { - DPS_TYPE_NONE = 0, - DPS_TYPE_1 = 1, - DPS_TYPE_2 = 2, - DPS_TYPE_3 = 3, - DPS_TYPE_MASK = 0x7, - DPS_FIRST_EIGHT = 8, + NVME_ID_NS_DPS_TYPE_NONE = 0, + NVME_ID_NS_DPS_TYPE_1 = 1, + NVME_ID_NS_DPS_TYPE_2 = 2, + NVME_ID_NS_DPS_TYPE_3 = 3, + NVME_ID_NS_DPS_TYPE_MASK = 0x7, + NVME_ID_NS_DPS_FIRST_EIGHT = 8, }; +#define NVME_ID_NS_DPS_TYPE(dps) (dps & NVME_ID_NS_DPS_TYPE_MASK) + +typedef struct NvmeDifTuple { + uint16_t guard; + uint16_t apptag; + uint32_t reftag; +} NvmeDifTuple; + enum NvmeZoneAttr { NVME_ZA_FINISHED_BY_CTLR = 1 << 0, NVME_ZA_FINISH_RECOMMENDED = 1 << 1, @@ -1428,5 +1441,6 @@ static inline void _nvme_check_size(void) QEMU_BUILD_BUG_ON(sizeof(NvmeSglDescriptor) != 16); QEMU_BUILD_BUG_ON(sizeof(NvmeIdNsDescr) != 4); QEMU_BUILD_BUG_ON(sizeof(NvmeZoneDescr) != 64); + QEMU_BUILD_BUG_ON(sizeof(NvmeDifTuple) != 8); } #endif diff --git a/hw/block/nvme-dif.c b/hw/block/nvme-dif.c new file mode 100644 index 000000000000..1b628dead715 --- /dev/null +++ b/hw/block/nvme-dif.c @@ -0,0 +1,508 @@ +#include "qemu/osdep.h" +#include "hw/block/block.h" +#include "sysemu/dma.h" +#include "sysemu/block-backend.h" +#include "qapi/error.h" +#include "trace.h" +#include "nvme.h" +#include "nvme-dif.h" + +uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba, + uint32_t reftag) +{ + if ((NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) == NVME_ID_NS_DPS_TYPE_1) && + (ctrl & NVME_RW_PRINFO_PRCHK_REF) && (slba & 0xffffffff) != reftag) { + return NVME_INVALID_PROT_INFO | NVME_DNR; + } + + return NVME_SUCCESS; +} + +/* from Linux kernel (crypto/crct10dif_common.c) */ +static uint16_t crc_t10dif(uint16_t crc, const unsigned char *buffer, + size_t len) +{ + unsigned int i; + + for (i = 0; i < len; i++) { + crc = (crc << 8) ^ t10_dif_crc_table[((crc >> 8) ^ buffer[i]) & 0xff]; + } + + return crc; +} + +void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len, + uint8_t *mbuf, size_t mlen, uint16_t apptag, + uint32_t reftag) +{ + uint8_t *end = buf + len; + size_t lsize = nvme_lsize(ns); + size_t msize = nvme_msize(ns); + int16_t pil = 0; + + if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) { + pil = nvme_msize(ns) - sizeof(NvmeDifTuple); + } + + trace_pci_nvme_dif_pract_generate_dif(len, lsize, lsize + pil, apptag, + reftag); + + for (; buf < end; buf += lsize, mbuf += msize) { + NvmeDifTuple *dif = (NvmeDifTuple *)(mbuf + pil); + uint16_t crc = crc_t10dif(0x0, buf, lsize); + + if (pil) { + crc = crc_t10dif(crc, mbuf, pil); + } + + dif->guard = cpu_to_be16(crc); + dif->apptag = cpu_to_be16(apptag); + dif->reftag = cpu_to_be32(reftag); + + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) != NVME_ID_NS_DPS_TYPE_3) { + reftag++; + } + } +} + +static uint16_t nvme_dif_prchk(NvmeNamespace *ns, NvmeDifTuple *dif, + uint8_t *buf, uint8_t *mbuf, size_t pil, + uint16_t ctrl, uint16_t apptag, + uint16_t appmask, uint32_t reftag) +{ + switch (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { + case NVME_ID_NS_DPS_TYPE_3: + if (be32_to_cpu(dif->reftag) != 0xffffffff) { + break; + } + + /* fallthrough */ + case NVME_ID_NS_DPS_TYPE_1: + case NVME_ID_NS_DPS_TYPE_2: + if (be16_to_cpu(dif->apptag) != 0xffff) { + break; + } + + trace_pci_nvme_dif_prchk_disabled(be16_to_cpu(dif->apptag), + be32_to_cpu(dif->reftag)); + + return NVME_SUCCESS; + } + + if (ctrl & NVME_RW_PRINFO_PRCHK_GUARD) { + uint16_t crc = crc_t10dif(0x0, buf, nvme_lsize(ns)); + + if (pil) { + crc = crc_t10dif(crc, mbuf, pil); + } + + trace_pci_nvme_dif_prchk_guard(be16_to_cpu(dif->guard), crc); + + if (be16_to_cpu(dif->guard) != crc) { + return NVME_E2E_GUARD_ERROR; + } + } + + if (ctrl & NVME_RW_PRINFO_PRCHK_APP) { + trace_pci_nvme_dif_prchk_apptag(be16_to_cpu(dif->apptag), apptag, + appmask); + + if ((be16_to_cpu(dif->apptag) & appmask) != (apptag & appmask)) { + return NVME_E2E_APP_ERROR; + } + } + + if (ctrl & NVME_RW_PRINFO_PRCHK_REF) { + trace_pci_nvme_dif_prchk_reftag(be32_to_cpu(dif->reftag), reftag); + + if (be32_to_cpu(dif->reftag) != reftag) { + return NVME_E2E_REF_ERROR; + } + } + + return NVME_SUCCESS; +} + +uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len, + uint8_t *mbuf, size_t mlen, uint16_t ctrl, + uint64_t slba, uint16_t apptag, + uint16_t appmask, uint32_t reftag) +{ + uint8_t *end = buf + len; + size_t lsize = nvme_lsize(ns); + size_t msize = nvme_msize(ns); + int16_t pil = 0; + uint16_t status; + + status = nvme_check_prinfo(ns, ctrl, slba, reftag); + if (status) { + return status; + } + + if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) { + pil = nvme_msize(ns) - sizeof(NvmeDifTuple); + } + + trace_pci_nvme_dif_check(NVME_RW_PRINFO(ctrl), lsize + pil); + + for (; buf < end; buf += lsize, mbuf += msize) { + NvmeDifTuple *dif = (NvmeDifTuple *)(mbuf + pil); + + status = nvme_dif_prchk(ns, dif, buf, mbuf, pil, ctrl, apptag, + appmask, reftag); + if (status) { + return status; + } + + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) != NVME_ID_NS_DPS_TYPE_3) { + reftag++; + } + } + + return NVME_SUCCESS; +} + +static uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, + size_t mlen, uint64_t slba) +{ + BlockBackend *blk = ns->blkconf.blk; + BlockDriverState *bs = blk_bs(blk); + + size_t msize = nvme_msize(ns); + size_t lsize = nvme_lsize(ns); + int64_t moffset = 0, offset = nvme_l2b(ns, slba); + uint8_t *mbufp, *end; + bool zeroed; + int16_t pil = 0; + int64_t bytes = (mlen / msize) * lsize; + int64_t pnum = 0; + + Error *err = NULL; + + + if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) { + pil = nvme_msize(ns) - sizeof(NvmeDifTuple); + } + + do { + int ret; + + bytes -= pnum; + + ret = bdrv_block_status(bs, offset, bytes, &pnum, NULL, NULL); + if (ret < 0) { + error_setg_errno(&err, -ret, "unable to get block status"); + error_report_err(err); + + return NVME_INTERNAL_DEV_ERROR; + } + + zeroed = !!(ret & BDRV_BLOCK_ZERO); + + trace_pci_nvme_block_status(offset, bytes, pnum, ret, zeroed); + + if (zeroed) { + mbufp = mbuf + moffset; + mlen = (pnum / lsize) * msize; + end = mbufp + mlen; + + for (; mbufp < end; mbufp += msize) { + memset(mbufp + pil, 0xff, sizeof(NvmeDifTuple)); + } + } + + moffset += (pnum / lsize) * msize; + offset += pnum; + } while (pnum != bytes); + + return NVME_SUCCESS; +} + +static void nvme_dif_rw_cb(void *opaque, int ret) +{ + NvmeBounceContext *ctx = opaque; + NvmeRequest *req = ctx->req; + NvmeNamespace *ns = req->ns; + BlockBackend *blk = ns->blkconf.blk; + + trace_pci_nvme_dif_rw_cb(nvme_cid(req), blk_name(blk)); + + qemu_iovec_destroy(&ctx->data.iov); + g_free(ctx->data.bounce); + + qemu_iovec_destroy(&ctx->mdata.iov); + g_free(ctx->mdata.bounce); + + g_free(ctx); + + nvme_rw_complete_cb(req, ret); +} + +static void nvme_dif_rw_check_cb(void *opaque, int ret) +{ + NvmeBounceContext *ctx = opaque; + NvmeRequest *req = ctx->req; + NvmeNamespace *ns = req->ns; + NvmeCtrl *n = nvme_ctrl(req); + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + uint64_t slba = le64_to_cpu(rw->slba); + uint16_t ctrl = le16_to_cpu(rw->control); + uint16_t apptag = le16_to_cpu(rw->apptag); + uint16_t appmask = le16_to_cpu(rw->appmask); + uint32_t reftag = le32_to_cpu(rw->reftag); + uint16_t status; + + trace_pci_nvme_dif_rw_check_cb(nvme_cid(req), NVME_RW_PRINFO(ctrl), apptag, + appmask, reftag); + + if (ret) { + goto out; + } + + status = nvme_dif_mangle_mdata(ns, ctx->mdata.bounce, ctx->mdata.iov.size, + slba); + if (status) { + req->status = status; + goto out; + } + + status = nvme_dif_check(ns, ctx->data.bounce, ctx->data.iov.size, + ctx->mdata.bounce, ctx->mdata.iov.size, ctrl, + slba, apptag, appmask, reftag); + if (status) { + req->status = status; + goto out; + } + + status = nvme_bounce_data(n, ctx->data.bounce, ctx->data.iov.size, + NVME_TX_DIRECTION_FROM_DEVICE, req); + if (status) { + req->status = status; + goto out; + } + + if (ctrl & NVME_RW_PRINFO_PRACT && nvme_msize(ns) == 8) { + goto out; + } + + status = nvme_bounce_mdata(n, ctx->mdata.bounce, ctx->mdata.iov.size, + NVME_TX_DIRECTION_FROM_DEVICE, req); + if (status) { + req->status = status; + } + +out: + nvme_dif_rw_cb(ctx, ret); +} + +static void nvme_dif_rw_mdata_in_cb(void *opaque, int ret) +{ + NvmeBounceContext *ctx = opaque; + NvmeRequest *req = ctx->req; + NvmeNamespace *ns = req->ns; + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + uint64_t slba = le64_to_cpu(rw->slba); + uint32_t nlb = le16_to_cpu(rw->nlb) + 1; + size_t mlen = nvme_m2b(ns, nlb); + uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + BlockBackend *blk = ns->blkconf.blk; + + trace_pci_nvme_dif_rw_mdata_in_cb(nvme_cid(req), blk_name(blk)); + + if (ret) { + goto out; + } + + ctx->mdata.bounce = g_malloc(mlen); + + qemu_iovec_reset(&ctx->mdata.iov); + qemu_iovec_add(&ctx->mdata.iov, ctx->mdata.bounce, mlen); + + req->aiocb = blk_aio_preadv(blk, offset, &ctx->mdata.iov, 0, + nvme_dif_rw_check_cb, ctx); + return; + +out: + nvme_dif_rw_cb(ctx, ret); +} + +static void nvme_dif_rw_mdata_out_cb(void *opaque, int ret) +{ + NvmeBounceContext *ctx = opaque; + NvmeRequest *req = ctx->req; + NvmeNamespace *ns = req->ns; + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + uint64_t slba = le64_to_cpu(rw->slba); + uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + BlockBackend *blk = ns->blkconf.blk; + + trace_pci_nvme_dif_rw_mdata_out_cb(nvme_cid(req), blk_name(blk)); + + if (ret) { + goto out; + } + + req->aiocb = blk_aio_pwritev(blk, offset, &ctx->mdata.iov, 0, + nvme_dif_rw_cb, ctx); + return; + +out: + nvme_dif_rw_cb(ctx, ret); +} + +uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req) +{ + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + NvmeNamespace *ns = req->ns; + BlockBackend *blk = ns->blkconf.blk; + bool wrz = rw->opcode == NVME_CMD_WRITE_ZEROES; + uint32_t nlb = le16_to_cpu(rw->nlb) + 1; + uint64_t slba = le64_to_cpu(rw->slba); + size_t len = nvme_l2b(ns, nlb); + size_t mlen = nvme_m2b(ns, nlb); + size_t mapped_len = len; + int64_t offset = nvme_l2b(ns, slba); + uint16_t ctrl = le16_to_cpu(rw->control); + uint16_t apptag = le16_to_cpu(rw->apptag); + uint16_t appmask = le16_to_cpu(rw->appmask); + uint32_t reftag = le32_to_cpu(rw->reftag); + bool pract = !!(ctrl & NVME_RW_PRINFO_PRACT); + NvmeBounceContext *ctx; + uint16_t status; + + trace_pci_nvme_dif_rw(pract, NVME_RW_PRINFO(ctrl)); + + ctx = g_new0(NvmeBounceContext, 1); + ctx->req = req; + + if (wrz) { + BdrvRequestFlags flags = BDRV_REQ_MAY_UNMAP; + + if (ctrl & NVME_RW_PRINFO_PRCHK_MASK) { + status = NVME_INVALID_PROT_INFO | NVME_DNR; + goto err; + } + + if (pract) { + uint8_t *mbuf, *end; + size_t msize = nvme_msize(ns); + int16_t pil = msize - sizeof(NvmeDifTuple); + + status = nvme_check_prinfo(ns, ctrl, slba, reftag); + if (status) { + goto err; + } + + flags = 0; + + ctx->mdata.bounce = g_malloc0(mlen); + + qemu_iovec_init(&ctx->mdata.iov, 1); + qemu_iovec_add(&ctx->mdata.iov, ctx->mdata.bounce, mlen); + + mbuf = ctx->mdata.bounce; + end = mbuf + mlen; + + if (ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT) { + pil = 0; + } + + for (; mbuf < end; mbuf += msize) { + NvmeDifTuple *dif = (NvmeDifTuple *)(mbuf + pil); + + dif->apptag = cpu_to_be16(apptag); + dif->reftag = cpu_to_be32(reftag); + + switch (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { + case NVME_ID_NS_DPS_TYPE_1: + case NVME_ID_NS_DPS_TYPE_2: + reftag++; + } + } + } + + req->aiocb = blk_aio_pwrite_zeroes(blk, offset, len, flags, + nvme_dif_rw_mdata_out_cb, ctx); + return NVME_NO_COMPLETE; + } + + if (nvme_ns_ext(ns) && !(pract && nvme_msize(ns) == 8)) { + mapped_len += mlen; + } + + status = nvme_map_dptr(n, &req->sg, mapped_len, &req->cmd); + if (status) { + return status; + } + + ctx->data.bounce = g_malloc(len); + + qemu_iovec_init(&ctx->data.iov, 1); + qemu_iovec_add(&ctx->data.iov, ctx->data.bounce, len); + + if (req->cmd.opcode == NVME_CMD_READ) { + block_acct_start(blk_get_stats(blk), &req->acct, ctx->data.iov.size, + BLOCK_ACCT_READ); + + req->aiocb = blk_aio_preadv(ns->blkconf.blk, offset, &ctx->data.iov, 0, + nvme_dif_rw_mdata_in_cb, ctx); + return NVME_NO_COMPLETE; + } + + status = nvme_bounce_data(n, ctx->data.bounce, ctx->data.iov.size, + NVME_TX_DIRECTION_TO_DEVICE, req); + if (status) { + goto err; + } + + ctx->mdata.bounce = g_malloc(mlen); + + qemu_iovec_init(&ctx->mdata.iov, 1); + qemu_iovec_add(&ctx->mdata.iov, ctx->mdata.bounce, mlen); + + if (!(pract && nvme_msize(ns) == 8)) { + status = nvme_bounce_mdata(n, ctx->mdata.bounce, ctx->mdata.iov.size, + NVME_TX_DIRECTION_TO_DEVICE, req); + if (status) { + goto err; + } + } + + status = nvme_check_prinfo(ns, ctrl, slba, reftag); + if (status) { + goto err; + } + + if (pract) { + /* splice generated protection information into the buffer */ + nvme_dif_pract_generate_dif(ns, ctx->data.bounce, ctx->data.iov.size, + ctx->mdata.bounce, ctx->mdata.iov.size, + apptag, reftag); + } else { + status = nvme_dif_check(ns, ctx->data.bounce, ctx->data.iov.size, + ctx->mdata.bounce, ctx->mdata.iov.size, ctrl, + slba, apptag, appmask, reftag); + if (status) { + goto err; + } + } + + block_acct_start(blk_get_stats(blk), &req->acct, ctx->data.iov.size, + BLOCK_ACCT_WRITE); + + req->aiocb = blk_aio_pwritev(ns->blkconf.blk, offset, &ctx->data.iov, 0, + nvme_dif_rw_mdata_out_cb, ctx); + + return NVME_NO_COMPLETE; + +err: + qemu_iovec_destroy(&ctx->data.iov); + g_free(ctx->data.bounce); + + qemu_iovec_destroy(&ctx->mdata.iov); + g_free(ctx->mdata.bounce); + + g_free(ctx); + + return status; +} diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 2e6bffc8e64d..a082a7004d8e 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -39,7 +39,7 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp) int lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas); int npdg, nlbas; - ns->id_ns.dlfeat = 0x9; + ns->id_ns.dlfeat = 0x1; id_ns->lbaf[lba_index].ds = 31 - clz32(ns->blkconf.logical_block_size); id_ns->lbaf[lba_index].ms = ns->params.ms; @@ -50,6 +50,9 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp) if (ns->params.mset) { id_ns->flbas |= 0x10; } + + id_ns->dpc = 0x1f; + id_ns->dps = ((ns->params.pil & 0x1) << 3) | ns->params.pi; } nlbas = nvme_ns_nlbas(ns); @@ -338,6 +341,12 @@ static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp) return -1; } + if (ns->params.pi && !ns->params.ms) { + error_setg(errp, "at least 8 bytes of metadata required to enable " + "protection information"); + return -1; + } + return 0; } @@ -416,6 +425,8 @@ static Property nvme_ns_props[] = { DEFINE_PROP_UUID("uuid", NvmeNamespace, params.uuid), DEFINE_PROP_UINT16("ms", NvmeNamespace, params.ms, 0), DEFINE_PROP_UINT8("mset", NvmeNamespace, params.mset, 0), + DEFINE_PROP_UINT8("pi", NvmeNamespace, params.pi, 0), + DEFINE_PROP_UINT8("pil", NvmeNamespace, params.pil, 0), DEFINE_PROP_UINT16("mssrl", NvmeNamespace, params.mssrl, 128), DEFINE_PROP_UINT32("mcl", NvmeNamespace, params.mcl, 128), DEFINE_PROP_UINT8("msrc", NvmeNamespace, params.msrc, 127), diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 2c4757ae46a7..7af651dc306f 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -144,6 +144,7 @@ #include "trace.h" #include "nvme.h" #include "nvme-ns.h" +#include "nvme-dif.h" #define NVME_MAX_IOQPAIRS 0xffff #define NVME_DB_SIZE 4 @@ -226,15 +227,6 @@ static const uint32_t nvme_cse_iocs_zoned[256] = { static void nvme_process_sq(void *opaque); -static uint16_t nvme_cid(NvmeRequest *req) -{ - if (!req) { - return 0xffff; - } - - return le16_to_cpu(req->cqe.cid); -} - static uint16_t nvme_sqid(NvmeRequest *req) { return le16_to_cpu(req->sq->sqid); @@ -933,8 +925,8 @@ unmap: return status; } -static uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len, - NvmeCmd *cmd) +uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len, + NvmeCmd *cmd) { uint64_t prp1, prp2; @@ -986,9 +978,16 @@ static uint16_t nvme_map_mptr(NvmeCtrl *n, NvmeSg *sg, size_t len, static uint16_t nvme_map_data(NvmeCtrl *n, uint32_t nlb, NvmeRequest *req) { NvmeNamespace *ns = req->ns; + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + uint16_t ctrl = le16_to_cpu(rw->control); size_t len = nvme_l2b(ns, nlb); uint16_t status; + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) && + (ctrl & NVME_RW_PRINFO_PRACT && nvme_msize(ns) == 8)) { + goto out; + } + if (nvme_ns_ext(ns)) { NvmeSg sg; @@ -1006,6 +1005,7 @@ static uint16_t nvme_map_data(NvmeCtrl *n, uint32_t nlb, NvmeRequest *req) return NVME_SUCCESS; } +out: return nvme_map_dptr(n, &req->sg, len, &req->cmd); } @@ -1035,11 +1035,6 @@ static uint16_t nvme_map_mdata(NvmeCtrl *n, uint32_t nlb, NvmeRequest *req) return nvme_map_mptr(n, &req->sg, len, &req->cmd); } -typedef enum NvmeTxDirection { - NVME_TX_DIRECTION_TO_DEVICE = 0, - NVME_TX_DIRECTION_FROM_DEVICE = 1, -} NvmeTxDirection; - static uint16_t nvme_tx_interleaved(NvmeCtrl *n, NvmeSg *sg, uint8_t *ptr, uint32_t len, uint32_t bytes, int32_t skip_bytes, int64_t offset, @@ -1164,12 +1159,15 @@ static inline uint16_t nvme_h2c(NvmeCtrl *n, uint8_t *ptr, uint32_t len, return nvme_tx(n, &req->sg, ptr, len, NVME_TX_DIRECTION_TO_DEVICE); } -static uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len, - NvmeTxDirection dir, NvmeRequest *req) +uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + NvmeTxDirection dir, NvmeRequest *req) { NvmeNamespace *ns = req->ns; + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + uint16_t ctrl = le16_to_cpu(rw->control); - if (nvme_ns_ext(ns)) { + if (nvme_ns_ext(ns) && + !(ctrl & NVME_RW_PRINFO_PRACT && nvme_msize(ns) == 8)) { size_t lsize = nvme_lsize(ns); size_t msize = nvme_msize(ns); @@ -1180,8 +1178,8 @@ static uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len, return nvme_tx(n, &req->sg, ptr, len, dir); } -static uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len, - NvmeTxDirection dir, NvmeRequest *req) +uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len, + NvmeTxDirection dir, NvmeRequest *req) { NvmeNamespace *ns = req->ns; uint16_t status; @@ -1777,7 +1775,7 @@ static void nvme_misc_cb(void *opaque, int ret) nvme_enqueue_req_completion(nvme_cq(req), req); } -static void nvme_rw_complete_cb(void *opaque, int ret) +void nvme_rw_complete_cb(void *opaque, int ret) { NvmeRequest *req = opaque; NvmeNamespace *ns = req->ns; @@ -1984,11 +1982,13 @@ struct nvme_copy_ctx { uint8_t *bounce; uint8_t *mbounce; uint32_t nlb; + NvmeCopySourceRange *ranges; }; struct nvme_copy_in_ctx { NvmeRequest *req; QEMUIOVector iov; + NvmeCopySourceRange *range; }; static void nvme_copy_complete_cb(void *opaque, int ret) @@ -2062,6 +2062,70 @@ static void nvme_copy_in_complete(NvmeRequest *req) block_acct_done(blk_get_stats(ns->blkconf.blk), &req->acct); + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { + uint16_t prinfor = (copy->control[0] >> 4) & 0xf; + uint16_t prinfow = (copy->control[2] >> 2) & 0xf; + uint16_t nr = copy->nr + 1; + NvmeCopySourceRange *range; + uint64_t slba; + uint32_t nlb; + uint16_t apptag, appmask; + uint32_t reftag; + uint8_t *buf = ctx->bounce, *mbuf = ctx->mbounce; + size_t len, mlen; + int i; + + /* + * The dif helpers expects prinfo to be similar to the control field of + * the NvmeRwCmd, so shift by 10 to fake it. + */ + prinfor = prinfor << 10; + prinfow = prinfow << 10; + + for (i = 0; i < nr; i++) { + range = &ctx->ranges[i]; + slba = le64_to_cpu(range->slba); + nlb = le16_to_cpu(range->nlb) + 1; + len = nvme_l2b(ns, nlb); + mlen = nvme_m2b(ns, nlb); + apptag = le16_to_cpu(range->apptag); + appmask = le16_to_cpu(range->appmask); + reftag = le32_to_cpu(range->reftag); + + status = nvme_dif_check(ns, buf, len, mbuf, mlen, prinfor, slba, + apptag, appmask, reftag); + if (status) { + goto invalid; + } + + buf += len; + mbuf += mlen; + } + + apptag = le16_to_cpu(copy->apptag); + appmask = le16_to_cpu(copy->appmask); + reftag = le32_to_cpu(copy->reftag); + + if (prinfow & NVME_RW_PRINFO_PRACT) { + size_t len = nvme_l2b(ns, ctx->nlb); + size_t mlen = nvme_m2b(ns, ctx->nlb); + + status = nvme_check_prinfo(ns, prinfow, sdlba, reftag); + if (status) { + goto invalid; + } + + nvme_dif_pract_generate_dif(ns, ctx->bounce, len, ctx->mbounce, + mlen, apptag, reftag); + } else { + status = nvme_dif_check(ns, ctx->bounce, len, ctx->mbounce, mlen, + prinfow, sdlba, apptag, appmask, reftag); + if (status) { + goto invalid; + } + } + } + status = nvme_check_bounds(ns, sdlba, ctx->nlb); if (status) { trace_pci_nvme_err_invalid_lba_range(sdlba, ctx->nlb, ns->id_ns.nsze); @@ -2156,7 +2220,13 @@ struct nvme_compare_ctx { static void nvme_compare_mdata_cb(void *opaque, int ret) { NvmeRequest *req = opaque; + NvmeNamespace *ns = req->ns; NvmeCtrl *n = nvme_ctrl(req); + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + uint16_t ctrl = le16_to_cpu(rw->control); + uint16_t apptag = le16_to_cpu(rw->apptag); + uint16_t appmask = le16_to_cpu(rw->appmask); + uint32_t reftag = le32_to_cpu(rw->reftag); struct nvme_compare_ctx *ctx = req->opaque; g_autofree uint8_t *buf = NULL; uint16_t status = NVME_SUCCESS; @@ -2172,6 +2242,40 @@ static void nvme_compare_mdata_cb(void *opaque, int ret) goto out; } + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { + uint64_t slba = le64_to_cpu(rw->slba); + uint8_t *bufp; + uint8_t *mbufp = ctx->mdata.bounce; + uint8_t *end = mbufp + ctx->mdata.iov.size; + size_t msize = nvme_msize(ns); + int16_t pil = 0; + + status = nvme_dif_check(ns, ctx->data.bounce, ctx->data.iov.size, + ctx->mdata.bounce, ctx->mdata.iov.size, ctrl, + slba, apptag, appmask, reftag); + if (status) { + req->status = status; + goto out; + } + + /* + * When formatted with protection information, do not compare the DIF + * tuple. + */ + if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) { + pil = nvme_msize(ns) - sizeof(NvmeDifTuple); + } + + for (bufp = buf; mbufp < end; bufp += msize, mbufp += msize) { + if (memcmp(bufp + pil, mbufp + pil, msize - pil)) { + req->status = NVME_CMP_FAILURE; + goto out; + } + } + + goto out; + } + if (memcmp(buf, ctx->mdata.bounce, ctx->mdata.iov.size)) { req->status = NVME_CMP_FAILURE; goto out; @@ -2331,12 +2435,18 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) { NvmeNamespace *ns = req->ns; NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd; - g_autofree NvmeCopySourceRange *range = NULL; uint16_t nr = copy->nr + 1; uint8_t format = copy->control[0] & 0xf; - uint32_t nlb = 0; + /* + * Shift the PRINFOR/PRINFOW values by 10 to allow reusing the + * NVME_RW_PRINFO constants. + */ + uint16_t prinfor = ((copy->control[0] >> 4) & 0xf) << 10; + uint16_t prinfow = ((copy->control[2] >> 2) & 0xf) << 10; + + uint32_t nlb = 0; uint8_t *bounce = NULL, *bouncep = NULL; uint8_t *mbounce = NULL, *mbouncep = NULL; struct nvme_copy_ctx *ctx; @@ -2345,6 +2455,11 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) trace_pci_nvme_copy(nvme_cid(req), nvme_nsid(ns), nr, format); + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) && + ((prinfor & NVME_RW_PRINFO_PRACT) != (prinfow & NVME_RW_PRINFO_PRACT))) { + return NVME_INVALID_FIELD | NVME_DNR; + } + if (!(n->id_ctrl.ocfs & (1 << format))) { trace_pci_nvme_err_copy_invalid_format(format); return NVME_INVALID_FIELD | NVME_DNR; @@ -2354,39 +2469,41 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) return NVME_CMD_SIZE_LIMIT | NVME_DNR; } - range = g_new(NvmeCopySourceRange, nr); + ctx = g_new(struct nvme_copy_ctx, 1); + ctx->ranges = g_new(NvmeCopySourceRange, nr); - status = nvme_h2c(n, (uint8_t *)range, nr * sizeof(NvmeCopySourceRange), - req); + status = nvme_h2c(n, (uint8_t *)ctx->ranges, + nr * sizeof(NvmeCopySourceRange), req); if (status) { - return status; + goto out; } for (i = 0; i < nr; i++) { - uint64_t slba = le64_to_cpu(range[i].slba); - uint32_t _nlb = le16_to_cpu(range[i].nlb) + 1; + uint64_t slba = le64_to_cpu(ctx->ranges[i].slba); + uint32_t _nlb = le16_to_cpu(ctx->ranges[i].nlb) + 1; if (_nlb > le16_to_cpu(ns->id_ns.mssrl)) { - return NVME_CMD_SIZE_LIMIT | NVME_DNR; + status = NVME_CMD_SIZE_LIMIT | NVME_DNR; + goto out; } status = nvme_check_bounds(ns, slba, _nlb); if (status) { trace_pci_nvme_err_invalid_lba_range(slba, _nlb, ns->id_ns.nsze); - return status; + goto out; } if (NVME_ERR_REC_DULBE(ns->features.err_rec)) { status = nvme_check_dulbe(ns, slba, _nlb); if (status) { - return status; + goto out; } } if (ns->params.zoned) { status = nvme_check_zone_read(ns, slba, _nlb); if (status) { - return status; + goto out; } } @@ -2394,7 +2511,8 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) } if (nlb > le32_to_cpu(ns->id_ns.mcl)) { - return NVME_CMD_SIZE_LIMIT | NVME_DNR; + status = NVME_CMD_SIZE_LIMIT | NVME_DNR; + goto out; } bounce = bouncep = g_malloc(nvme_l2b(ns, nlb)); @@ -2405,8 +2523,6 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) block_acct_start(blk_get_stats(ns->blkconf.blk), &req->acct, 0, BLOCK_ACCT_READ); - ctx = g_new(struct nvme_copy_ctx, 1); - ctx->bounce = bounce; ctx->mbounce = mbounce; ctx->nlb = nlb; @@ -2415,8 +2531,8 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) req->opaque = ctx; for (i = 0; i < nr; i++) { - uint64_t slba = le64_to_cpu(range[i].slba); - uint32_t nlb = le16_to_cpu(range[i].nlb) + 1; + uint64_t slba = le64_to_cpu(ctx->ranges[i].slba); + uint32_t nlb = le16_to_cpu(ctx->ranges[i].nlb) + 1; size_t len = nvme_l2b(ns, nlb); int64_t offset = nvme_l2b(ns, slba); @@ -2463,6 +2579,12 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) } return NVME_NO_COMPLETE; + +out: + g_free(ctx->ranges); + g_free(ctx); + + return status; } static uint16_t nvme_compare(NvmeCtrl *n, NvmeRequest *req) @@ -2472,6 +2594,7 @@ static uint16_t nvme_compare(NvmeCtrl *n, NvmeRequest *req) BlockBackend *blk = ns->blkconf.blk; uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = le16_to_cpu(rw->nlb) + 1; + uint16_t ctrl = le16_to_cpu(rw->control); size_t data_len = nvme_l2b(ns, nlb); size_t len = data_len; int64_t offset = nvme_l2b(ns, slba); @@ -2480,6 +2603,10 @@ static uint16_t nvme_compare(NvmeCtrl *n, NvmeRequest *req) trace_pci_nvme_compare(nvme_cid(req), nvme_nsid(ns), slba, nlb); + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) && (ctrl & NVME_RW_PRINFO_PRACT)) { + return NVME_INVALID_PROT_INFO | NVME_DNR; + } + if (nvme_ns_ext(ns)) { len += nvme_m2b(ns, nlb); } @@ -2582,6 +2709,7 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req) NvmeNamespace *ns = req->ns; uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; + uint16_t ctrl = le16_to_cpu(rw->control); uint64_t data_size = nvme_l2b(ns, nlb); uint64_t mapped_size = data_size; uint64_t data_offset; @@ -2590,6 +2718,14 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req) if (nvme_ns_ext(ns)) { mapped_size += nvme_m2b(ns, nlb); + + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { + bool pract = ctrl & NVME_RW_PRINFO_PRACT; + + if (pract && nvme_msize(ns) == 8) { + mapped_size = data_size; + } + } } trace_pci_nvme_read(nvme_cid(req), nvme_nsid(ns), nlb, mapped_size, slba); @@ -2620,6 +2756,10 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req) } } + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { + return nvme_dif_rw(n, req); + } + status = nvme_map_data(n, nlb, req); if (status) { goto invalid; @@ -2644,6 +2784,7 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, NvmeNamespace *ns = req->ns; uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; + uint16_t ctrl = le16_to_cpu(rw->control); uint64_t data_size = nvme_l2b(ns, nlb); uint64_t mapped_size = data_size; uint64_t data_offset; @@ -2654,6 +2795,14 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, if (nvme_ns_ext(ns)) { mapped_size += nvme_m2b(ns, nlb); + + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { + bool pract = ctrl & NVME_RW_PRINFO_PRACT; + + if (pract && nvme_msize(ns) == 8) { + mapped_size -= nvme_m2b(ns, nlb); + } + } } trace_pci_nvme_write(nvme_cid(req), nvme_io_opc_str(rw->opcode), @@ -2676,6 +2825,8 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, zone = nvme_get_zone_by_slba(ns, slba); if (append) { + bool piremap = !!(ctrl & NVME_RW_PIREMAP); + if (unlikely(slba != zone->d.zslba)) { trace_pci_nvme_err_append_not_at_start(slba, zone->d.zslba); status = NVME_INVALID_FIELD; @@ -2689,7 +2840,32 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, } slba = zone->w_ptr; + rw->slba = cpu_to_le64(slba); res->slba = cpu_to_le64(slba); + + switch (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { + case NVME_ID_NS_DPS_TYPE_1: + if (!piremap) { + return NVME_INVALID_PROT_INFO | NVME_DNR; + } + + /* fallthrough */ + + case NVME_ID_NS_DPS_TYPE_2: + if (piremap) { + uint32_t reftag = le32_to_cpu(rw->reftag); + rw->reftag = cpu_to_le32(reftag + (slba - zone->d.zslba)); + } + + break; + + case NVME_ID_NS_DPS_TYPE_3: + if (piremap) { + return NVME_INVALID_PROT_INFO | NVME_DNR; + } + + break; + } } status = nvme_check_zone_write(ns, zone, slba, nlb); @@ -2707,6 +2883,10 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, data_offset = nvme_l2b(ns, slba); + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { + return nvme_dif_rw(n, req); + } + if (!wrz) { status = nvme_map_data(n, nlb, req); if (status) { diff --git a/hw/block/meson.build b/hw/block/meson.build index 549282915521..5b4a7699f98f 100644 --- a/hw/block/meson.build +++ b/hw/block/meson.build @@ -13,7 +13,7 @@ softmmu_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c')) softmmu_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c')) softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen-block.c')) softmmu_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c')) -softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c', 'nvme-ns.c', 'nvme-subsys.c')) +softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c', 'nvme-ns.c', 'nvme-subsys.c', 'nvme-dif.c')) specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c')) specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c')) diff --git a/hw/block/trace-events b/hw/block/trace-events index 62780f43d8e4..fc243d0b4624 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -45,6 +45,17 @@ pci_nvme_read(uint16_t cid, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_ pci_nvme_write(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" pci_nvme_misc_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_dif_rw(uint8_t pract, uint8_t prinfo) "pract 0x%"PRIx8" prinfo 0x%"PRIx8"" +pci_nvme_dif_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_dif_rw_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_dif_rw_mdata_out_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_dif_rw_check_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32"" +pci_nvme_dif_pract_generate_dif(size_t len, size_t lba_size, size_t chksum_len, uint16_t apptag, uint32_t reftag) "len %zu lba_size %zu chksum_len %zu apptag 0x%"PRIx16" reftag 0x%"PRIx32"" +pci_nvme_dif_check(uint8_t prinfo, uint16_t chksum_len) "prinfo 0x%"PRIx8" chksum_len %"PRIu16"" +pci_nvme_dif_prchk_disabled(uint16_t apptag, uint32_t reftag) "apptag 0x%"PRIx16" reftag 0x%"PRIx32"" +pci_nvme_dif_prchk_guard(uint16_t guard, uint16_t crc) "guard 0x%"PRIx16" crc 0x%"PRIx16"" +pci_nvme_dif_prchk_apptag(uint16_t apptag, uint16_t elbat, uint16_t elbatm) "apptag 0x%"PRIx16" elbat 0x%"PRIx16" elbatm 0x%"PRIx16"" +pci_nvme_dif_prchk_reftag(uint32_t reftag, uint32_t elbrt) "reftag 0x%"PRIx32" elbrt 0x%"PRIx32"" pci_nvme_copy(uint16_t cid, uint32_t nsid, uint16_t nr, uint8_t format) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu16" format 0x%"PRIx8"" pci_nvme_copy_source_range(uint64_t slba, uint32_t nlb) "slba 0x%"PRIx64" nlb %"PRIu32"" pci_nvme_copy_in_complete(uint16_t cid) "cid %"PRIu16"" From patchwork Tue Mar 16 21:47:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 1454318 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=irrelevant.dk header.i=@irrelevant.dk header.a=rsa-sha256 header.s=fm2 header.b=zmPYoo8x; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=ogslMyg6; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F0Rzj0bMZz9sW1 for ; Wed, 17 Mar 2021 09:00:17 +1100 (AEDT) Received: from localhost ([::1]:55808 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMHja-000842-VY for incoming@patchwork.ozlabs.org; Tue, 16 Mar 2021 18:00:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60478) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXv-00071E-K8; Tue, 16 Mar 2021 17:48:11 -0400 Received: from new1-smtp.messagingengine.com ([66.111.4.221]:54293) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXr-0000xP-Ie; Tue, 16 Mar 2021 17:48:11 -0400 Received: from compute2.internal (compute2.nyi.internal [10.202.2.42]) by mailnew.nyi.internal (Postfix) with ESMTP id C5FD2580A76; Tue, 16 Mar 2021 17:48:06 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Tue, 16 Mar 2021 17:48:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=W7fOFU7TnGXUq bdMIdegDguw6DvoBIz2eqDxiNMSaB4=; b=zmPYoo8xN3aC/PEFQ1SLCDmNdvUB9 zxluhhDkdWf9KvK5zDX4tIDsP6/XfjhgECIg7+B/zFdJPKkDj+FHHoBGbYLjVFOD eJjUkqA4n/v/ijmzSpoJZYSGiMnflg+WXG2K1Y4Bgxv8Al7tghRbnZKVifamZs1T 48ATkWZGWlt6wxFrTDi0F8Y3hPV0FtWCbOb0TEjLuhbR75QWdd8NUMAqVZz86T+9 Z+jBPgFA2oujNX57wSQelsBnnM86S05O+PHjGx07cYrEyrbAaNgpE3feHQ/kaBVt X4tC/W2q9Jgyloh4YbxWAv6NIkRO2MEhTgy4kDVRF3XjymX3FBBOTvYdQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=W7fOFU7TnGXUqbdMIdegDguw6DvoBIz2eqDxiNMSaB4=; b=ogslMyg6 Li1bDj2mUVtoPGnJLA1rcmsyV2od6nkrXV/Li0UT2N1F7GClRgBlhGNZd9pjaQYx l+sxO4XPooPkCURvXIbFjEwlwft9fItriJbYJ7I4rv+inYADKr6DuBHryleXX/tU HspR3IMBl4E0Hy3ECzxoEOLmkPkXMpQ+oNEwbkuJq5oXdV0yoR3IbyoWsXN9v66q 6WmWaTbg+JlGvCblQfJieNRcoVg7XH4OJR7aspJTFjwEZfObss8DRl+DqLuuYuhj wWAm+hUx7ffsR1bqzR8whe0xlKktzx3Ukv9IZ5twqiaSbFSbS1c8Qwr6BsSKJ6Ok TYlhW+LEth1g9g== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrudefvddgudehhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecukfhppeektddrudeijedrleekrdduledtnecuvehluhhsthgvrhfuihiivgepud enucfrrghrrghmpehmrghilhhfrhhomhepihhtshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: from apples.local (80-167-98-190-cable.dk.customer.tdc.net [80.167.98.190]) by mail.messagingengine.com (Postfix) with ESMTPA id 5915C108005C; Tue, 16 Mar 2021 17:48:05 -0400 (EDT) From: Klaus Jensen To: Peter Maydell , qemu-devel@nongnu.org Subject: [PULL 06/11] hw/block/nvme: add verify command Date: Tue, 16 Mar 2021 22:47:48 +0100 Message-Id: <20210316214753.399389-7-its@irrelevant.dk> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210316214753.399389-1-its@irrelevant.dk> References: <20210316214753.399389-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.221; envelope-from=its@irrelevant.dk; helo=new1-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Klaus Jensen , Gollu Appalanaidu , Max Reitz , Keith Busch , Stefan Hajnoczi , Klaus Jensen Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Gollu Appalanaidu See NVM Express 1.4, section 6.14 ("Verify Command"). Signed-off-by: Gollu Appalanaidu [k.jensen: rebased, refactored for e2e] Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme-dif.h | 2 + hw/block/nvme.h | 1 + include/block/nvme.h | 2 + hw/block/nvme-dif.c | 4 +- hw/block/nvme.c | 147 +++++++++++++++++++++++++++++++++++++++++- hw/block/trace-events | 3 + 6 files changed, 156 insertions(+), 3 deletions(-) diff --git a/hw/block/nvme-dif.h b/hw/block/nvme-dif.h index 793829782c9d..5a8e37c8525b 100644 --- a/hw/block/nvme-dif.h +++ b/hw/block/nvme-dif.h @@ -39,6 +39,8 @@ static const uint16_t t10_dif_crc_table[256] = { uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba, uint32_t reftag); +uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen, + uint64_t slba); void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len, uint8_t *mbuf, size_t mlen, uint16_t apptag, uint32_t reftag); diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 115d0177654d..11c7fcc317da 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -98,6 +98,7 @@ static inline const char *nvme_io_opc_str(uint8_t opc) case NVME_CMD_COMPARE: return "NVME_NVM_CMD_COMPARE"; case NVME_CMD_WRITE_ZEROES: return "NVME_NVM_CMD_WRITE_ZEROES"; case NVME_CMD_DSM: return "NVME_NVM_CMD_DSM"; + case NVME_CMD_VERIFY: return "NVME_NVM_CMD_VERIFY"; case NVME_CMD_COPY: return "NVME_NVM_CMD_COPY"; case NVME_CMD_ZONE_MGMT_SEND: return "NVME_ZONED_CMD_MGMT_SEND"; case NVME_CMD_ZONE_MGMT_RECV: return "NVME_ZONED_CMD_MGMT_RECV"; diff --git a/include/block/nvme.h b/include/block/nvme.h index 288038dc9562..ba757b32dbb7 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -580,6 +580,7 @@ enum NvmeIoCommands { NVME_CMD_COMPARE = 0x05, NVME_CMD_WRITE_ZEROES = 0x08, NVME_CMD_DSM = 0x09, + NVME_CMD_VERIFY = 0x0c, NVME_CMD_COPY = 0x19, NVME_CMD_ZONE_MGMT_SEND = 0x79, NVME_CMD_ZONE_MGMT_RECV = 0x7a, @@ -1084,6 +1085,7 @@ enum NvmeIdCtrlOncs { NVME_ONCS_FEATURES = 1 << 4, NVME_ONCS_RESRVATIONS = 1 << 5, NVME_ONCS_TIMESTAMP = 1 << 6, + NVME_ONCS_VERIFY = 1 << 7, NVME_ONCS_COPY = 1 << 8, }; diff --git a/hw/block/nvme-dif.c b/hw/block/nvme-dif.c index 1b628dead715..2038d724bda5 100644 --- a/hw/block/nvme-dif.c +++ b/hw/block/nvme-dif.c @@ -162,8 +162,8 @@ uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len, return NVME_SUCCESS; } -static uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, - size_t mlen, uint64_t slba) +uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen, + uint64_t slba) { BlockBackend *blk = ns->blkconf.blk; BlockDriverState *bs = blk_bs(blk); diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 7af651dc306f..d754bd8e0440 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -208,6 +208,7 @@ static const uint32_t nvme_cse_iocs_nvm[256] = { [NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_READ] = NVME_CMD_EFF_CSUPP, [NVME_CMD_DSM] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, + [NVME_CMD_VERIFY] = NVME_CMD_EFF_CSUPP, [NVME_CMD_COPY] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_COMPARE] = NVME_CMD_EFF_CSUPP, }; @@ -218,6 +219,7 @@ static const uint32_t nvme_cse_iocs_zoned[256] = { [NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_READ] = NVME_CMD_EFF_CSUPP, [NVME_CMD_DSM] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, + [NVME_CMD_VERIFY] = NVME_CMD_EFF_CSUPP, [NVME_CMD_COPY] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, [NVME_CMD_COMPARE] = NVME_CMD_EFF_CSUPP, [NVME_CMD_ZONE_APPEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, @@ -1884,6 +1886,90 @@ static void nvme_aio_flush_cb(void *opaque, int ret) nvme_enqueue_req_completion(nvme_cq(req), req); } +static void nvme_verify_cb(void *opaque, int ret) +{ + NvmeBounceContext *ctx = opaque; + NvmeRequest *req = ctx->req; + NvmeNamespace *ns = req->ns; + BlockBackend *blk = ns->blkconf.blk; + BlockAcctCookie *acct = &req->acct; + BlockAcctStats *stats = blk_get_stats(blk); + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + uint64_t slba = le64_to_cpu(rw->slba); + uint16_t ctrl = le16_to_cpu(rw->control); + uint16_t apptag = le16_to_cpu(rw->apptag); + uint16_t appmask = le16_to_cpu(rw->appmask); + uint32_t reftag = le32_to_cpu(rw->reftag); + uint16_t status; + + trace_pci_nvme_verify_cb(nvme_cid(req), NVME_RW_PRINFO(ctrl), apptag, + appmask, reftag); + + if (ret) { + block_acct_failed(stats, acct); + nvme_aio_err(req, ret); + goto out; + } + + block_acct_done(stats, acct); + + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { + status = nvme_dif_mangle_mdata(ns, ctx->mdata.bounce, + ctx->mdata.iov.size, slba); + if (status) { + req->status = status; + goto out; + } + + req->status = nvme_dif_check(ns, ctx->data.bounce, ctx->data.iov.size, + ctx->mdata.bounce, ctx->mdata.iov.size, + ctrl, slba, apptag, appmask, reftag); + } + +out: + qemu_iovec_destroy(&ctx->data.iov); + g_free(ctx->data.bounce); + + qemu_iovec_destroy(&ctx->mdata.iov); + g_free(ctx->mdata.bounce); + + g_free(ctx); + + nvme_enqueue_req_completion(nvme_cq(req), req); +} + + +static void nvme_verify_mdata_in_cb(void *opaque, int ret) +{ + NvmeBounceContext *ctx = opaque; + NvmeRequest *req = ctx->req; + NvmeNamespace *ns = req->ns; + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + uint64_t slba = le64_to_cpu(rw->slba); + uint32_t nlb = le16_to_cpu(rw->nlb) + 1; + size_t mlen = nvme_m2b(ns, nlb); + uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + BlockBackend *blk = ns->blkconf.blk; + + trace_pci_nvme_verify_mdata_in_cb(nvme_cid(req), blk_name(blk)); + + if (ret) { + goto out; + } + + ctx->mdata.bounce = g_malloc(mlen); + + qemu_iovec_reset(&ctx->mdata.iov); + qemu_iovec_add(&ctx->mdata.iov, ctx->mdata.bounce, mlen); + + req->aiocb = blk_aio_preadv(blk, offset, &ctx->mdata.iov, 0, + nvme_verify_cb, ctx); + return; + +out: + nvme_verify_cb(ctx, ret); +} + static void nvme_aio_discard_cb(void *opaque, int ret) { NvmeRequest *req = opaque; @@ -2431,6 +2517,62 @@ static uint16_t nvme_dsm(NvmeCtrl *n, NvmeRequest *req) return status; } +static uint16_t nvme_verify(NvmeCtrl *n, NvmeRequest *req) +{ + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + NvmeNamespace *ns = req->ns; + BlockBackend *blk = ns->blkconf.blk; + uint64_t slba = le64_to_cpu(rw->slba); + uint32_t nlb = le16_to_cpu(rw->nlb) + 1; + size_t len = nvme_l2b(ns, nlb); + int64_t offset = nvme_l2b(ns, slba); + uint16_t ctrl = le16_to_cpu(rw->control); + uint32_t reftag = le32_to_cpu(rw->reftag); + NvmeBounceContext *ctx = NULL; + uint16_t status; + + trace_pci_nvme_verify(nvme_cid(req), nvme_nsid(ns), slba, nlb); + + if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { + status = nvme_check_prinfo(ns, ctrl, slba, reftag); + if (status) { + return status; + } + + if (ctrl & NVME_RW_PRINFO_PRACT) { + return NVME_INVALID_PROT_INFO | NVME_DNR; + } + } + + status = nvme_check_bounds(ns, slba, nlb); + if (status) { + trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); + return status; + } + + if (NVME_ERR_REC_DULBE(ns->features.err_rec)) { + status = nvme_check_dulbe(ns, slba, nlb); + if (status) { + return status; + } + } + + ctx = g_new0(NvmeBounceContext, 1); + ctx->req = req; + + ctx->data.bounce = g_malloc(len); + + qemu_iovec_init(&ctx->data.iov, 1); + qemu_iovec_add(&ctx->data.iov, ctx->data.bounce, len); + + block_acct_start(blk_get_stats(blk), &req->acct, ctx->data.iov.size, + BLOCK_ACCT_READ); + + req->aiocb = blk_aio_preadv(ns->blkconf.blk, offset, &ctx->data.iov, 0, + nvme_verify_mdata_in_cb, ctx); + return NVME_NO_COMPLETE; +} + static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) { NvmeNamespace *ns = req->ns; @@ -3449,6 +3591,8 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) return nvme_compare(n, req); case NVME_CMD_DSM: return nvme_dsm(n, req); + case NVME_CMD_VERIFY: + return nvme_verify(n, req); case NVME_CMD_COPY: return nvme_copy(n, req); case NVME_CMD_ZONE_MGMT_SEND: @@ -5770,7 +5914,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) id->nn = cpu_to_le32(n->num_namespaces); id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROES | NVME_ONCS_TIMESTAMP | NVME_ONCS_FEATURES | NVME_ONCS_DSM | - NVME_ONCS_COMPARE | NVME_ONCS_COPY); + NVME_ONCS_COMPARE | NVME_ONCS_COPY | + NVME_ONCS_VERIFY); /* * NOTE: If this device ever supports a command set that does NOT use 0x0 diff --git a/hw/block/trace-events b/hw/block/trace-events index fc243d0b4624..72114a5946fc 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -60,6 +60,9 @@ pci_nvme_copy(uint16_t cid, uint32_t nsid, uint16_t nr, uint8_t format) "cid %"P pci_nvme_copy_source_range(uint64_t slba, uint32_t nlb) "slba 0x%"PRIx64" nlb %"PRIu32"" pci_nvme_copy_in_complete(uint16_t cid) "cid %"PRIu16"" pci_nvme_copy_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_verify(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" +pci_nvme_verify_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_verify_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32"" pci_nvme_rw_complete_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" pci_nvme_block_status(int64_t offset, int64_t bytes, int64_t pnum, int ret, bool zeroed) "offset %"PRId64" bytes %"PRId64" pnum %"PRId64" ret 0x%x zeroed %d" pci_nvme_dsm(uint16_t cid, uint32_t nsid, uint32_t nr, uint32_t attr) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu32" attr 0x%"PRIx32"" From patchwork Tue Mar 16 21:47:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 1454319 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=irrelevant.dk header.i=@irrelevant.dk header.a=rsa-sha256 header.s=fm2 header.b=GDjBkgql; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=eltFXmg2; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F0S1V1vPHz9sRR for ; Wed, 17 Mar 2021 09:01:50 +1100 (AEDT) Received: from localhost ([::1]:57826 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMHl5-0000fr-Qo for incoming@patchwork.ozlabs.org; Tue, 16 Mar 2021 18:01:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60476) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXv-00070k-7k; Tue, 16 Mar 2021 17:48:11 -0400 Received: from out5-smtp.messagingengine.com ([66.111.4.29]:53399) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXt-0000yj-7K; Tue, 16 Mar 2021 17:48:11 -0400 Received: from compute2.internal (compute2.nyi.internal [10.202.2.42]) by mailout.nyi.internal (Postfix) with ESMTP id 486015C00DC; Tue, 16 Mar 2021 17:48:08 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Tue, 16 Mar 2021 17:48:08 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=v7R6ji4hmzhu3 WPoc4UYASaZHazKMQsmhFwtwuXaMHI=; b=GDjBkgqlRcrERQDIwXgWX0KlcPvN8 4wGA+BRgwrAtfGeFLKA/P1y/8KQZoCqyIsppgQDVyfj6t2fqchMoOUEBZSVzZ4b3 QmHJPZwsBE93sQfDTJZgUwZ5BmBF5zMWASaZZ+wrgwMIRnA6NyyQmL9fXF0jvY6e J7AZI9+oyiI3XXB5dcpbegc3rowcHqHo4ea7YhG9FbnC8spM1Q3x1DrIZrlal7ui xbywOXrG7NWxO61WvM2JQ6wEoCKT/K0Ip9qAd6VYngb10E6jKhU4Tm1qhMpHSvF+ HmqUiUbKs9Yip8dSO5N2hUvSF+pHr+VRlvliOiaFcgjlWDYrFNQfsIy6g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=v7R6ji4hmzhu3WPoc4UYASaZHazKMQsmhFwtwuXaMHI=; b=eltFXmg2 Ydgm6GyfMgHutfBKgIzadCs4kBY4CjUlq3MoHLK2Bdljipm7k3f/e3x5T9n3ACT2 ZBHEtf6HnKmZj7MIFN6xGYVJeaIidKmJQBfrHNa+D911fs01xIRbuDWYzUED8IZq jNe6pn+s2WK57W81VWLP6gWUh6pEdsBlvywVvTl5KSJaIeu7RBj076bqNAJWEc5x btq1bnnRG7zfRa0am00hPX/rwHtCgvhbcsMcg3nne5eyD+yoOxiwojBMFP9d79vh FrBecZmzQZIuY/frq7but68hQvslRjgYwtyevxDh0BamMg+Mr3CpylrUXrzRNHio dHpNCG6bXK7EUg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrudefvddgudehhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecukfhppeektddrudeijedrleekrdduledtnecuvehluhhsthgvrhfuihiivgepud enucfrrghrrghmpehmrghilhhfrhhomhepihhtshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: from apples.local (80-167-98-190-cable.dk.customer.tdc.net [80.167.98.190]) by mail.messagingengine.com (Postfix) with ESMTPA id E8396108005C; Tue, 16 Mar 2021 17:48:06 -0400 (EDT) From: Klaus Jensen To: Peter Maydell , qemu-devel@nongnu.org Subject: [PULL 07/11] hw/block/nvme: add non-mdts command size limit for verify Date: Tue, 16 Mar 2021 22:47:49 +0100 Message-Id: <20210316214753.399389-8-its@irrelevant.dk> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210316214753.399389-1-its@irrelevant.dk> References: <20210316214753.399389-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.29; envelope-from=its@irrelevant.dk; helo=out5-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Stefan Hajnoczi , Klaus Jensen Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Verify is not subject to MDTS, so a single Verify command may result in excessive amounts of allocated memory. Impose a limit on the data size by adding support for TP 4040 ("Non-MDTS Command Size Limits"). Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme.h | 1 + hw/block/nvme.c | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 11c7fcc317da..7b082212db04 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -26,6 +26,7 @@ typedef struct NvmeParams { uint8_t aerl; uint32_t aer_max_queued; uint8_t mdts; + uint8_t vsl; bool use_intel_id; uint8_t zasl; bool legacy_cmb; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index d754bd8e0440..64cb966ab695 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -23,7 +23,8 @@ * [pmrdev=,] \ * max_ioqpairs=, \ * aerl=,aer_max_queued=, \ - * mdts=,zoned.zasl=, \ + * mdts=,vsl=, \ + * zoned.zasl=, \ * subsys= * -device nvme-ns,drive=,bus=,nsid=,\ * zoned=, \ @@ -78,12 +79,26 @@ * as a power of two (2^n) and is in units of the minimum memory page size * (CAP.MPSMIN). The default value is 7 (i.e. 512 KiB). * + * - `vsl` + * Indicates the maximum data size limit for the Verify command. Like `mdts`, + * this value is specified as a power of two (2^n) and is in units of the + * minimum memory page size (CAP.MPSMIN). The default value is 7 (i.e. 512 + * KiB). + * * - `zoned.zasl` * Indicates the maximum data transfer size for the Zone Append command. Like * `mdts`, the value is specified as a power of two (2^n) and is in units of * the minimum memory page size (CAP.MPSMIN). The default value is 0 (i.e. * defaulting to the value of `mdts`). * + * - `zoned.append_size_limit` + * The maximum I/O size in bytes that is allowed in Zone Append command. + * The default is 128KiB. Since internally this this value is maintained as + * ZASL = log2( / ), some values assigned + * to this property may be rounded down and result in a lower maximum ZA + * data size being in effect. By setting this property to 0, users can make + * ZASL to be equal to MDTS. This property only affects zoned namespaces. + * * nvme namespace device parameters * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * - `subsys` @@ -2544,6 +2559,10 @@ static uint16_t nvme_verify(NvmeCtrl *n, NvmeRequest *req) } } + if (len > n->page_size << n->params.vsl) { + return NVME_INVALID_FIELD | NVME_DNR; + } + status = nvme_check_bounds(ns, slba, nlb); if (status) { trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); @@ -4109,12 +4128,14 @@ static uint16_t nvme_identify_ctrl_csi(NvmeCtrl *n, NvmeRequest *req) { NvmeIdentify *c = (NvmeIdentify *)&req->cmd; uint8_t id[NVME_IDENTIFY_DATA_SIZE] = {}; + NvmeIdCtrlNvm *id_nvm = (NvmeIdCtrlNvm *)&id; trace_pci_nvme_identify_ctrl_csi(c->csi); switch (c->csi) { case NVME_CSI_NVM: - ((NvmeIdCtrlNvm *)&id)->dmrsl = cpu_to_le32(n->dmrsl); + id_nvm->vsl = n->params.vsl; + id_nvm->dmrsl = cpu_to_le32(n->dmrsl); break; case NVME_CSI_ZONED: @@ -5657,6 +5678,11 @@ static void nvme_check_constraints(NvmeCtrl *n, Error **errp) "than or equal to mdts (Maximum Data Transfer Size)"); return; } + + if (!n->params.vsl) { + error_setg(errp, "vsl must be non-zero"); + return; + } } static void nvme_init_state(NvmeCtrl *n) @@ -5914,8 +5940,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) id->nn = cpu_to_le32(n->num_namespaces); id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROES | NVME_ONCS_TIMESTAMP | NVME_ONCS_FEATURES | NVME_ONCS_DSM | - NVME_ONCS_COMPARE | NVME_ONCS_COPY | - NVME_ONCS_VERIFY); + NVME_ONCS_COMPARE | NVME_ONCS_COPY); /* * NOTE: If this device ever supports a command set that does NOT use 0x0 @@ -6058,6 +6083,7 @@ static Property nvme_props[] = { DEFINE_PROP_UINT8("aerl", NvmeCtrl, params.aerl, 3), DEFINE_PROP_UINT32("aer_max_queued", NvmeCtrl, params.aer_max_queued, 64), DEFINE_PROP_UINT8("mdts", NvmeCtrl, params.mdts, 7), + DEFINE_PROP_UINT8("vsl", NvmeCtrl, params.vsl, 7), DEFINE_PROP_BOOL("use-intel-id", NvmeCtrl, params.use_intel_id, false), DEFINE_PROP_BOOL("legacy-cmb", NvmeCtrl, params.legacy_cmb, false), DEFINE_PROP_UINT8("zoned.zasl", NvmeCtrl, params.zasl, 0), From patchwork Tue Mar 16 21:47:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 1454312 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=irrelevant.dk header.i=@irrelevant.dk header.a=rsa-sha256 header.s=fm2 header.b=qMvTCH4v; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=KYnEbb4L; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F0RnJ0Vgvz9sRR for ; Wed, 17 Mar 2021 08:51:14 +1100 (AEDT) Received: from localhost ([::1]:39012 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMHan-0000Su-RQ for incoming@patchwork.ozlabs.org; Tue, 16 Mar 2021 17:51:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60536) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXy-00075L-M2; Tue, 16 Mar 2021 17:48:14 -0400 Received: from new1-smtp.messagingengine.com ([66.111.4.221]:45103) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXw-0000z5-SQ; Tue, 16 Mar 2021 17:48:14 -0400 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailnew.nyi.internal (Postfix) with ESMTP id E4C64580A7B; Tue, 16 Mar 2021 17:48:09 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Tue, 16 Mar 2021 17:48:09 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=8F3ZKsYMEXHk+ 5AdV0um3WvGB+j6ek/Kt6khc+0in98=; b=qMvTCH4vL1oVOtuRtwolzhZm+vfD+ oJh1kZqKVTJwmrhBuehxu+4xwbRu6RKPuyH+RQgNIOLOYhSy9n5b4WtWnrUTph0/ hPgIWpt8ciqzpV37PWAnQJxmnAdgCn4cGpRjsVa97lD3k0FTJsP5vhpBBZpTaE/d VGAe/YcRc4nUwRDaMcSBfQ9ZzZOFittVEAhnsee0bgUrB4LCLKcQSFgu4wb3hJPA 8PXM7fCIGMaVGr/wvUqLSaNT3Fo8OvNOda8Si151La/JgOGeNkNPFgKZl51YMx35 9qND+bwyHqvdPVIiFG899+ZVgPsUeo/xERStwx3WD/aYrm0y/mzmijNow== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=8F3ZKsYMEXHk+5AdV0um3WvGB+j6ek/Kt6khc+0in98=; b=KYnEbb4L OuPi9fxrVYZEdKqqcu0RtENL6vQhKWeQ17hKYnbgPsuasrz9QsCAZJKXAtQojBkR 18OjVijL4tmJv8UaY4lAavc8oPnNDxUJ0K0ixORYGRAKH9ewzUgBy8fcdboBYkKE gi6FsF0YITgBrCJ2vrp0mBlUtDsQEsO+rwQS/T2EnmAOWB5VZ9cJAXA29yxcYjHi cveZLlJGIHl5e4lfPkDBbyYTrFktvl+ZUT4EUkmLFO+Lwt+ybuK71sJZ0lBnbC2B fXqKi7W1CBB+OWZRKbuVavqX8+CUkw1+hhIQkP3hrEMvRS4uJU0zoIoDmK7KJgNC qm6soF6g5cV7/w== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrudefvddgudehhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecukfhppeektddrudeijedrleekrdduledtnecuvehluhhsthgvrhfuihiivgepud enucfrrghrrghmpehmrghilhhfrhhomhepihhtshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: from apples.local (80-167-98-190-cable.dk.customer.tdc.net [80.167.98.190]) by mail.messagingengine.com (Postfix) with ESMTPA id 6954B108005C; Tue, 16 Mar 2021 17:48:08 -0400 (EDT) From: Klaus Jensen To: Peter Maydell , qemu-devel@nongnu.org Subject: [PULL 08/11] hw/block/nvme: support multiple lba formats Date: Tue, 16 Mar 2021 22:47:50 +0100 Message-Id: <20210316214753.399389-9-its@irrelevant.dk> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210316214753.399389-1-its@irrelevant.dk> References: <20210316214753.399389-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.221; envelope-from=its@irrelevant.dk; helo=new1-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Stefan Hajnoczi , Klaus Jensen , Minwoo Im Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Minwoo Im This patch introduces multiple LBA formats supported with the typical logical block sizes of 512 bytes and 4096 bytes as well as metadata sizes of 0, 8, 16 and 64 bytes. The format will be chosed based on the lbads and ms parameters of the nvme-ns device. Signed-off-by: Minwoo Im [k.jensen: resurrected and rebased] Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme-ns.c | 60 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index a082a7004d8e..00e8f6af2162 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -36,13 +36,15 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp) { BlockDriverInfo bdi; NvmeIdNs *id_ns = &ns->id_ns; - int lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas); int npdg, nlbas; + uint8_t ds; + uint16_t ms; + int i; ns->id_ns.dlfeat = 0x1; - id_ns->lbaf[lba_index].ds = 31 - clz32(ns->blkconf.logical_block_size); - id_ns->lbaf[lba_index].ms = ns->params.ms; + ds = 31 - clz32(ns->blkconf.logical_block_size); + ms = ns->params.ms; if (ns->params.ms) { id_ns->mc = 0x3; @@ -53,8 +55,47 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp) id_ns->dpc = 0x1f; id_ns->dps = ((ns->params.pil & 0x1) << 3) | ns->params.pi; + + NvmeLBAF lbaf[16] = { + [0] = { .ds = 9 }, + [1] = { .ds = 9, .ms = 8 }, + [2] = { .ds = 9, .ms = 16 }, + [3] = { .ds = 9, .ms = 64 }, + [4] = { .ds = 12 }, + [5] = { .ds = 12, .ms = 8 }, + [6] = { .ds = 12, .ms = 16 }, + [7] = { .ds = 12, .ms = 64 }, + }; + + memcpy(&id_ns->lbaf, &lbaf, sizeof(lbaf)); + id_ns->nlbaf = 7; + } else { + NvmeLBAF lbaf[16] = { + [0] = { .ds = 9 }, + [1] = { .ds = 12 }, + }; + + memcpy(&id_ns->lbaf, &lbaf, sizeof(lbaf)); + id_ns->nlbaf = 1; } + for (i = 0; i <= id_ns->nlbaf; i++) { + NvmeLBAF *lbaf = &id_ns->lbaf[i]; + if (lbaf->ds == ds) { + if (lbaf->ms == ms) { + id_ns->flbas |= i; + goto lbaf_found; + } + } + } + + /* add non-standard lba format */ + id_ns->nlbaf++; + id_ns->lbaf[id_ns->nlbaf].ds = ds; + id_ns->lbaf[id_ns->nlbaf].ms = ms; + id_ns->flbas |= id_ns->nlbaf; + +lbaf_found: nlbas = nvme_ns_nlbas(ns); id_ns->nsze = cpu_to_le64(nlbas); @@ -244,9 +285,10 @@ static void nvme_ns_zoned_init_state(NvmeNamespace *ns) } } -static void nvme_ns_init_zoned(NvmeNamespace *ns, int lba_index) +static void nvme_ns_init_zoned(NvmeNamespace *ns) { NvmeIdNsZoned *id_ns_z; + int i; nvme_ns_zoned_init_state(ns); @@ -258,9 +300,11 @@ static void nvme_ns_init_zoned(NvmeNamespace *ns, int lba_index) id_ns_z->zoc = 0; id_ns_z->ozcs = ns->params.cross_zone_read ? 0x01 : 0x00; - id_ns_z->lbafe[lba_index].zsze = cpu_to_le64(ns->zone_size); - id_ns_z->lbafe[lba_index].zdes = - ns->params.zd_extension_size >> 6; /* Units of 64B */ + for (i = 0; i <= ns->id_ns.nlbaf; i++) { + id_ns_z->lbafe[i].zsze = cpu_to_le64(ns->zone_size); + id_ns_z->lbafe[i].zdes = + ns->params.zd_extension_size >> 6; /* Units of 64B */ + } ns->csi = NVME_CSI_ZONED; ns->id_ns.nsze = cpu_to_le64(ns->num_zones * ns->zone_size); @@ -367,7 +411,7 @@ int nvme_ns_setup(NvmeNamespace *ns, Error **errp) if (nvme_ns_zoned_check_calc_geometry(ns, errp) != 0) { return -1; } - nvme_ns_init_zoned(ns, 0); + nvme_ns_init_zoned(ns); } return 0; From patchwork Tue Mar 16 21:47:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 1454321 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=irrelevant.dk header.i=@irrelevant.dk header.a=rsa-sha256 header.s=fm2 header.b=xuijtmiG; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=V6idU0J7; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F0S6R1Nncz9sRR for ; Wed, 17 Mar 2021 09:06:07 +1100 (AEDT) Received: from localhost ([::1]:35890 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMHpE-0003kK-JX for incoming@patchwork.ozlabs.org; Tue, 16 Mar 2021 18:06:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60560) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXz-00077x-Pm; Tue, 16 Mar 2021 17:48:15 -0400 Received: from new1-smtp.messagingengine.com ([66.111.4.221]:59793) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXx-000109-9n; Tue, 16 Mar 2021 17:48:15 -0400 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailnew.nyi.internal (Postfix) with ESMTP id 86B05580A4C; Tue, 16 Mar 2021 17:48:11 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Tue, 16 Mar 2021 17:48:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=/H6HKZa/P0P88 Yi6XaWz3bOggBIM5Ew5LY537SqxRzQ=; b=xuijtmiGshwUghkx/cCyK+f16RFpt FUyTmT6FtQOH5r86oa9PUM87VuW1aFA3HkjoC21F6jR7dor5U76xz0oUFFDcGyta UdKoWzeNQSbiFoAkiqfxSIoNk0kV66qMebNm8BlAiXuIQAUj4ZdQRxGLX5ItX53h G/hs3/TGZ4lvUAmKojqxPgJwEHsMu7G+bnSVdMzVoR63tiETjYKpZjbJwynWfm0y k9hTJ604j+xgFgvxQTYgyPmmFyZwC/3AI5HoQCrfPK8oMf0LJWLRxXfOXIE03qzZ /dYimQzhhcEy/hMeGBRCcFEGI53cNJDJLQmIsUI5ZLWU87oKRYdf3aMlA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=/H6HKZa/P0P88Yi6XaWz3bOggBIM5Ew5LY537SqxRzQ=; b=V6idU0J7 L8AmUiod9uHkXnOzx98NmYFj4rGlVRQS/iPmlS368Q6K0Zo+HTEuY35iKaP8Oe/8 vaWGI5OUcbyNTFUKJFtGskWLUQ/1FvW+FOD6ge4uN+8mT/25a+biQnr5AtLpXCr/ 6VKnbPuYB7hH5w0lrshfVQ3OCIWk2WehPxQjU+nHWw7LCOz4LUaegHDgER4CeWA1 1PK4wcczRuSS5yJZk1UVnXUXwK4CN8eIDobH84/ybvgD5NE+Nu9uz581SmYPwj0K NlJL8Kouh6C9aMG9JLAbpl2hR3rHfcw7QR4446GlbJET11btxteAzZQzOYt1UC/F y1SwIhTrz4tI4A== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrudefvddgudehhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecukfhppeektddrudeijedrleekrdduledtnecuvehluhhsthgvrhfuihiivgepud enucfrrghrrghmpehmrghilhhfrhhomhepihhtshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: from apples.local (80-167-98-190-cable.dk.customer.tdc.net [80.167.98.190]) by mail.messagingengine.com (Postfix) with ESMTPA id 0749C108005C; Tue, 16 Mar 2021 17:48:09 -0400 (EDT) From: Klaus Jensen To: Peter Maydell , qemu-devel@nongnu.org Subject: [PULL 09/11] hw/block/nvme: prefer runtime helpers instead of device parameters Date: Tue, 16 Mar 2021 22:47:51 +0100 Message-Id: <20210316214753.399389-10-its@irrelevant.dk> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210316214753.399389-1-its@irrelevant.dk> References: <20210316214753.399389-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.221; envelope-from=its@irrelevant.dk; helo=new1-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Minwoo Im , Stefan Hajnoczi , Klaus Jensen Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen In preparation for Format NVM support, use runtime helpers instead of the constant device parameters when getting lba size information etc. Signed-off-by: Klaus Jensen Reviewed-by: Minwoo Im --- hw/block/nvme-ns.h | 2 +- hw/block/nvme-ns.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index e2f53d999699..07e16880801d 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -138,7 +138,7 @@ static inline bool nvme_ns_ext(NvmeNamespace *ns) /* calculate the number of LBAs that the namespace can accomodate */ static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns) { - if (ns->params.ms) { + if (nvme_msize(ns)) { return ns->size / (nvme_lsize(ns) + nvme_msize(ns)); } return ns->size >> nvme_ns_lbads(ns); diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 00e8f6af2162..7e3cba55e4db 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -110,11 +110,11 @@ lbaf_found: /* support DULBE and I/O optimization fields */ id_ns->nsfeat |= (0x4 | 0x10); - npdg = ns->blkconf.discard_granularity / ns->blkconf.logical_block_size; + npdg = ns->blkconf.discard_granularity / nvme_lsize(ns); if (bdrv_get_info(blk_bs(ns->blkconf.blk), &bdi) >= 0 && bdi.cluster_size > ns->blkconf.discard_granularity) { - npdg = bdi.cluster_size / ns->blkconf.logical_block_size; + npdg = bdi.cluster_size / nvme_lsize(ns); } id_ns->npda = id_ns->npdg = npdg - 1; @@ -161,7 +161,7 @@ static int nvme_ns_init_blk(NvmeNamespace *ns, Error **errp) static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp) { uint64_t zone_size, zone_cap; - uint32_t lbasz = ns->blkconf.logical_block_size; + uint32_t lbasz = nvme_lsize(ns); /* Make sure that the values of ZNS properties are sane */ if (ns->params.zone_size_bs) { From patchwork Tue Mar 16 21:47:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 1454325 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=irrelevant.dk header.i=@irrelevant.dk header.a=rsa-sha256 header.s=fm2 header.b=IRRFh3hQ; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=RkmwPrRa; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F0SCy0CJPz9sRR for ; Wed, 17 Mar 2021 09:10:54 +1100 (AEDT) Received: from localhost ([::1]:46006 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMHtr-0008CI-Sr for incoming@patchwork.ozlabs.org; Tue, 16 Mar 2021 18:10:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60582) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHY1-0007B8-4c; Tue, 16 Mar 2021 17:48:17 -0400 Received: from new1-smtp.messagingengine.com ([66.111.4.221]:44239) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHXx-00010o-Sz; Tue, 16 Mar 2021 17:48:16 -0400 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailnew.nyi.internal (Postfix) with ESMTP id 21F69580A76; Tue, 16 Mar 2021 17:48:13 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Tue, 16 Mar 2021 17:48:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=T23YrOp/speKd jcX67s/LEXoUYiRjWTWXjYsdg7FdZc=; b=IRRFh3hQpH1CIHzhDtkF8I+yhdlvS tHIQ8mCoFKga227haG8EWynRC4s2S5y/SXC9Vny24wmJugkxbpHinRz37xGePacm m9cSlA8h5/N+dbX56rjsDbUpS0sx66yAdciCxauxRvoUfAhr3PO7gFFRv+gUndRq m8do0bf2ik+gp9ShZkgHU5zC0R58Klp/VCnLlP3z95BIiWT6a5e0bkux/EKYdsdP nZzCZM5QBDcwFTxF1ByI2aAyWAobSHemrgb6arMyy4OWFRpeM55hCaO0plVeKQzg isuAwXojErqsvGyrDNyP24YBC/8+aytWcJrcvd3eoemjPtolhKL0lUdNA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=T23YrOp/speKdjcX67s/LEXoUYiRjWTWXjYsdg7FdZc=; b=RkmwPrRa rEyjYfJmWjff2cWZTjYy2cUa/wICa9JebsPS/8o/3kUz7dGi3t3PRSW/Z3lXeTR5 MmVl0eEjJYyi5gti/dEcncIxYmIQfvnCNAvD26C9Gw1fsWeCphnKCWS/hHGbQDB6 mG4ToyPWwRnxDgD00y6c2ROyDTVsSZH1fjWAs4FqkaeqhPoe7qIQb8kb8BieeCSV KfKqoVpk70HKVZxv8jvf56BVNDgQpkkfLh1iM/uV0CnNzTLevCylrzBuSAECRKcS V2z8JjO3KNIlpfs2JBgHHzKMPfOi1xzYlEDPqFZlSU44O5TbnRerBdAUdM6yuXxX eBiL8AtdZvePuA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrudefvddgudehhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecukfhppeektddrudeijedrleekrdduledtnecuvehluhhsthgvrhfuihiivgepfe enucfrrghrrghmpehmrghilhhfrhhomhepihhtshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: from apples.local (80-167-98-190-cable.dk.customer.tdc.net [80.167.98.190]) by mail.messagingengine.com (Postfix) with ESMTPA id 99020108005C; Tue, 16 Mar 2021 17:48:11 -0400 (EDT) From: Klaus Jensen To: Peter Maydell , qemu-devel@nongnu.org Subject: [PULL 10/11] hw/block/nvme: pull lba format initialization Date: Tue, 16 Mar 2021 22:47:52 +0100 Message-Id: <20210316214753.399389-11-its@irrelevant.dk> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210316214753.399389-1-its@irrelevant.dk> References: <20210316214753.399389-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.221; envelope-from=its@irrelevant.dk; helo=new1-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Minwoo Im , Stefan Hajnoczi , Klaus Jensen Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Pull lba format initialization code into separate function in preparation for Format NVM support. Signed-off-by: Klaus Jensen Reviewed-by: Minwoo Im --- hw/block/nvme-ns.c | 74 +++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 7e3cba55e4db..1e8ef36ba5ae 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -32,17 +32,55 @@ #define MIN_DISCARD_GRANULARITY (4 * KiB) +static void nvme_ns_init_format(NvmeNamespace *ns) +{ + NvmeIdNs *id_ns = &ns->id_ns; + BlockDriverInfo bdi; + int npdg, nlbas, ret; + + nlbas = nvme_ns_nlbas(ns); + + id_ns->nsze = cpu_to_le64(nlbas); + + /* no thin provisioning */ + id_ns->ncap = id_ns->nsze; + id_ns->nuse = id_ns->ncap; + + ns->mdata_offset = nvme_l2b(ns, nlbas); + + npdg = ns->blkconf.discard_granularity / nvme_lsize(ns); + + ret = bdrv_get_info(blk_bs(ns->blkconf.blk), &bdi); + if (ret >= 0 && bdi.cluster_size > ns->blkconf.discard_granularity) { + npdg = bdi.cluster_size / nvme_lsize(ns); + } + + id_ns->npda = id_ns->npdg = npdg - 1; +} + static int nvme_ns_init(NvmeNamespace *ns, Error **errp) { - BlockDriverInfo bdi; NvmeIdNs *id_ns = &ns->id_ns; - int npdg, nlbas; uint8_t ds; uint16_t ms; int i; + ns->csi = NVME_CSI_NVM; + ns->id_ns.dlfeat = 0x1; + /* support DULBE and I/O optimization fields */ + id_ns->nsfeat |= (0x4 | 0x10); + + if (nvme_ns_shared(ns)) { + id_ns->nmic |= NVME_NMIC_NS_SHARED; + } + + /* simple copy */ + id_ns->mssrl = cpu_to_le16(ns->params.mssrl); + id_ns->mcl = cpu_to_le32(ns->params.mcl); + id_ns->msrc = ns->params.msrc; + ds = 31 - clz32(ns->blkconf.logical_block_size); ms = ns->params.ms; @@ -96,37 +134,7 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp) id_ns->flbas |= id_ns->nlbaf; lbaf_found: - nlbas = nvme_ns_nlbas(ns); - - id_ns->nsze = cpu_to_le64(nlbas); - ns->mdata_offset = nvme_l2b(ns, nlbas); - - ns->csi = NVME_CSI_NVM; - - /* no thin provisioning */ - id_ns->ncap = id_ns->nsze; - id_ns->nuse = id_ns->ncap; - - /* support DULBE and I/O optimization fields */ - id_ns->nsfeat |= (0x4 | 0x10); - - npdg = ns->blkconf.discard_granularity / nvme_lsize(ns); - - if (bdrv_get_info(blk_bs(ns->blkconf.blk), &bdi) >= 0 && - bdi.cluster_size > ns->blkconf.discard_granularity) { - npdg = bdi.cluster_size / nvme_lsize(ns); - } - - id_ns->npda = id_ns->npdg = npdg - 1; - - if (nvme_ns_shared(ns)) { - id_ns->nmic |= NVME_NMIC_NS_SHARED; - } - - /* simple copy */ - id_ns->mssrl = cpu_to_le16(ns->params.mssrl); - id_ns->mcl = cpu_to_le32(ns->params.mcl); - id_ns->msrc = ns->params.msrc; + nvme_ns_init_format(ns); return 0; } From patchwork Tue Mar 16 21:47:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 1454331 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=irrelevant.dk header.i=@irrelevant.dk header.a=rsa-sha256 header.s=fm2 header.b=u5n1+TYY; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm2 header.b=I26vdvAh; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F0SLt2cyCz9sVb for ; Wed, 17 Mar 2021 09:16:54 +1100 (AEDT) Received: from localhost ([::1]:34620 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMHzg-0006yB-5V for incoming@patchwork.ozlabs.org; Tue, 16 Mar 2021 18:16:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60606) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHY2-0007FI-Vh; Tue, 16 Mar 2021 17:48:19 -0400 Received: from new1-smtp.messagingengine.com ([66.111.4.221]:59695) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMHY0-00012q-KG; Tue, 16 Mar 2021 17:48:18 -0400 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailnew.nyi.internal (Postfix) with ESMTP id C1523580A4C; Tue, 16 Mar 2021 17:48:15 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Tue, 16 Mar 2021 17:48:15 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=irrelevant.dk; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=WoE/sX9J+0qD/ kEuH3GUilv3Cb4Cd0xi/xvOGKnKYTU=; b=u5n1+TYYMNVJD/I41YreMTzNykEfC 64v08yENR1C3MP9zJParrdBratJxazg1oHqtFjmq5MxV2/tC97ZTLHXs0tblxTss +DLXygTVs1ESWVIpO8CPuB9kqRdqj3pAI5iY6WuFD6b8BSubTAFIFvDTu56wR0K/ kNq/4XJmDPlhxPdwzG5AoUUlMs4+sSd1Z3Q+9R7YMDGV6YBlHLazxE1/Gf7l38Qw f7SlVp4evpfxzw74fUYUVDj/LXkM2tvfHWwadK53rFXQ5Ji7pr6ygM5FEIpW2yOH fmruyIrHDxK3f8cek/hN5Q7wcCyf2WTrm5aWMQpJOmerYl6vDaMSfZUvw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; bh=WoE/sX9J+0qD/kEuH3GUilv3Cb4Cd0xi/xvOGKnKYTU=; b=I26vdvAh /iZyka8hWFySR2TUgt8VnxpQ4u2j4ve2rjm3Pwjd2T4OuADiuh2x7eaI4BDwSvji XKsQneo4U13kPNVN9FhfmEpJpSYSZFhDMnficzhQ24ej4QiLolqrlBEjWcSxtvjy +rmzUlHdRiYgZk8kId0D86nFC1ACE6m1T3I9wxkmVziv6ilAeuP4tWfINaUH1puL lu3dxKCuubgDb/B5g/87BR289/kndyyA8HJGoDDrp02bRVBjTo2XFzML9Lnz3DE9 HESXmxOkzGFR/wEEyebYudnNuhF3hZV0VXDYFjGZxLqupmGJRAxTlRVi3CnSfO1b Lp+rW0sC0du3pA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrudefvddgudehhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepueelteegieeuhffgkeefgfevjeeigfetkeeitdfgtdeifefhtdfhfeeuffev gfeknecukfhppeektddrudeijedrleekrdduledtnecuvehluhhsthgvrhfuihiivgepfe enucfrrghrrghmpehmrghilhhfrhhomhepihhtshesihhrrhgvlhgvvhgrnhhtrdgukh X-ME-Proxy: Received: from apples.local (80-167-98-190-cable.dk.customer.tdc.net [80.167.98.190]) by mail.messagingengine.com (Postfix) with ESMTPA id 35102108005C; Tue, 16 Mar 2021 17:48:13 -0400 (EDT) From: Klaus Jensen To: Peter Maydell , qemu-devel@nongnu.org Subject: [PULL 11/11] hw/block/nvme: add support for the format nvm command Date: Tue, 16 Mar 2021 22:47:53 +0100 Message-Id: <20210316214753.399389-12-its@irrelevant.dk> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210316214753.399389-1-its@irrelevant.dk> References: <20210316214753.399389-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.221; envelope-from=its@irrelevant.dk; helo=new1-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , qemu-block@nongnu.org, Klaus Jensen , Gollu Appalanaidu , Max Reitz , Keith Busch , Stefan Hajnoczi , Klaus Jensen , Minwoo Im Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Minwoo Im Format NVM admin command can make a namespace or namespaces to be with different LBA size and metadata size with protection information types. This patch introduces Format NVM command with LBA format, Metadata, and Protection Information for the device. The secure erase operation things and support for formatting zoned namespaces are yet to be added. The parameter checks inside of this patch has been referred from Keith's old branch. Signed-off-by: Minwoo Im [anaidu.gollu: rebased on e2e] Signed-off-by: Gollu Appalanaidu [k.jensen: rebased for reworked aio tracking] Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme-ns.h | 7 ++ hw/block/nvme.h | 1 + include/block/nvme.h | 1 + hw/block/nvme-ns.c | 3 +- hw/block/nvme.c | 175 +++++++++++++++++++++++++++++++++++++++++- hw/block/trace-events | 3 + 6 files changed, 188 insertions(+), 2 deletions(-) diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index 07e16880801d..9ab7894fc83e 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -59,6 +59,7 @@ typedef struct NvmeNamespace { NvmeIdNs id_ns; const uint32_t *iocs; uint8_t csi; + uint16_t status; NvmeSubsystem *subsys; QTAILQ_ENTRY(NvmeNamespace) entry; @@ -84,6 +85,11 @@ typedef struct NvmeNamespace { } features; } NvmeNamespace; +static inline uint16_t nvme_ns_status(NvmeNamespace *ns) +{ + return ns->status; +} + static inline uint32_t nvme_nsid(NvmeNamespace *ns) { if (ns) { @@ -218,6 +224,7 @@ static inline void nvme_aor_dec_active(NvmeNamespace *ns) assert(ns->nr_active_zones >= 0); } +void nvme_ns_init_format(NvmeNamespace *ns); int nvme_ns_setup(NvmeNamespace *ns, Error **errp); void nvme_ns_drain(NvmeNamespace *ns); void nvme_ns_shutdown(NvmeNamespace *ns); diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 7b082212db04..5b0031b11db2 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -86,6 +86,7 @@ static inline const char *nvme_adm_opc_str(uint8_t opc) case NVME_ADM_CMD_SET_FEATURES: return "NVME_ADM_CMD_SET_FEATURES"; case NVME_ADM_CMD_GET_FEATURES: return "NVME_ADM_CMD_GET_FEATURES"; case NVME_ADM_CMD_ASYNC_EV_REQ: return "NVME_ADM_CMD_ASYNC_EV_REQ"; + case NVME_ADM_CMD_FORMAT_NVM: return "NVME_ADM_CMD_FORMAT_NVM"; default: return "NVME_ADM_CMD_UNKNOWN"; } } diff --git a/include/block/nvme.h b/include/block/nvme.h index ba757b32dbb7..b0a4e4291611 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -828,6 +828,7 @@ enum NvmeStatusCodes { NVME_CAP_EXCEEDED = 0x0081, NVME_NS_NOT_READY = 0x0082, NVME_NS_RESV_CONFLICT = 0x0083, + NVME_FORMAT_IN_PROGRESS = 0x0084, NVME_INVALID_CQID = 0x0100, NVME_INVALID_QID = 0x0101, NVME_MAX_QSIZE_EXCEEDED = 0x0102, diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 1e8ef36ba5ae..7f8d139a8663 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -32,7 +32,7 @@ #define MIN_DISCARD_GRANULARITY (4 * KiB) -static void nvme_ns_init_format(NvmeNamespace *ns) +void nvme_ns_init_format(NvmeNamespace *ns) { NvmeIdNs *id_ns = &ns->id_ns; BlockDriverInfo bdi; @@ -66,6 +66,7 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp) int i; ns->csi = NVME_CSI_NVM; + ns->status = 0x0; ns->id_ns.dlfeat = 0x1; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 64cb966ab695..6842b01ab58b 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -213,6 +213,7 @@ static const uint32_t nvme_cse_acs[256] = { [NVME_ADM_CMD_GET_FEATURES] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_ASYNC_EV_REQ] = NVME_CMD_EFF_CSUPP, [NVME_ADM_CMD_NS_ATTACHMENT] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_NIC, + [NVME_ADM_CMD_FORMAT_NVM] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, }; static const uint32_t nvme_cse_iocs_none[256]; @@ -1866,6 +1867,42 @@ out: nvme_rw_complete_cb(req, ret); } +struct nvme_aio_format_ctx { + NvmeRequest *req; + NvmeNamespace *ns; + + /* number of outstanding write zeroes for this namespace */ + int *count; +}; + +static void nvme_aio_format_cb(void *opaque, int ret) +{ + struct nvme_aio_format_ctx *ctx = opaque; + NvmeRequest *req = ctx->req; + NvmeNamespace *ns = ctx->ns; + uintptr_t *num_formats = (uintptr_t *)&req->opaque; + int *count = ctx->count; + + g_free(ctx); + + if (ret) { + nvme_aio_err(req, ret); + } + + if (--(*count)) { + return; + } + + g_free(count); + ns->status = 0x0; + + if (--(*num_formats)) { + return; + } + + nvme_enqueue_req_completion(nvme_cq(req), req); +} + struct nvme_aio_flush_ctx { NvmeRequest *req; NvmeNamespace *ns; @@ -3556,6 +3593,7 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req) static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) { uint32_t nsid = le32_to_cpu(req->cmd.nsid); + uint16_t status; trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req), req->cmd.opcode, nvme_io_opc_str(req->cmd.opcode)); @@ -3597,6 +3635,11 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) return NVME_INVALID_OPCODE | NVME_DNR; } + status = nvme_ns_status(req->ns); + if (unlikely(status)) { + return status; + } + switch (req->cmd.opcode) { case NVME_CMD_WRITE_ZEROES: return nvme_write_zeroes(n, req); @@ -4898,6 +4941,134 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req) return NVME_SUCCESS; } +static uint16_t nvme_format_ns(NvmeCtrl *n, NvmeNamespace *ns, uint8_t lbaf, + uint8_t mset, uint8_t pi, uint8_t pil, + NvmeRequest *req) +{ + int64_t len, offset; + struct nvme_aio_format_ctx *ctx; + BlockBackend *blk = ns->blkconf.blk; + uint16_t ms; + uintptr_t *num_formats = (uintptr_t *)&req->opaque; + int *count; + + if (ns->params.zoned) { + return NVME_INVALID_FORMAT | NVME_DNR; + } + + trace_pci_nvme_format_ns(nvme_cid(req), nvme_nsid(ns), lbaf, mset, pi, pil); + + if (lbaf > ns->id_ns.nlbaf) { + return NVME_INVALID_FORMAT | NVME_DNR; + } + + ms = ns->id_ns.lbaf[lbaf].ms; + + if (pi && (ms < sizeof(NvmeDifTuple))) { + return NVME_INVALID_FORMAT | NVME_DNR; + } + + if (pi && pi > NVME_ID_NS_DPS_TYPE_3) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + nvme_ns_drain(ns); + nvme_ns_shutdown(ns); + nvme_ns_cleanup(ns); + + ns->id_ns.dps = (pil << 3) | pi; + ns->id_ns.flbas = lbaf | (mset << 4); + + nvme_ns_init_format(ns); + + ns->status = NVME_FORMAT_IN_PROGRESS; + + len = ns->size; + offset = 0; + + count = g_new(int, 1); + *count = 1; + + (*num_formats)++; + + while (len) { + ctx = g_new(struct nvme_aio_format_ctx, 1); + ctx->req = req; + ctx->ns = ns; + ctx->count = count; + + size_t bytes = MIN(BDRV_REQUEST_MAX_BYTES, len); + + (*count)++; + + blk_aio_pwrite_zeroes(blk, offset, bytes, BDRV_REQ_MAY_UNMAP, + nvme_aio_format_cb, ctx); + + offset += bytes; + len -= bytes; + + } + + (*count)--; + + return NVME_NO_COMPLETE; +} + +static uint16_t nvme_format(NvmeCtrl *n, NvmeRequest *req) +{ + NvmeNamespace *ns; + uint32_t dw10 = le32_to_cpu(req->cmd.cdw10); + uint32_t nsid = le32_to_cpu(req->cmd.nsid); + uint8_t lbaf = dw10 & 0xf; + uint8_t mset = (dw10 >> 4) & 0x1; + uint8_t pi = (dw10 >> 5) & 0x7; + uint8_t pil = (dw10 >> 8) & 0x1; + uintptr_t *num_formats = (uintptr_t *)&req->opaque; + uint16_t status; + int i; + + trace_pci_nvme_format(nvme_cid(req), nsid, lbaf, mset, pi, pil); + + /* 1-initialize; see the comment in nvme_dsm */ + *num_formats = 1; + + if (nsid != NVME_NSID_BROADCAST) { + if (!nvme_nsid_valid(n, nsid)) { + return NVME_INVALID_NSID | NVME_DNR; + } + + ns = nvme_ns(n, nsid); + if (!ns) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + status = nvme_format_ns(n, ns, lbaf, mset, pi, pil, req); + if (status && status != NVME_NO_COMPLETE) { + req->status = status; + } + } else { + for (i = 1; i <= n->num_namespaces; i++) { + ns = nvme_ns(n, i); + if (!ns) { + continue; + } + + status = nvme_format_ns(n, ns, lbaf, mset, pi, pil, req); + if (status && status != NVME_NO_COMPLETE) { + req->status = status; + break; + } + } + } + + /* account for the 1-initialization */ + if (--(*num_formats)) { + return NVME_NO_COMPLETE; + } + + return req->status; +} + static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req) { trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), req->cmd.opcode, @@ -4936,6 +5107,8 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req) return nvme_aer(n, req); case NVME_ADM_CMD_NS_ATTACHMENT: return nvme_ns_attachment(n, req); + case NVME_ADM_CMD_FORMAT_NVM: + return nvme_format(n, req); default: assert(false); } @@ -5912,7 +6085,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) id->mdts = n->params.mdts; id->ver = cpu_to_le32(NVME_SPEC_VER); - id->oacs = cpu_to_le16(NVME_OACS_NS_MGMT); + id->oacs = cpu_to_le16(NVME_OACS_NS_MGMT | NVME_OACS_FORMAT); id->cntrltype = 0x1; /* diff --git a/hw/block/trace-events b/hw/block/trace-events index 72114a5946fc..b71cf7a08755 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -41,6 +41,9 @@ pci_nvme_map_sgl(uint8_t typ, uint64_t len) "type 0x%"PRIx8" len %"PRIu64"" pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" nsid %"PRIu32" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'" pci_nvme_admin_cmd(uint16_t cid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'" pci_nvme_flush(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" +pci_nvme_format(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8"" +pci_nvme_format_ns(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8"" +pci_nvme_format_cb(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" pci_nvme_read(uint16_t cid, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" pci_nvme_write(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"