From patchwork Thu Sep 24 20:45:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 304474 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A2F79C4363D for ; Thu, 24 Sep 2020 20:56:29 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id E1075221EB for ; Thu, 24 Sep 2020 20:56:28 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E1075221EB Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:57920 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYHz-0002Gy-EA for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 16:56:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38504) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7M-0004Pq-Up; Thu, 24 Sep 2020 16:45:28 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:34723) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7J-0007gP-BF; Thu, 24 Sep 2020 16:45:28 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id A055058050A; Thu, 24 Sep 2020 16:45:22 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:22 -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=fm1; bh=1QikJUcbsmo2U P6Df439yCuIR8yF+wYrAAq6TthCldM=; b=RBxRamU4/6xEzn9ZzUj4g0mkBznFG MI30IndJOKgA3UeSjoo1w1hC8VhHpKhurbHUK4d2TTaLoWtph0+xut/8Y4WkHU5A 0bI9ckGOAOjqj8wA+6ySsbKf8D/eUPvgTMSRp8c1gGqby2epw1lAMpTDjzAXpTbO OqkBFMJDioYx6Ny58c2QgeAIoYIsTIfKgflP3/dLntuhbL2Rjj2nEFbjQTj8HNP7 XIodnANutTEO9efrZ5q8xbgnJnYSfhtAIxjNlijXQRScPYxzQ9jEytJ19P2LioXO D179O1ocgeVj5sk759u+1v9LSAYYi7pmA0ifvWEGUX+bdoqjFXeN7JnHw== 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= fm3; bh=1QikJUcbsmo2UP6Df439yCuIR8yF+wYrAAq6TthCldM=; b=VNGqAy04 n2J6TDcgqBurMHtkvWxJN7bS/6pLst96EJZaAKZQAbMwUOePP1ieC1Dab9gD37TN JbBaZG9rG6jLoh47NZcee7wenpWvB5YgnayWN2hMemVDP9AH3LTRjIb+dp+Orl/P GqFdBaoZJwtJ56Dv48aSGCH1Tqec/g2UI9EkdoDLVDOCyv7SRmfPDbp4nfkSsN+N H1jXNqR+yDpRpJ2B/Aujyf1SIkHFK4EFUzdF/QsFbX4IrI3cCRBJnusJyke5uwlV THk86IW5zT5JOooka65ARCZCGfbVTXdJZUXIjQzkJ7PHZnPeWfl7YxsOqJ6a6iJa Uuu6VwKrGa+U6w== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeeuleetgeeiuefhgfekfefgveejiefgteekiedtgfdtieefhfdthfefueffvefg keenucfkphepkedtrdduieejrdelkedrudeltdenucevlhhushhtvghrufhiiigvpedtne curfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirhhrvghlvghvrghnthdrughk 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 49A663064685; Thu, 24 Sep 2020 16:45:19 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 01/16] hw/block/nvme: add nsid to get/setfeat trace events Date: Thu, 24 Sep 2020 22:45:01 +0200 Message-Id: <20200924204516.1881843-2-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Include the namespace id in the pci_nvme_{get,set}feat trace events. Signed-off-by: Klaus Jensen --- hw/block/nvme.c | 4 ++-- hw/block/trace-events | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index da8344f196a8..84b6b516fa7b 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1660,7 +1660,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req) [NVME_ARBITRATION] = NVME_ARB_AB_NOLIMIT, }; - trace_pci_nvme_getfeat(nvme_cid(req), fid, sel, dw11); + trace_pci_nvme_getfeat(nvme_cid(req), nsid, fid, sel, dw11); if (!nvme_feature_support[fid]) { return NVME_INVALID_FIELD | NVME_DNR; @@ -1798,7 +1798,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) uint8_t fid = NVME_GETSETFEAT_FID(dw10); uint8_t save = NVME_SETFEAT_SAVE(dw10); - trace_pci_nvme_setfeat(nvme_cid(req), fid, save, dw11); + trace_pci_nvme_setfeat(nvme_cid(req), nsid, fid, save, dw11); if (save) { return NVME_FID_NOT_SAVEABLE | NVME_DNR; diff --git a/hw/block/trace-events b/hw/block/trace-events index 446cca08e9ab..5a239b80bf36 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -53,8 +53,8 @@ pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32"" pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32"" pci_nvme_identify_ns_descr_list(uint32_t ns) "nsid %"PRIu32"" pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64"" -pci_nvme_getfeat(uint16_t cid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32"" -pci_nvme_setfeat(uint16_t cid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32"" +pci_nvme_getfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32"" +pci_nvme_setfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32"" pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s" pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d" pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d" From patchwork Thu Sep 24 20:45:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 304476 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 538E0C4363D for ; Thu, 24 Sep 2020 20:50:04 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id A7C4C221EB for ; Thu, 24 Sep 2020 20:50:03 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A7C4C221EB Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:49368 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYBm-00071m-BB for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 16:50:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38470) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7L-0004Oq-IN; Thu, 24 Sep 2020 16:45:27 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:50925) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7J-0007gQ-BE; Thu, 24 Sep 2020 16:45:27 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id 9BC2A580508; Thu, 24 Sep 2020 16:45:22 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:22 -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=fm1; bh=+Fjf+ehIwJaI4 71JRdnpqYu38GUIs8qKDBklTJPNZG4=; b=jLQ/bx+UwCp7D9LOj9aglUzUOBwzU y7HWrxuNtQQmgyTN6/dcr3BV7KvMX609hjJgHlrdIit/AnPP6YKph0M9RLe69b95 6QIu1TFcTuV1I1x1c0OS8sef05mCjxuQJlyRe1flbW5a3nqa3LkjSf90LAqT8r1H KURNFI5zRZ3zn9qj50VEpGyjgNtW8F53JqhArzgwVNQJ8VDyEWNqKGmafViteIDx TtY9idC9wMrwkS1DPWDKmkLxpeM/2GivFHWfyOLsx2yt4AgCaD/dG++Bvj8ZZKpi IVF/h2nCGTOo9hCbu+BgqWWFZSHq6RM1d4boJ5epqTJdDkyq2vbXYTNMQ== 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= fm3; bh=+Fjf+ehIwJaI471JRdnpqYu38GUIs8qKDBklTJPNZG4=; b=kYceSFdx N6MbqYb73Pmh34uO/WO5cfXaV0ks9m5/ND0Lk06KR/Q01IPmsVLWoCWqXkdXMWAF eAapO7u2oBNRLYQo+qOY2Lrd2JjEx4Wr7+/x/udCEuKTPKmDZpM1ouovC4MfWPFm 5IuqAKzYHFnO7mEnjWGJH+FPHl/KAAiN9iP2SfsIJCxMwIYEwEI/30Vv8LiElrWx gjLvjeKQHUtsgjl/aFqEUf7YB/016YWsjnMo2PqTfBYUctgmbQoSa427tc8IQ6od 0NbulYdzvNPUCQwFWpIb1u6FJ7sNdyCgxLu8kvu69OvOmbCP3LkIMTi1DWo0EhmJ 9DGwljEzXYDhZQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeeuleetgeeiuefhgfekfefgveejiefgteekiedtgfdtieefhfdthfefueffvefg keenucfkphepkedtrdduieejrdelkedrudeltdenucevlhhushhtvghrufhiiigvpedtne curfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirhhrvghlvghvrghnthdrughk 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 950F8306467D; Thu, 24 Sep 2020 16:45:20 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 02/16] hw/block/nvme: add trace event for requests with non-zero status code Date: Thu, 24 Sep 2020 22:45:02 +0200 Message-Id: <20200924204516.1881843-3-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen If a command results in a non-zero status code, trace it. Signed-off-by: Klaus Jensen --- hw/block/nvme.c | 6 ++++++ hw/block/trace-events | 1 + 2 files changed, 7 insertions(+) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 84b6b516fa7b..3cbc3c7b75b1 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -777,6 +777,12 @@ static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req) assert(cq->cqid == req->sq->cqid); trace_pci_nvme_enqueue_req_completion(nvme_cid(req), cq->cqid, req->status); + + if (req->status) { + trace_pci_nvme_err_req_status(nvme_cid(req), nvme_nsid(req->ns), + req->status, req->cmd.opcode); + } + QTAILQ_REMOVE(&req->sq->out_req_list, req, entry); QTAILQ_INSERT_TAIL(&cq->req_list, req, entry); timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500); diff --git a/hw/block/trace-events b/hw/block/trace-events index 5a239b80bf36..9e7507c5abde 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -89,6 +89,7 @@ pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" # nvme traces for error conditions pci_nvme_err_mdts(uint16_t cid, size_t len) "cid %"PRIu16" len %zu" +pci_nvme_err_req_status(uint16_t cid, uint32_t nsid, uint16_t status, uint8_t opc) "cid %"PRIu16" nsid %"PRIu32" status 0x%"PRIx16" opc 0x%"PRIx8"" pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64"" pci_nvme_err_addr_write(uint64_t addr) "addr 0x%"PRIx64"" pci_nvme_err_cfs(void) "controller fatal status" From patchwork Thu Sep 24 20:45:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 304472 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B4317C4363D for ; Thu, 24 Sep 2020 21:02:50 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id E263422208 for ; Thu, 24 Sep 2020 21:02:49 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E263422208 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:37940 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYO8-0005tP-Nw for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 17:02:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38524) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7O-0004RD-1f; Thu, 24 Sep 2020 16:45:30 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:54601) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7J-0007h9-O9; Thu, 24 Sep 2020 16:45:29 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id AE0F558050C; Thu, 24 Sep 2020 16:45:23 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:23 -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=fm1; bh= qEKNIM+lPRA0c0RxRX/s4SVmBXPBiqyjUZhRX090gXI=; b=mFIKeNALOPJUzzRw iQmgnHbCruZbtxHZ557Ki9T2Dga7uvYIdf7IJyunEHhYJvfawD+lBR1h8hi+vi0U Sgmfnu/1BnemS7q5DnipzX2wO4tGWuYT7Q/rDU9e4zhi33zjlGf7KSIdfOXc4MVM GPED2AcPoApQFkEMtXqYjiAUmIOGPzVallmizORUeQI/OqIkm2qmP3JKAsgbVqIZ rqrdJVd+uIQjSxo1+AsXcHd95utdTNPkOJsNOlVzav3bJalt/9/tCnyzB9K/8Ps7 j4niKCZzRlL0yode+N5vSJIkwPEfeW3JAkesgXh3JdlplEc7vVNywlSPo7WI87LN e9wA8g== 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=fm3; bh=qEKNIM+lPRA0c0RxRX/s4SVmBXPBiqyjUZhRX090g XI=; b=AhE/dRdrkdAkBngThpoY6CKJWUUXmMoY4KWrDhw6ZYIqSoyo/dY1564MN tkYiYiQTf1J0oVQuUSd8IgbuRk4XrPd7CqEVUXMjinlUtzZ+np1B7R6dHnt7fplH uQoOz9zK6ay1VPxPQv2L91z0pB0tcGhkf/MLmX4APIXzjJIfsNWxR2kvMW2DxPKi x6vrYWd1VmdIAawCqr5OFnZtUBOeNbmitZYagGKtTTrlcbmcrnrtgDl5ZNMD7PA5 duZsaqUkdfsHgYaOJXJ/VSZWdOHn16DdZpjekY3ri4Uju0Ql8RzPPfTm3cHM/8xx cAxS/u9GeRI4hmTTfPASsVksj9lJg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfgggtgfesthekredtredtjeenucfhrhhomhepmfhlrghu shculfgvnhhsvghnuceoihhtshesihhrrhgvlhgvvhgrnhhtrdgukheqnecuggftrfgrth htvghrnhepteevuedugeevieehgeeileeufeetvddtkeetfeelgeehudfhjeeuledvhfff tdegnecukfhppeektddrudeijedrleekrdduledtnecuvehluhhsthgvrhfuihiivgeptd 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 D8F443064682; Thu, 24 Sep 2020 16:45:21 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 03/16] hw/block/nvme: make lba data size configurable Date: Thu, 24 Sep 2020 22:45:03 +0200 Message-Id: <20200924204516.1881843-4-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen , Maxim Levitsky , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Allos the LBA data size (lbads) to be set between 9 and 12. Signed-off-by: Klaus Jensen Acked-by: Keith Busch Reviewed-by: Maxim Levitsky Reviewed-by: Philippe Mathieu-Daudé --- docs/specs/nvme.txt | 11 ++++++++++- hw/block/nvme-ns.h | 1 + hw/block/nvme-ns.c | 8 +++++++- hw/block/nvme.c | 1 + 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/docs/specs/nvme.txt b/docs/specs/nvme.txt index 56d393884e7a..438ca50d698c 100644 --- a/docs/specs/nvme.txt +++ b/docs/specs/nvme.txt @@ -1,7 +1,16 @@ NVM Express Controller ====================== -The nvme device (-device nvme) emulates an NVM Express Controller. +The nvme device (-device nvme) emulates an NVM Express Controller. It is used +together with nvme-ns devices (-device nvme-ns) which emulates an NVM Express +Namespace. + +nvme-ns Options +--------------- + + `lbads`; The "LBA Data Size (LBADS)" indicates the LBA data size used by the + namespace. It is specified in terms of a power of two. Only values between + 9 and 12 (both inclusive) are supported. Reference Specifications diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index 83734f4606e1..78b0d1a00672 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -21,6 +21,7 @@ typedef struct NvmeNamespaceParams { uint32_t nsid; + uint8_t lbads; } NvmeNamespaceParams; typedef struct NvmeNamespace { diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 2ba0263ddaca..576c7486f45b 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -36,7 +36,7 @@ static void nvme_ns_init(NvmeNamespace *ns) ns->id_ns.dlfeat = 0x9; } - id_ns->lbaf[0].ds = BDRV_SECTOR_BITS; + id_ns->lbaf[0].ds = ns->params.lbads; id_ns->nsze = cpu_to_le64(nvme_ns_nlbas(ns)); @@ -77,6 +77,11 @@ static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp) return -1; } + if (ns->params.lbads < 9 || ns->params.lbads > 12) { + error_setg(errp, "unsupported lbads (supported: 9-12)"); + return -1; + } + return 0; } @@ -125,6 +130,7 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp) static Property nvme_ns_props[] = { DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf), DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0), + DEFINE_PROP_UINT8("lbads", NvmeNamespace, params.lbads, BDRV_SECTOR_BITS), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 3cbc3c7b75b1..758f58c88026 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -2812,6 +2812,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) if (n->namespace.blkconf.blk) { ns = &n->namespace; ns->params.nsid = 1; + ns->params.lbads = BDRV_SECTOR_BITS; if (nvme_ns_setup(n, ns, errp)) { return; From patchwork Thu Sep 24 20:45:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 304475 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 26F2AC4363D for ; Thu, 24 Sep 2020 20:50:51 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id BF18620717 for ; Thu, 24 Sep 2020 20:50:50 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org BF18620717 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:50136 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYCX-0007Lf-M9 for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 16:50:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38510) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7N-0004Py-3a; Thu, 24 Sep 2020 16:45:29 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:51605) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7J-0007iS-NB; Thu, 24 Sep 2020 16:45:28 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id D760C580507; Thu, 24 Sep 2020 16:45:24 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:24 -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=fm1; bh=WbPXCy/OFaknh L9vreyycHOBgrvUUYu9WIgBvZGZ6+E=; b=tKawj+n4tvXW+Y0Lxx+coHYMzKQEo d3oRKfX1ByweMyxdq5pmi9mf9UdnvqVjwenRz2z3YMd8ewKIcr5pq0yeIu2x//br ik2k7MFZmZq7CNp+SOHXk5NXF/2tU9cFyWJ1DIef0mesRlWt0aavGoQZvTvfv8ct G3hA02JD9bE6itnd4nWdCIfYLWZQTLx7GoWAwmyHEUi//KztPUYiUbY8Y9N0oHS/ 1vFiofgM5rmI6R/2qMGyVba+Rz011T/GpqMAbgby5cjZit1epiSN3OqtPKTjfXD4 OfvTIYhy6PECgJYmOv+C5iwgLv+6NrD/HpUbYEeTDn7oYsC4ssiBKTSeA== 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= fm3; bh=WbPXCy/OFaknhL9vreyycHOBgrvUUYu9WIgBvZGZ6+E=; b=FWXKG6k7 b5R95mDnWHxok2kQopm1BuLS+RKdpNIHKDIvi45lMSLWrNMpDlACowNZ9UJu2wkX n4qQboPgtp9dnx16gze6i1GyEd/PubtRwfJtUzu/LgvCQDFRXbFyDoopxJcZv5Nf 7Y3LPMlWufNoBkJdU/ZnOkMWK3VDB7JkYawmNJd/Vx8IUy1T0y3D/K5fa47pqRUX XosV2X9OrMgExjopyO2tZLjuk42OwdmoePoX/QPzOkzG5dIwG2dlZSgQMOgZKa41 Fwhj6VpfB+aGOm4bOGbz2E/4klzznNBlGZgUIfbLoBAKfFF+NulLq/b1qjpDYXII wyrtfjsBKelQ9g== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeeuleetgeeiuefhgfekfefgveejiefgteekiedtgfdtieefhfdthfefueffvefg keenucfkphepkedtrdduieejrdelkedrudeltdenucevlhhushhtvghrufhiiigvpedvne curfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirhhrvghlvghvrghnthdrughk 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 5CFFF3064683; Thu, 24 Sep 2020 16:45:23 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 04/16] hw/block/nvme: reject io commands if only admin command set selected Date: Thu, 24 Sep 2020 22:45:04 +0200 Message-Id: <20200924204516.1881843-5-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen If the host sets CC.CSS to 111b, all commands submitted to I/O queues should be completed with status Invalid Command Opcode. Note that this is technically a v1.4 feature, but it does not hurt to implement before we finally bump the reported version implemented. Signed-off-by: Klaus Jensen --- include/block/nvme.h | 5 +++++ hw/block/nvme.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/include/block/nvme.h b/include/block/nvme.h index 58647bcdad0b..7a30cf285ae0 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -110,6 +110,11 @@ enum NvmeCcMask { #define NVME_CC_IOSQES(cc) ((cc >> CC_IOSQES_SHIFT) & CC_IOSQES_MASK) #define NVME_CC_IOCQES(cc) ((cc >> CC_IOCQES_SHIFT) & CC_IOCQES_MASK) +enum NvmeCcCss { + NVME_CC_CSS_NVM = 0x0, + NVME_CC_CSS_ADMIN_ONLY = 0x7, +}; + enum NvmeCstsShift { CSTS_RDY_SHIFT = 0, CSTS_CFS_SHIFT = 1, diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 758f58c88026..27af2f0b38d5 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1065,6 +1065,10 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req), req->cmd.opcode, nvme_io_opc_str(req->cmd.opcode)); + if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_ADMIN_ONLY) { + return NVME_INVALID_OPCODE | NVME_DNR; + } + if (!nvme_nsid_valid(n, nsid)) { return NVME_INVALID_NSID | NVME_DNR; } From patchwork Thu Sep 24 20:45:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 272802 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 78FA9C4363D for ; Thu, 24 Sep 2020 20:52:22 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id D25A222208 for ; Thu, 24 Sep 2020 20:52:21 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D25A222208 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:52244 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYE0-0008Jv-R9 for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 16:52:20 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38554) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7P-0004SG-PC; Thu, 24 Sep 2020 16:45:31 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:53395) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7L-0007jG-VE; Thu, 24 Sep 2020 16:45:31 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id 6910258050D; Thu, 24 Sep 2020 16:45:26 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:26 -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=fm1; bh=lLWIYy5Nac5ZM W2eRDZjjpMxYppJ2wzvImlA/zmiNkQ=; b=zJhsKXS6/NtxkkE5kTGTCE/1eTCza U9mStPjvlIYISRAxeTB0KGSix83NNvYNul4F73Zef68+73xRsS346W8Nzm2sRSWZ Qhb9s3C95WaDn0/E/Q5IORKEYXnRYUEWIu0VhH37+EAAHdiZq2fzLUDB9uS0CTUa fwXmNIMrbcCIWn9Tc7JOj3srNLJluKkVd56WXkhYXxRo+ni4bTp4f9+6ReDfLfXu J0AVJO6qbJ4rSccFi9FW5QfVxHDI85ilrbYCBuXgZH0KbTAe50Ovc/IuscTek5ot uiCdJT+oTJ5YeOr8OxTwRfJ3ryGE2UQrmoNq2sAQdCIep8UmusBFKpzsw== 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= fm3; bh=lLWIYy5Nac5ZMW2eRDZjjpMxYppJ2wzvImlA/zmiNkQ=; b=Us8l/bJY d+mqVNrB22Szs3kygjpO41gxq27WeTGxVtU4DGV3OhOPR+Q8Vwmzjfu1RXkIORFy jVwHHzlUEkAP71vzbm1W53pclRFANvtgas87gpBnZ4X0ZtRcLfUCWAKT46kXpB/n tq2TCe387EDRiFvw5UR5wiHvNoeerdRMSOCUiUxpTVmY7UN5KQgfTGbp9B+KVad7 DbBI+nreFQS3SByhDrP2Rm1y1wusyzv2Gsi/ufgopH5JdhQ9fFLnzyumqoBMo/RS HtVa/d42BYtVGJwSz2OnegQOYHRGLv5NnmvLCFbeA0gR/+ps4z/NLsuFnjuvNYCY YPAzYkgfKhK/VA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeeuleetgeeiuefhgfekfefgveejiefgteekiedtgfdtieefhfdthfefueffvefg keenucfkphepkedtrdduieejrdelkedrudeltdenucevlhhushhtvghrufhiiigvpedvne curfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirhhrvghlvghvrghnthdrughk 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 A062D3064674; Thu, 24 Sep 2020 16:45:24 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 05/16] hw/block/nvme: consolidate read, write and write zeroes Date: Thu, 24 Sep 2020 22:45:05 +0200 Message-Id: <20200924204516.1881843-6-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Consolidate the read/write and write zeroes functions. Signed-off-by: Klaus Jensen --- hw/block/nvme.h | 11 ++++++++ include/block/nvme.h | 2 ++ hw/block/nvme.c | 65 +++++++++++++++---------------------------- hw/block/trace-events | 3 +- 4 files changed, 37 insertions(+), 44 deletions(-) diff --git a/hw/block/nvme.h b/hw/block/nvme.h index e080a2318a50..ccf52ac7bb82 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -36,6 +36,17 @@ typedef struct NvmeRequest { QTAILQ_ENTRY(NvmeRequest)entry; } NvmeRequest; +static inline bool nvme_req_is_write(NvmeRequest *req) +{ + switch (req->cmd.opcode) { + case NVME_CMD_WRITE: + case NVME_CMD_WRITE_ZEROES: + return true; + default: + return false; + } +} + static inline const char *nvme_adm_opc_str(uint8_t opc) { switch (opc) { diff --git a/include/block/nvme.h b/include/block/nvme.h index 7a30cf285ae0..999b4f8ae0d4 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -438,6 +438,8 @@ typedef struct QEMU_PACKED NvmeCmd { uint32_t cdw15; } NvmeCmd; +#define NVME_CMD_OPCODE_DATA_TRANSFER_MASK 0x3 + #define NVME_CMD_FLAGS_FUSE(flags) (flags & 0x3) #define NVME_CMD_FLAGS_PSDT(flags) ((flags >> 6) & 0x3) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 27af2f0b38d5..795c7e7c529f 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -997,48 +997,19 @@ static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req) return nvme_do_aio(ns->blkconf.blk, 0, 0, req); } -static uint16_t nvme_write_zeroes(NvmeCtrl *n, NvmeRequest *req) +static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) { NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; NvmeNamespace *ns = req->ns; + uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; - uint64_t offset = nvme_l2b(ns, slba); - uint32_t count = nvme_l2b(ns, nlb); + size_t len = nvme_l2b(ns, nlb); + uint16_t status; - trace_pci_nvme_write_zeroes(nvme_cid(req), nvme_nsid(ns), slba, nlb); - - status = nvme_check_bounds(n, ns, slba, nlb); - if (status) { - trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); - return status; - } - - return nvme_do_aio(ns->blkconf.blk, offset, count, req); -} - -static uint16_t nvme_rw(NvmeCtrl *n, NvmeRequest *req) -{ - NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; - NvmeNamespace *ns = req->ns; - uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; - uint64_t slba = le64_to_cpu(rw->slba); - - uint64_t data_size = nvme_l2b(ns, nlb); - uint64_t data_offset = nvme_l2b(ns, slba); - enum BlockAcctType acct = req->cmd.opcode == NVME_CMD_WRITE ? - BLOCK_ACCT_WRITE : BLOCK_ACCT_READ; - uint16_t status; - - trace_pci_nvme_rw(nvme_cid(req), nvme_io_opc_str(rw->opcode), - nvme_nsid(ns), nlb, data_size, slba); - - status = nvme_check_mdts(n, data_size); - if (status) { - trace_pci_nvme_err_mdts(nvme_cid(req), data_size); - goto invalid; - } + trace_pci_nvme_rwz(nvme_cid(req), nvme_io_opc_str(rw->opcode), + nvme_nsid(ns), nlb, len, slba); status = nvme_check_bounds(n, ns, slba, nlb); if (status) { @@ -1046,15 +1017,26 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeRequest *req) goto invalid; } - status = nvme_map_dptr(n, data_size, req); - if (status) { - goto invalid; + if (req->cmd.opcode & NVME_CMD_OPCODE_DATA_TRANSFER_MASK) { + status = nvme_check_mdts(n, len); + if (status) { + trace_pci_nvme_err_mdts(nvme_cid(req), len); + goto invalid; + } + + status = nvme_map_dptr(n, len, req); + if (status) { + goto invalid; + } } - return nvme_do_aio(ns->blkconf.blk, data_offset, data_size, req); + return nvme_do_aio(ns->blkconf.blk, nvme_l2b(ns, slba), len, req); invalid: - block_acct_invalid(blk_get_stats(ns->blkconf.blk), acct); + block_acct_invalid(blk_get_stats(ns->blkconf.blk), + nvme_req_is_write(req) ? BLOCK_ACCT_WRITE : + BLOCK_ACCT_READ); + return status; } @@ -1082,10 +1064,9 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) case NVME_CMD_FLUSH: return nvme_flush(n, req); case NVME_CMD_WRITE_ZEROES: - return nvme_write_zeroes(n, req); case NVME_CMD_WRITE: case NVME_CMD_READ: - return nvme_rw(n, req); + return nvme_rwz(n, req); default: trace_pci_nvme_err_invalid_opc(req->cmd.opcode); return NVME_INVALID_OPCODE | NVME_DNR; diff --git a/hw/block/trace-events b/hw/block/trace-events index 9e7507c5abde..b18056c49836 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -40,9 +40,8 @@ pci_nvme_map_prp(uint64_t trans_len, uint32_t len, uint64_t prp1, uint64_t prp2, pci_nvme_map_sgl(uint16_t cid, uint8_t typ, uint64_t len) "cid %"PRIu16" 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_rw(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_rwz(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t len, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" len %"PRIu64" lba 0x%"PRIx64"" pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_write_zeroes(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba %"PRIu64" nlb %"PRIu32"" pci_nvme_do_aio(uint16_t cid, uint8_t opc, const char *opname, const char *blkname, int64_t offset, size_t len) "cid %"PRIu16" opc 0x%"PRIx8" opname '%s' blk '%s' offset %"PRId64" len %zu" pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16"" pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d" From patchwork Thu Sep 24 20:45:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 272796 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 762ACC4363D for ; Thu, 24 Sep 2020 21:13:51 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 9241120B1F for ; Thu, 24 Sep 2020 21:13:50 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9241120B1F Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:52986 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYYn-0004Q1-Ev for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 17:13:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38556) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7P-0004Sl-SJ; Thu, 24 Sep 2020 16:45:31 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:58363) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7N-0007k4-3T; Thu, 24 Sep 2020 16:45:31 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id 147A458050E; Thu, 24 Sep 2020 16:45:28 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:28 -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=fm1; bh=eMFL+KloNOKMc UMKk25g1WoQY0r3uhy8qMNoTTEz55k=; b=KJEmn/BVb4t2WjPhC+SPrSsrNT2ec D+bVJ9qPrxkqZ1wvIVBq/qKWnBhmNCk4330PnDPBuR5Hwx3/ymf31zslqnx+OPar m1/ivZg4830Bsf7QF/+BtW1hB+29qOOugL4GpSQOEs3UGb6nH36EHaXma/CYMCX6 4YBSeBflQ5zgIkBtzHFhuz0+qQcNgZij0xtmlo2sENaOcVa/Fa7wlo2YCMAZRwxW m8EwZQbqZtVvvka4+PzyLXEDSejxOMfVy2if9ZX41yRPuCkimAJq/+6jJ/YlJgRr HcNACwmV4Z4dHNV5WiI6kXaI6Vqp+iN7aPmgZKfZBKKyTeLWAq3eKtjbg== 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= fm3; bh=eMFL+KloNOKMcUMKk25g1WoQY0r3uhy8qMNoTTEz55k=; b=nObfYEDF 3sowoWCAOTgz+is0EUKOVhIs+UQsM6YQgHbPLcr3SqoWcGRL5DFcZhc2cG+8dz6+ TIknZ4wzCQkhis0OwfNoNTC0aUPY1nuuBjCZTSaJgWjQ92taiCk1snIUjMeRDTEP q4S21p1QeLiiI9KvQ4QY2hT7XFx7n9+aFnkjKyor/UCx+PY0iN6Kygw28Pl7GSWR pFOa0AFlZnBCuJF/o0VrmRB8mM4/LOrhbADs0PbixtfPfB4s4ROW9EIM5ziLyp1D APr4cPlLhmT6ffLpfjme2UmQG1jThBU7+Zg6sDovNeN1F17LXdvvJFTsonl5o4e7 FqfD9fT3ihmF8w== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeekudehfeethfdvvdegieffheekueeghefhudfghffhhfevjeejffeuhedugedu udenucffohhmrghinhepuhhtihhlihiirghtihhonhdrmhgrphenucfkphepkedtrdduie ejrdelkedrudeltdenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhl fhhrohhmpehithhssehirhhrvghlvghvrghnthdrughk 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 E53EB3064682; Thu, 24 Sep 2020 16:45:25 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 06/16] hw/block/nvme: add support for dulbe and block utilization tracking Date: Thu, 24 Sep 2020 22:45:06 +0200 Message-Id: <20200924204516.1881843-7-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen This adds support for reporting the Deallocated or Unwritten Logical Block error (DULBE). This requires tracking the allocated/deallocated status of all logical blocks. Introduce a bitmap that does this. The bitmap is persisted on the new 'pstate' blockdev that is associated with a namespace. If no such drive is attached, the controller will not indicate support for DULBE. Signed-off-by: Klaus Jensen --- docs/specs/nvme.txt | 7 +++ hw/block/nvme-ns.h | 13 +++++ include/block/nvme.h | 5 ++ hw/block/nvme-ns.c | 110 ++++++++++++++++++++++++++++++++++++++++ hw/block/nvme.c | 113 ++++++++++++++++++++++++++++++++++++++++-- hw/block/trace-events | 2 + 6 files changed, 247 insertions(+), 3 deletions(-) diff --git a/docs/specs/nvme.txt b/docs/specs/nvme.txt index 438ca50d698c..9a5c67f10b5d 100644 --- a/docs/specs/nvme.txt +++ b/docs/specs/nvme.txt @@ -12,6 +12,13 @@ nvme-ns Options namespace. It is specified in terms of a power of two. Only values between 9 and 12 (both inclusive) are supported. + `pstate`; This parameter specifies another blockdev to be used for storing + persistent state such as logical block allocation tracking. Adding this + parameter enables various optional features of the device. + + -drive id=pstate,file=pstate.img,format=raw + -device nvme-ns,pstate=pstate,... + Reference Specifications ------------------------ diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index 78b0d1a00672..51141796909f 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -31,7 +31,20 @@ typedef struct NvmeNamespace { int64_t size; NvmeIdNs id_ns; + struct { + BlockBackend *blk; + + struct { + unsigned long *map; + int64_t offset; + } utilization; + } pstate; + NvmeNamespaceParams params; + + struct { + uint32_t err_rec; + } features; } NvmeNamespace; static inline uint32_t nvme_nsid(NvmeNamespace *ns) diff --git a/include/block/nvme.h b/include/block/nvme.h index 999b4f8ae0d4..abd49d371e63 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -683,6 +683,7 @@ enum NvmeStatusCodes { NVME_E2E_REF_ERROR = 0x0284, NVME_CMP_FAILURE = 0x0285, NVME_ACCESS_DENIED = 0x0286, + NVME_DULB = 0x0287, NVME_MORE = 0x2000, NVME_DNR = 0x4000, NVME_NO_COMPLETE = 0xffff, @@ -898,6 +899,9 @@ enum NvmeIdCtrlLpa { #define NVME_AEC_NS_ATTR(aec) ((aec >> 8) & 0x1) #define NVME_AEC_FW_ACTIVATION(aec) ((aec >> 9) & 0x1) +#define NVME_ERR_REC_TLER(err_rec) (err_rec & 0xffff) +#define NVME_ERR_REC_DULBE(err_rec) (err_rec & 0x10000) + enum NvmeFeatureIds { NVME_ARBITRATION = 0x1, NVME_POWER_MANAGEMENT = 0x2, @@ -1018,6 +1022,7 @@ enum NvmeNsIdentifierType { #define NVME_ID_NS_NSFEAT_THIN(nsfeat) ((nsfeat & 0x1)) +#define NVME_ID_NS_NSFEAT_DULBE(nsfeat) ((nsfeat >> 2) & 0x1) #define NVME_ID_NS_FLBAS_EXTENDED(flbas) ((flbas >> 4) & 0x1) #define NVME_ID_NS_FLBAS_INDEX(flbas) ((flbas & 0xf)) #define NVME_ID_NS_MC_SEPARATE(mc) ((mc >> 1) & 0x1) diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 576c7486f45b..9a63004c000a 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -25,9 +25,36 @@ #include "hw/qdev-properties.h" #include "hw/qdev-core.h" +#include "trace.h" + #include "nvme.h" #include "nvme-ns.h" +static int nvme_blk_truncate(BlockBackend *blk, size_t len, Error **errp) +{ + int ret; + uint64_t perm, shared_perm; + + blk_get_perm(blk, &perm, &shared_perm); + + ret = blk_set_perm(blk, perm | BLK_PERM_RESIZE, shared_perm, errp); + if (ret < 0) { + return ret; + } + + ret = blk_truncate(blk, len, false, PREALLOC_MODE_OFF, 0, errp); + if (ret < 0) { + return ret; + } + + ret = blk_set_perm(blk, perm, shared_perm, errp); + if (ret < 0) { + return ret; + } + + return 0; +} + static void nvme_ns_init(NvmeNamespace *ns) { NvmeIdNs *id_ns = &ns->id_ns; @@ -45,6 +72,67 @@ static void nvme_ns_init(NvmeNamespace *ns) id_ns->nuse = id_ns->ncap; } +static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) +{ + BlockBackend *blk = ns->pstate.blk; + uint64_t perm, shared_perm; + ssize_t len; + size_t pstate_len; + int ret; + + perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; + shared_perm = BLK_PERM_ALL; + + ret = blk_set_perm(blk, perm, shared_perm, errp); + if (ret) { + return ret; + } + + pstate_len = ROUND_UP(DIV_ROUND_UP(nvme_ns_nlbas(ns), 8), + BDRV_SECTOR_SIZE); + + len = blk_getlength(blk); + if (len < 0) { + error_setg_errno(errp, -len, "could not determine pstate size"); + return len; + } + + unsigned long *map = bitmap_new(nvme_ns_nlbas(ns)); + ns->pstate.utilization.offset = 0; + + if (!len) { + ret = nvme_blk_truncate(blk, pstate_len, errp); + if (ret < 0) { + return ret; + } + + ns->pstate.utilization.map = map; + } else { + if (len != pstate_len) { + error_setg(errp, "pstate size mismatch " + "(expected %zd bytes; was %zu bytes)", + pstate_len, len); + return -1; + } + + ret = blk_pread(blk, 0, map, pstate_len); + if (ret < 0) { + error_setg_errno(errp, -ret, "could not read pstate"); + return ret; + } +#ifdef HOST_WORDS_BIGENDIAN + ns->pstate.utilization.map = bitmap_new(nvme_ns_nlbas(ns)); + bitmap_from_le(ns->pstate.utilization.map, map, nvme_ns_nlbas(ns)); +#else + ns->pstate.utilization.map = map; +#endif + + return 0; + } + + return 0; +} + static int nvme_ns_init_blk(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) { if (!blkconf_blocksizes(&ns->blkconf, errp)) { @@ -96,6 +184,19 @@ int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) } nvme_ns_init(ns); + + if (ns->pstate.blk) { + if (nvme_ns_setup_blk_pstate(ns, errp)) { + return -1; + } + + /* + * With a pstate file in place we can enable the Deallocated or + * Unwritten Logical Block Error feature. + */ + ns->id_ns.nsfeat |= 0x4; + } + if (nvme_register_namespace(n, ns, errp)) { return -1; } @@ -106,11 +207,19 @@ int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) void nvme_ns_drain(NvmeNamespace *ns) { blk_drain(ns->blkconf.blk); + + if (ns->pstate.blk) { + blk_drain(ns->pstate.blk); + } } void nvme_ns_flush(NvmeNamespace *ns) { blk_flush(ns->blkconf.blk); + + if (ns->pstate.blk) { + blk_flush(ns->pstate.blk); + } } static void nvme_ns_realize(DeviceState *dev, Error **errp) @@ -131,6 +240,7 @@ static Property nvme_ns_props[] = { DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf), DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0), DEFINE_PROP_UINT8("lbads", NvmeNamespace, params.lbads, BDRV_SECTOR_BITS), + DEFINE_PROP_DRIVE("pstate", NvmeNamespace, pstate.blk), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 795c7e7c529f..b16e089bda80 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -105,6 +105,7 @@ static const bool nvme_feature_support[NVME_FID_MAX] = { static const uint32_t nvme_feature_cap[NVME_FID_MAX] = { [NVME_TEMPERATURE_THRESHOLD] = NVME_FEAT_CAP_CHANGE, + [NVME_ERROR_RECOVERY] = NVME_FEAT_CAP_CHANGE | NVME_FEAT_CAP_NS, [NVME_VOLATILE_WRITE_CACHE] = NVME_FEAT_CAP_CHANGE, [NVME_NUMBER_OF_QUEUES] = NVME_FEAT_CAP_CHANGE, [NVME_ASYNCHRONOUS_EVENT_CONF] = NVME_FEAT_CAP_CHANGE, @@ -888,6 +889,61 @@ static inline uint16_t nvme_check_bounds(NvmeCtrl *n, NvmeNamespace *ns, return NVME_SUCCESS; } +static inline uint16_t nvme_check_dulbe(NvmeNamespace *ns, uint64_t slba, + uint32_t nlb) +{ + uint64_t elba = slba + nlb; + + if (find_next_zero_bit(ns->pstate.utilization.map, elba, slba) < elba) { + return NVME_DULB; + } + + return NVME_SUCCESS; +} + +static int nvme_allocate(NvmeNamespace *ns, uint64_t slba, uint32_t nlb) +{ + int nlongs, first; + int64_t offset; + unsigned long *map, *src; + int ret; + + if (!(ns->pstate.blk && nvme_check_dulbe(ns, slba, nlb))) { + return 0; + } + + trace_pci_nvme_allocate(nvme_nsid(ns), slba, nlb); + + bitmap_set(ns->pstate.utilization.map, slba, nlb); + + nlongs = BITS_TO_LONGS(nlb) + 1; + first = slba / BITS_PER_LONG; + offset = ns->pstate.utilization.offset + first * sizeof(unsigned long); + src = ns->pstate.utilization.map; + +#ifdef HOST_WORDS_BIGENDIAN + map = g_new(nlongs, sizeof(unsigned long)); + for (int i = first; i < first + nlongs; i++) { +# if HOST_LONG_BITS == 64 + map[i] = bswap64(src[i]); +# else + map[i] = bswap32(src[i]); +# endif + } +#else + map = src; +#endif + + ret = blk_pwrite(ns->pstate.blk, offset, &map[first], + nlongs * sizeof(unsigned long), 0); + +#ifdef HOST_WORDS_BIGENDIAN + g_free(map); +#endif + return ret; +} + + static void nvme_rw_cb(void *opaque, int ret) { NvmeRequest *req = opaque; @@ -1006,6 +1062,7 @@ static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; size_t len = nvme_l2b(ns, nlb); + bool is_write = nvme_req_is_write(req); uint16_t status; trace_pci_nvme_rwz(nvme_cid(req), nvme_io_opc_str(rw->opcode), @@ -1017,6 +1074,16 @@ static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) goto invalid; } + if (!is_write) { + if (NVME_ERR_REC_DULBE(ns->features.err_rec)) { + status = nvme_check_dulbe(ns, slba, nlb); + if (status) { + trace_pci_nvme_err_dulbe(nvme_cid(req), slba, nlb); + goto invalid; + } + } + } + if (req->cmd.opcode & NVME_CMD_OPCODE_DATA_TRANSFER_MASK) { status = nvme_check_mdts(n, len); if (status) { @@ -1030,12 +1097,18 @@ static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) } } + if (is_write) { + if (nvme_allocate(ns, slba, nlb) < 0) { + status = NVME_INTERNAL_DEV_ERROR; + goto invalid; + } + } + return nvme_do_aio(ns->blkconf.blk, nvme_l2b(ns, slba), len, req); invalid: block_acct_invalid(blk_get_stats(ns->blkconf.blk), - nvme_req_is_write(req) ? BLOCK_ACCT_WRITE : - BLOCK_ACCT_READ); + is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ); return status; } @@ -1638,6 +1711,8 @@ static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, NvmeRequest *req) static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req) { + NvmeNamespace *ns; + NvmeCmd *cmd = &req->cmd; uint32_t dw10 = le32_to_cpu(cmd->cdw10); uint32_t dw11 = le32_to_cpu(cmd->cdw11); @@ -1708,6 +1783,18 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req) } return NVME_INVALID_FIELD | NVME_DNR; + case NVME_ERROR_RECOVERY: + if (!nvme_nsid_valid(n, nsid)) { + return NVME_INVALID_NSID | NVME_DNR; + } + + ns = nvme_ns(n, nsid); + if (unlikely(!ns)) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + result = ns->features.err_rec; + goto out; case NVME_VOLATILE_WRITE_CACHE: result = n->features.vwc; trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled"); @@ -1780,7 +1867,7 @@ static uint16_t nvme_set_feature_timestamp(NvmeCtrl *n, NvmeRequest *req) static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) { - NvmeNamespace *ns; + NvmeNamespace *ns = NULL; NvmeCmd *cmd = &req->cmd; uint32_t dw10 = le32_to_cpu(cmd->cdw10); @@ -1847,6 +1934,26 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) NVME_LOG_SMART_INFO); } + break; + case NVME_ERROR_RECOVERY: + if (nsid == NVME_NSID_BROADCAST) { + for (int i = 1; i <= n->num_namespaces; i++) { + ns = nvme_ns(n, i); + + if (!ns) { + continue; + } + + if (NVME_ID_NS_NSFEAT_DULBE(ns->id_ns.nsfeat)) { + ns->features.err_rec = dw11; + } + } + + break; + } + + assert(ns); + ns->features.err_rec = dw11; break; case NVME_VOLATILE_WRITE_CACHE: n->features.vwc = dw11 & 0x1; diff --git a/hw/block/trace-events b/hw/block/trace-events index b18056c49836..774513469274 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -42,6 +42,7 @@ pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode, cons 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_rwz(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t len, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" len %"PRIu64" lba 0x%"PRIx64"" pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_allocate(uint32_t ns, uint64_t slba, uint32_t nlb) "nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" pci_nvme_do_aio(uint16_t cid, uint8_t opc, const char *opname, const char *blkname, int64_t offset, size_t len) "cid %"PRIu16" opc 0x%"PRIx8" opname '%s' blk '%s' offset %"PRId64" len %zu" pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16"" pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d" @@ -89,6 +90,7 @@ pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" # nvme traces for error conditions pci_nvme_err_mdts(uint16_t cid, size_t len) "cid %"PRIu16" len %zu" pci_nvme_err_req_status(uint16_t cid, uint32_t nsid, uint16_t status, uint8_t opc) "cid %"PRIu16" nsid %"PRIu32" status 0x%"PRIx16" opc 0x%"PRIx8"" +pci_nvme_err_dulbe(uint16_t cid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" slba 0x%"PRIx64" nlb %"PRIu32"" pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64"" pci_nvme_err_addr_write(uint64_t addr) "addr 0x%"PRIx64"" pci_nvme_err_cfs(void) "controller fatal status" From patchwork Thu Sep 24 20:45:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 304473 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4296EC4363D for ; Thu, 24 Sep 2020 20:58:33 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id E2A3822208 for ; Thu, 24 Sep 2020 20:58:32 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E2A3822208 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:60820 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYJz-0003Xs-JL for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 16:58:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38572) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7Q-0004Tw-Vx; Thu, 24 Sep 2020 16:45:33 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:40053) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7N-0007lF-Qa; Thu, 24 Sep 2020 16:45:32 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id 055D8580507; Thu, 24 Sep 2020 16:45:29 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:29 -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=fm1; bh=SXFx23TeRDOqr gzQ7FwB+l5swhZ3k1PDeDOb5JK3G40=; b=OMk56wdgEufYoMKYHTTHcw442+bM9 qLo0XqG/u4QyeXBavhCrsg4qF8BR8AL4ABZHZtkEF9+wu4E82eI5u4Hgv/cU6u6x OOC4zVMS2auei1Bs0mRYbT48DMr8HNMZ6BL37QLOhGMoYkqxmPkTtu301Og/tXJk wM0NHWkxIBcS4Qcrji1Ls9Nm0GFABAnTK3CqQWHn/tZo/YzdtUzTOnOp8Vk0cU/M c9kIVHV1Px/u0UM12gkK8gSyt5c62u34jnKjCsAm1jEQxkfcqS/gwU1NdyO++nVx UInM6b4FjS5xPQ3ZZKjKDCMfs85OjTFnfi3F7cWstK56knI7XIFUVBSgw== 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= fm3; bh=SXFx23TeRDOqrgzQ7FwB+l5swhZ3k1PDeDOb5JK3G40=; b=WN4rShwK b94QSg6J6XVT4+Q0Vqf/YC1k6eQOa2F1kvZ+qsCsoCe5AmF7f2R1OHhtlb/N+KqB J0ZLhaPGsHN6TosQBdQwY+IcrKCw7dwYpYzcBTbHjisLOQubzMDFeB67D3QLvXMT WAc8MVaPcGLMx0fhUGmRwqhZtDYmYRO8lPx81nknq7gejDcSzz9RknxgyT02c82w 2UhppZ91Kq7Ur+uO9wANX2RL2TkGAZNPTRkRyP4vH7sibrjTZ+DzcZ2/O2QYRNCX e5x7su4+7xEWbsOif2vkqHV25NHjhZyTMqALkApF0p0L89516DyVv/rbUoz552OM jViQMICHzXKgTw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeeuleetgeeiuefhgfekfefgveejiefgteekiedtgfdtieefhfdthfefueffvefg keenucfkphepkedtrdduieejrdelkedrudeltdenucevlhhushhtvghrufhiiigvpeegne curfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirhhrvghlvghvrghnthdrughk 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 33702306467D; Thu, 24 Sep 2020 16:45:27 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 07/16] hw/block/nvme: add commands supported and effects log page Date: Thu, 24 Sep 2020 22:45:07 +0200 Message-Id: <20200924204516.1881843-8-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Gollu Appalanaidu , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Gollu Appalanaidu This is to support for the Commands Supported and Effects log page. See NVM Express Spec 1.3d, sec. 5.14.1.5 ("Commands Supported and Effects") Signed-off-by: Gollu Appalanaidu Signed-off-by: Klaus Jensen --- include/block/nvme.h | 21 +++++++++++++ hw/block/nvme.c | 75 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/include/block/nvme.h b/include/block/nvme.h index abd49d371e63..5a5e19f6bedc 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -734,6 +734,24 @@ typedef struct QEMU_PACKED NvmeSmartLog { uint8_t reserved2[320]; } NvmeSmartLog; +typedef struct QEMU_PACKED NvmeEffectsLog { + uint32_t acs[256]; + uint32_t iocs[256]; + uint8_t rsvd2048[2048]; +} NvmeEffectsLog; + +enum { + NVME_EFFECTS_CSUPP = 1 << 0, + NVME_EFFECTS_LBCC = 1 << 1, + NVME_EFFECTS_NCC = 1 << 2, + NVME_EFFECTS_NIC = 1 << 3, + NVME_EFFECTS_CCC = 1 << 4, + NVME_EFFECTS_CSE_SINGLE = 1 << 16, + NVME_EFFECTS_CSE_MULTI = 1 << 17, + NVME_EFFECTS_CSE_MASK = 3 << 16, + NVME_EFFECTS_UUID_SEL = 1 << 19, +}; + enum NvmeSmartWarn { NVME_SMART_SPARE = 1 << 0, NVME_SMART_TEMPERATURE = 1 << 1, @@ -746,6 +764,7 @@ enum NvmeLogIdentifier { NVME_LOG_ERROR_INFO = 0x01, NVME_LOG_SMART_INFO = 0x02, NVME_LOG_FW_SLOT_INFO = 0x03, + NVME_LOG_EFFECTS = 0x05, }; typedef struct QEMU_PACKED NvmePSD { @@ -857,6 +876,7 @@ enum NvmeIdCtrlFrmw { }; enum NvmeIdCtrlLpa { + NVME_LPA_EFFECTS_LOG = 1 << 1, NVME_LPA_EXTENDED = 1 << 2, }; @@ -1064,5 +1084,6 @@ static inline void _nvme_check_size(void) QEMU_BUILD_BUG_ON(sizeof(NvmeIdNs) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeSglDescriptor) != 16); QEMU_BUILD_BUG_ON(sizeof(NvmeIdNsDescr) != 4); + QEMU_BUILD_BUG_ON(sizeof(NvmeEffectsLog) != 4096); } #endif diff --git a/hw/block/nvme.c b/hw/block/nvme.c index b16e089bda80..21f558f75559 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -81,6 +81,7 @@ #define NVME_TEMPERATURE_WARNING 0x157 #define NVME_TEMPERATURE_CRITICAL 0x175 #define NVME_NUM_FW_SLOTS 1 +#define NVME_MAX_ADM_IO_CMDS 0xFF #define NVME_GUEST_ERR(trace, fmt, ...) \ do { \ @@ -112,6 +113,46 @@ static const uint32_t nvme_feature_cap[NVME_FID_MAX] = { [NVME_TIMESTAMP] = NVME_FEAT_CAP_CHANGE, }; +#define NVME_EFFECTS_ADMIN_INITIALIZER \ + [NVME_ADM_CMD_DELETE_SQ] = NVME_EFFECTS_CSUPP, \ + [NVME_ADM_CMD_CREATE_SQ] = NVME_EFFECTS_CSUPP, \ + [NVME_ADM_CMD_GET_LOG_PAGE] = NVME_EFFECTS_CSUPP, \ + [NVME_ADM_CMD_DELETE_CQ] = NVME_EFFECTS_CSUPP, \ + [NVME_ADM_CMD_CREATE_CQ] = NVME_EFFECTS_CSUPP, \ + [NVME_ADM_CMD_IDENTIFY] = NVME_EFFECTS_CSUPP, \ + [NVME_ADM_CMD_ABORT] = NVME_EFFECTS_CSUPP, \ + [NVME_ADM_CMD_SET_FEATURES] = NVME_EFFECTS_CSUPP | \ + NVME_EFFECTS_CCC | \ + NVME_EFFECTS_NIC | \ + NVME_EFFECTS_NCC, \ + [NVME_ADM_CMD_GET_FEATURES] = NVME_EFFECTS_CSUPP, \ + [NVME_ADM_CMD_ASYNC_EV_REQ] = NVME_EFFECTS_CSUPP + +#define NVME_EFFECTS_NVM_INITIALIZER \ + [NVME_CMD_FLUSH] = NVME_EFFECTS_CSUPP | \ + NVME_EFFECTS_LBCC, \ + [NVME_CMD_WRITE] = NVME_EFFECTS_CSUPP | \ + NVME_EFFECTS_LBCC, \ + [NVME_CMD_READ] = NVME_EFFECTS_CSUPP, \ + [NVME_CMD_WRITE_ZEROES] = NVME_EFFECTS_CSUPP | \ + NVME_EFFECTS_LBCC + +static const NvmeEffectsLog nvme_effects_admin_only = { + .acs = { + NVME_EFFECTS_ADMIN_INITIALIZER, + }, +}; + +static const NvmeEffectsLog nvme_effects = { + .acs = { + NVME_EFFECTS_ADMIN_INITIALIZER, + }, + + .iocs = { + NVME_EFFECTS_NVM_INITIALIZER, + }, +}; + static void nvme_process_sq(void *opaque); static uint16_t nvme_cid(NvmeRequest *req) @@ -1365,6 +1406,36 @@ static uint16_t nvme_error_info(NvmeCtrl *n, uint8_t rae, uint32_t buf_len, DMA_DIRECTION_FROM_DEVICE, req); } +static uint16_t nvme_effects_log(NvmeCtrl *n, uint32_t buf_len, uint64_t off, + NvmeRequest *req) +{ + const NvmeEffectsLog *effects; + + uint32_t trans_len; + + if (off > sizeof(NvmeEffectsLog)) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + switch (NVME_CC_CSS(n->bar.cc)) { + case NVME_CC_CSS_ADMIN_ONLY: + effects = &nvme_effects_admin_only; + break; + + case NVME_CC_CSS_NVM: + effects = &nvme_effects; + break; + + default: + return NVME_INTERNAL_DEV_ERROR | NVME_DNR; + } + + trans_len = MIN(sizeof(NvmeEffectsLog) - off, buf_len); + + return nvme_dma(n, (uint8_t *)effects + off, trans_len, + DMA_DIRECTION_FROM_DEVICE, req); +} + static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest *req) { NvmeCmd *cmd = &req->cmd; @@ -1408,6 +1479,8 @@ static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest *req) return nvme_smart_info(n, rae, len, off, req); case NVME_LOG_FW_SLOT_INFO: return nvme_fw_log_info(n, len, off, req); + case NVME_LOG_EFFECTS: + return nvme_effects_log(n, len, off, req); default: trace_pci_nvme_err_invalid_log_page(nvme_cid(req), lid); return NVME_INVALID_FIELD | NVME_DNR; @@ -2841,7 +2914,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) id->acl = 3; id->aerl = n->params.aerl; id->frmw = (NVME_NUM_FW_SLOTS << 1) | NVME_FRMW_SLOT1_RO; - id->lpa = NVME_LPA_EXTENDED; + id->lpa = NVME_LPA_EFFECTS_LOG | NVME_LPA_EXTENDED; /* recommended default value (~70 C) */ id->wctemp = cpu_to_le16(NVME_TEMPERATURE_WARNING); From patchwork Thu Sep 24 20:45:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 304471 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4161DC4363D for ; Thu, 24 Sep 2020 21:05:09 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 88BEB22208 for ; Thu, 24 Sep 2020 21:05:08 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 88BEB22208 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:40624 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYQN-000770-2p for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 17:05:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38616) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7Y-0004Xn-1C; Thu, 24 Sep 2020 16:45:40 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:51017) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7Q-0007my-2C; Thu, 24 Sep 2020 16:45:39 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id 4A42B58050C; Thu, 24 Sep 2020 16:45:31 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:31 -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=fm1; bh=PrCna6ZwTkQ8L DzZcN0skhp9euqg56QTIHlhBWBuKfQ=; b=Tp8cW5RePxxz3YE+XW4Ru8L5Xxzk+ CNz51TniyX/MGDaB/JlqdAQSITWsF6q7pY8yGqpS7IkAy4N8ZKvzsloUJjc5KzAZ xXLcDHrQQLWDVg6MpbcfDieXqofExT9IteT9V96O5aBYjkmbJBT08nx/axjXJkUH mZJ9CRDanmOndlOU7OBd10kzokY4riTgULrYl6BlSTB8GAYjc3opILS/SMp8ISaI ZZ/JxjX2idRaboSF/V+u7UtPjP3bdEZXsx9GC0CHH0XjQ0MN2kFjzvXVtpvKIb48 zOMk2QWZaV4GUBOz2bqpKCrBQWUmh2loIPuTL9pYZKLw5oejYi3qMJZ0A== 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= fm3; bh=PrCna6ZwTkQ8LDzZcN0skhp9euqg56QTIHlhBWBuKfQ=; b=Ug5+tTuj IeVMgC0u32ACfU7UGIoZ+ey5FNK8XExyUkr5DGWyHlZ+MKhoX7Cu9JgRBC9CmMB8 5KAZmrSeeWgHsQsrOshLeJ25JvaRUus+aJdU/kv6Xyf/8csOjzMuOyp3RdeqTVP+ 2XSJfsbks4GT3myzw2FVGGA22OG69U2sZaBCcpGweoh5oed08vgjtea6FEk/ljuP q46mfiTD5qeiLWm4ickGmK2EiCW+iaIcE/HoJmXqzbXS40Zfw+bH4L3vGSIFsZsT tOfu+/NdjRoXFrmT9yPrqEJJ/EUl0I5h5SYsuPAWBFa4d3KrLWDKqzbKSglP7vxZ rl6Jjq64YCbY3Q== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeeuleetgeeiuefhgfekfefgveejiefgteekiedtgfdtieefhfdthfefueffvefg keenucfkphepkedtrdduieejrdelkedrudeltdenucevlhhushhtvghrufhiiigvpeegne curfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirhhrvghlvghvrghnthdrughk 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 94A883064674; Thu, 24 Sep 2020 16:45:28 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 08/16] hw/block/nvme: support namespace types Date: Thu, 24 Sep 2020 22:45:08 +0200 Message-Id: <20200924204516.1881843-9-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Implement support for TP 4056 ("Namespace Types"). This adds the 'iocs' (I/O Command Set) device parameter to the nvme-ns device. Signed-off-by: Klaus Jensen --- docs/specs/nvme.txt | 3 + hw/block/nvme-ns.h | 11 +- hw/block/nvme.h | 3 + include/block/nvme.h | 58 +++++++++-- block/nvme.c | 4 +- hw/block/nvme-ns.c | 21 +++- hw/block/nvme.c | 228 ++++++++++++++++++++++++++++++++++-------- hw/block/trace-events | 6 +- 8 files changed, 275 insertions(+), 59 deletions(-) diff --git a/docs/specs/nvme.txt b/docs/specs/nvme.txt index 9a5c67f10b5d..890990510b14 100644 --- a/docs/specs/nvme.txt +++ b/docs/specs/nvme.txt @@ -19,6 +19,9 @@ nvme-ns Options -drive id=pstate,file=pstate.img,format=raw -device nvme-ns,pstate=pstate,... + `iocs`; The "I/O Command Set" associated with the namespace. E.g. 0x0 for the + NVM Command Set (the default), or 0x2 for the Zoned Namespace Command Set. + Reference Specifications ------------------------ diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index 51141796909f..06c0bc8b32a4 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -21,6 +21,7 @@ typedef struct NvmeNamespaceParams { uint32_t nsid; + uint8_t iocs; uint8_t lbads; } NvmeNamespaceParams; @@ -29,7 +30,8 @@ typedef struct NvmeNamespace { BlockConf blkconf; int32_t bootindex; int64_t size; - NvmeIdNs id_ns; + uint8_t iocs; + void *id_ns[NVME_IOCS_MAX]; struct { BlockBackend *blk; @@ -56,9 +58,14 @@ static inline uint32_t nvme_nsid(NvmeNamespace *ns) return -1; } +static inline NvmeIdNsNvm *nvme_ns_id_nvm(NvmeNamespace *ns) +{ + return ns->id_ns[NVME_IOCS_NVM]; +} + static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns) { - NvmeIdNs *id_ns = &ns->id_ns; + NvmeIdNsNvm *id_ns = nvme_ns_id_nvm(ns); return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; } diff --git a/hw/block/nvme.h b/hw/block/nvme.h index ccf52ac7bb82..f66ed9ab7eff 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -123,6 +123,7 @@ typedef struct NvmeFeatureVal { }; uint32_t async_config; uint32_t vwc; + uint32_t iocsci; } NvmeFeatureVal; typedef struct NvmeCtrl { @@ -150,6 +151,7 @@ typedef struct NvmeCtrl { uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */ uint64_t starttime_ms; uint16_t temperature; + uint64_t iocscs[512]; HostMemoryBackend *pmrdev; @@ -165,6 +167,7 @@ typedef struct NvmeCtrl { NvmeSQueue admin_sq; NvmeCQueue admin_cq; NvmeIdCtrl id_ctrl; + void *id_ctrl_iocss[NVME_IOCS_MAX]; NvmeFeatureVal features; } NvmeCtrl; diff --git a/include/block/nvme.h b/include/block/nvme.h index 5a5e19f6bedc..792fccf8c81f 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -82,6 +82,11 @@ enum NvmeCapMask { #define NVME_CAP_SET_PMRS(cap, val) (cap |= (uint64_t)(val & CAP_PMR_MASK)\ << CAP_PMR_SHIFT) +enum NvmeCapCss { + NVME_CAP_CSS_NVM = 1 << 0, + NVME_CAP_CSS_CSI = 1 << 6, +}; + enum NvmeCcShift { CC_EN_SHIFT = 0, CC_CSS_SHIFT = 4, @@ -112,6 +117,7 @@ enum NvmeCcMask { enum NvmeCcCss { NVME_CC_CSS_NVM = 0x0, + NVME_CC_CSS_ALL = 0x6, NVME_CC_CSS_ADMIN_ONLY = 0x7, }; @@ -383,6 +389,11 @@ enum NvmePmrmscMask { #define NVME_PMRMSC_SET_CBA(pmrmsc, val) \ (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT) +enum NvmeCommandSet { + NVME_IOCS_NVM = 0x0, + NVME_IOCS_MAX = 0x1, +}; + enum NvmeSglDescriptorType { NVME_SGL_DESCR_TYPE_DATA_BLOCK = 0x0, NVME_SGL_DESCR_TYPE_BIT_BUCKET = 0x1, @@ -531,8 +542,13 @@ typedef struct QEMU_PACKED NvmeIdentify { uint64_t rsvd2[2]; uint64_t prp1; uint64_t prp2; - uint32_t cns; - uint32_t rsvd11[5]; + uint8_t cns; + uint8_t rsvd3; + uint16_t cntid; + uint16_t nvmsetid; + uint8_t rsvd4; + uint8_t csi; + uint32_t rsvd11[4]; } NvmeIdentify; typedef struct QEMU_PACKED NvmeRwCmd { @@ -624,8 +640,15 @@ typedef struct QEMU_PACKED NvmeAerResult { } NvmeAerResult; typedef struct QEMU_PACKED NvmeCqe { - uint32_t result; - uint32_t rsvd; + union { + struct { + uint32_t dw0; + uint32_t dw1; + }; + + uint64_t qw0; + }; + uint16_t sq_head; uint16_t sq_id; uint16_t cid; @@ -673,6 +696,10 @@ enum NvmeStatusCodes { NVME_FEAT_NOT_CHANGEABLE = 0x010e, NVME_FEAT_NOT_NS_SPEC = 0x010f, NVME_FW_REQ_SUSYSTEM_RESET = 0x0110, + NVME_IOCS_NOT_SUPPORTED = 0x0127, + NVME_IOCS_NOT_ENABLED = 0x0128, + NVME_IOCS_COMB_REJECTED = 0x0129, + NVME_INVALID_IOCS = 0x0126, NVME_CONFLICTING_ATTRS = 0x0180, NVME_INVALID_PROT_INFO = 0x0181, NVME_WRITE_TO_RO = 0x0182, @@ -734,6 +761,8 @@ typedef struct QEMU_PACKED NvmeSmartLog { uint8_t reserved2[320]; } NvmeSmartLog; +#define NVME_ACS_MAX 256 + typedef struct QEMU_PACKED NvmeEffectsLog { uint32_t acs[256]; uint32_t iocs[256]; @@ -782,10 +811,14 @@ typedef struct QEMU_PACKED NvmePSD { #define NVME_IDENTIFY_DATA_SIZE 4096 enum { - NVME_ID_CNS_NS = 0x0, - NVME_ID_CNS_CTRL = 0x1, - NVME_ID_CNS_NS_ACTIVE_LIST = 0x2, - NVME_ID_CNS_NS_DESCR_LIST = 0x3, + NVME_ID_CNS_NS = 0x00, + NVME_ID_CNS_CTRL = 0x01, + NVME_ID_CNS_NS_ACTIVE_LIST = 0x02, + NVME_ID_CNS_NS_DESCR_LIST = 0x03, + NVME_ID_CNS_NS_IOCS = 0x05, + NVME_ID_CNS_CTRL_IOCS = 0x06, + NVME_ID_CNS_NS_ACTIVE_LIST_IOCS = 0x07, + NVME_ID_CNS_IOCS = 0x1c, }; typedef struct QEMU_PACKED NvmeIdCtrl { @@ -935,6 +968,7 @@ enum NvmeFeatureIds { NVME_WRITE_ATOMICITY = 0xa, NVME_ASYNCHRONOUS_EVENT_CONF = 0xb, NVME_TIMESTAMP = 0xe, + NVME_COMMAND_SET_PROFILE = 0x19, NVME_SOFTWARE_PROGRESS_MARKER = 0x80, NVME_FID_MAX = 0x100, }; @@ -983,7 +1017,7 @@ typedef struct QEMU_PACKED NvmeLBAF { #define NVME_NSID_BROADCAST 0xffffffff -typedef struct QEMU_PACKED NvmeIdNs { +typedef struct QEMU_PACKED NvmeIdNsNvm { uint64_t nsze; uint64_t ncap; uint64_t nuse; @@ -1011,7 +1045,7 @@ typedef struct QEMU_PACKED NvmeIdNs { NvmeLBAF lbaf[16]; uint8_t rsvd192[192]; uint8_t vs[3712]; -} NvmeIdNs; +} NvmeIdNsNvm; typedef struct QEMU_PACKED NvmeIdNsDescr { uint8_t nidt; @@ -1023,12 +1057,14 @@ enum { NVME_NIDT_EUI64_LEN = 8, NVME_NIDT_NGUID_LEN = 16, NVME_NIDT_UUID_LEN = 16, + NVME_NIDT_CSI_LEN = 1, }; enum NvmeNsIdentifierType { NVME_NIDT_EUI64 = 0x1, NVME_NIDT_NGUID = 0x2, NVME_NIDT_UUID = 0x3, + NVME_NIDT_CSI = 0x4, }; /*Deallocate Logical Block Features*/ @@ -1081,7 +1117,7 @@ static inline void _nvme_check_size(void) QEMU_BUILD_BUG_ON(sizeof(NvmeFwSlotInfoLog) != 512); QEMU_BUILD_BUG_ON(sizeof(NvmeSmartLog) != 512); QEMU_BUILD_BUG_ON(sizeof(NvmeIdCtrl) != 4096); - QEMU_BUILD_BUG_ON(sizeof(NvmeIdNs) != 4096); + QEMU_BUILD_BUG_ON(sizeof(NvmeIdNsNvm) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeSglDescriptor) != 16); QEMU_BUILD_BUG_ON(sizeof(NvmeIdNsDescr) != 4); QEMU_BUILD_BUG_ON(sizeof(NvmeEffectsLog) != 4096); diff --git a/block/nvme.c b/block/nvme.c index f4f27b6da7d8..b5cc0185c298 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -336,7 +336,7 @@ static inline int nvme_translate_error(const NvmeCqe *c) { uint16_t status = (le16_to_cpu(c->status) >> 1) & 0xFF; if (status) { - trace_nvme_error(le32_to_cpu(c->result), + trace_nvme_error(le32_to_cpu(c->dw0), le16_to_cpu(c->sq_head), le16_to_cpu(c->sq_id), le16_to_cpu(c->cid), @@ -503,7 +503,7 @@ static void nvme_identify(BlockDriverState *bs, int namespace, Error **errp) BDRVNVMeState *s = bs->opaque; union { NvmeIdCtrl ctrl; - NvmeIdNs ns; + NvmeIdNsNvm ns; } *id; NvmeLBAF *lbaf; uint16_t oncs; diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 9a63004c000a..68b2ce3d17c5 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -57,10 +57,15 @@ static int nvme_blk_truncate(BlockBackend *blk, size_t len, Error **errp) static void nvme_ns_init(NvmeNamespace *ns) { - NvmeIdNs *id_ns = &ns->id_ns; + NvmeIdNsNvm *id_ns; + + ns->id_ns[NVME_IOCS_NVM] = g_new0(NvmeIdNsNvm, 1); + id_ns = nvme_ns_id_nvm(ns); + + ns->iocs = ns->params.iocs; if (blk_get_flags(ns->blkconf.blk) & BDRV_O_UNMAP) { - ns->id_ns.dlfeat = 0x9; + id_ns->dlfeat = 0x9; } id_ns->lbaf[0].ds = ns->params.lbads; @@ -170,6 +175,14 @@ static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp) return -1; } + switch (ns->params.iocs) { + case NVME_IOCS_NVM: + break; + default: + error_setg(errp, "unsupported iocs"); + return -1; + } + return 0; } @@ -194,7 +207,8 @@ int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) * With a pstate file in place we can enable the Deallocated or * Unwritten Logical Block Error feature. */ - ns->id_ns.nsfeat |= 0x4; + NvmeIdNsNvm *id_ns = nvme_ns_id_nvm(ns); + id_ns->nsfeat |= 0x4; } if (nvme_register_namespace(n, ns, errp)) { @@ -241,6 +255,7 @@ static Property nvme_ns_props[] = { DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0), DEFINE_PROP_UINT8("lbads", NvmeNamespace, params.lbads, BDRV_SECTOR_BITS), DEFINE_PROP_DRIVE("pstate", NvmeNamespace, pstate.blk), + DEFINE_PROP_UINT8("iocs", NvmeNamespace, params.iocs, NVME_IOCS_NVM), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 21f558f75559..f5578ea3bd63 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -102,6 +102,7 @@ static const bool nvme_feature_support[NVME_FID_MAX] = { [NVME_WRITE_ATOMICITY] = true, [NVME_ASYNCHRONOUS_EVENT_CONF] = true, [NVME_TIMESTAMP] = true, + [NVME_COMMAND_SET_PROFILE] = true, }; static const uint32_t nvme_feature_cap[NVME_FID_MAX] = { @@ -111,6 +112,7 @@ static const uint32_t nvme_feature_cap[NVME_FID_MAX] = { [NVME_NUMBER_OF_QUEUES] = NVME_FEAT_CAP_CHANGE, [NVME_ASYNCHRONOUS_EVENT_CONF] = NVME_FEAT_CAP_CHANGE, [NVME_TIMESTAMP] = NVME_FEAT_CAP_CHANGE, + [NVME_COMMAND_SET_PROFILE] = NVME_FEAT_CAP_CHANGE, }; #define NVME_EFFECTS_ADMIN_INITIALIZER \ @@ -143,13 +145,15 @@ static const NvmeEffectsLog nvme_effects_admin_only = { }, }; -static const NvmeEffectsLog nvme_effects = { - .acs = { - NVME_EFFECTS_ADMIN_INITIALIZER, - }, +static const NvmeEffectsLog nvme_effects[NVME_IOCS_MAX] = { + [NVME_IOCS_NVM] = { + .acs = { + NVME_EFFECTS_ADMIN_INITIALIZER, + }, - .iocs = { - NVME_EFFECTS_NVM_INITIALIZER, + .iocs = { + NVME_EFFECTS_NVM_INITIALIZER, + }, }, }; @@ -861,7 +865,7 @@ static void nvme_process_aers(void *opaque) req = n->aer_reqs[n->outstanding_aers]; - result = (NvmeAerResult *) &req->cqe.result; + result = (NvmeAerResult *) &req->cqe.dw0; result->event_type = event->result.event_type; result->event_info = event->result.event_info; result->log_page = event->result.log_page; @@ -921,7 +925,8 @@ static inline uint16_t nvme_check_mdts(NvmeCtrl *n, size_t len) static inline uint16_t nvme_check_bounds(NvmeCtrl *n, NvmeNamespace *ns, uint64_t slba, uint32_t nlb) { - uint64_t nsze = le64_to_cpu(ns->id_ns.nsze); + NvmeIdNsNvm *id_ns = nvme_ns_id_nvm(ns); + uint64_t nsze = le64_to_cpu(id_ns->nsze); if (unlikely(UINT64_MAX - slba < nlb || slba + nlb > nsze)) { return NVME_LBA_RANGE | NVME_DNR; @@ -1111,7 +1116,8 @@ static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) status = nvme_check_bounds(n, ns, slba, nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); + NvmeIdNsNvm *id_ns = nvme_ns_id_nvm(ns); + trace_pci_nvme_err_invalid_lba_range(slba, nlb, id_ns->nsze); goto invalid; } @@ -1157,9 +1163,10 @@ invalid: static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) { uint32_t nsid = le32_to_cpu(req->cmd.nsid); + uint8_t opc = req->cmd.opcode; trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req), - req->cmd.opcode, nvme_io_opc_str(req->cmd.opcode)); + opc, nvme_io_opc_str(req->cmd.opcode)); if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_ADMIN_ONLY) { return NVME_INVALID_OPCODE | NVME_DNR; @@ -1174,6 +1181,10 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) return NVME_INVALID_FIELD | NVME_DNR; } + if (!(nvme_effects[req->ns->iocs].iocs[opc] & NVME_EFFECTS_CSUPP)) { + return NVME_INVALID_OPCODE | NVME_DNR; + } + switch (req->cmd.opcode) { case NVME_CMD_FLUSH: return nvme_flush(n, req); @@ -1412,6 +1423,7 @@ static uint16_t nvme_effects_log(NvmeCtrl *n, uint32_t buf_len, uint64_t off, const NvmeEffectsLog *effects; uint32_t trans_len; + uint8_t csi = le32_to_cpu(req->cmd.cdw14) >> 24; if (off > sizeof(NvmeEffectsLog)) { return NVME_INVALID_FIELD | NVME_DNR; @@ -1423,7 +1435,17 @@ static uint16_t nvme_effects_log(NvmeCtrl *n, uint32_t buf_len, uint64_t off, break; case NVME_CC_CSS_NVM: - effects = &nvme_effects; + effects = &nvme_effects[NVME_IOCS_NVM]; + break; + + case NVME_CC_CSS_ALL: + if (!(n->iocscs[n->features.iocsci] & (1 << csi))) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + assert(csi < NVME_IOCS_MAX); + + effects = &nvme_effects[csi]; break; default: @@ -1593,39 +1615,94 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeRequest *req) return NVME_SUCCESS; } -static uint16_t nvme_identify_ctrl(NvmeCtrl *n, NvmeRequest *req) +static uint16_t nvme_identify_ctrl(NvmeCtrl *n, uint8_t cns, uint8_t csi, + NvmeRequest *req) { + NvmeIdCtrl empty = { 0 }; + NvmeIdCtrl *id_ctrl = ∅ + trace_pci_nvme_identify_ctrl(); - return nvme_dma(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl), + switch (cns) { + case NVME_ID_CNS_CTRL: + id_ctrl = &n->id_ctrl; + + break; + + case NVME_ID_CNS_CTRL_IOCS: + if (!(n->iocscs[n->features.iocsci] & (1 << csi))) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + assert(csi < NVME_IOCS_MAX); + + if (n->id_ctrl_iocss[csi]) { + id_ctrl = n->id_ctrl_iocss[csi]; + } + + break; + + default: + return NVME_INVALID_FIELD | NVME_DNR; + } + + return nvme_dma(n, (uint8_t *)id_ctrl, sizeof(*id_ctrl), DMA_DIRECTION_FROM_DEVICE, req); } -static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeRequest *req) +static uint16_t nvme_identify_ns(NvmeCtrl *n, uint8_t cns, uint8_t csi, + NvmeRequest *req) { + NvmeIdNsNvm empty = { 0 }; + void *id_ns = ∅ NvmeNamespace *ns; NvmeIdentify *c = (NvmeIdentify *)&req->cmd; - NvmeIdNs *id_ns, inactive = { 0 }; uint32_t nsid = le32_to_cpu(c->nsid); - trace_pci_nvme_identify_ns(nsid); + trace_pci_nvme_identify_ns(nsid, csi); if (!nvme_nsid_valid(n, nsid) || nsid == NVME_NSID_BROADCAST) { return NVME_INVALID_NSID | NVME_DNR; } ns = nvme_ns(n, nsid); - if (unlikely(!ns)) { - id_ns = &inactive; - } else { - id_ns = &ns->id_ns; + if (ns) { + switch (cns) { + case NVME_ID_CNS_NS: + id_ns = ns->id_ns[NVME_IOCS_NVM]; + if (!id_ns) { + return NVME_INVALID_IOCS | NVME_DNR; + } + + break; + + case NVME_ID_CNS_NS_IOCS: + if (csi == NVME_IOCS_NVM) { + break; + } + + if (csi >= NVME_IOCS_MAX) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + id_ns = ns->id_ns[csi]; + if (!id_ns) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + break; + + default: + return NVME_INVALID_FIELD | NVME_DNR; + } } - return nvme_dma(n, (uint8_t *)id_ns, sizeof(NvmeIdNs), + return nvme_dma(n, (uint8_t *)id_ns, NVME_IDENTIFY_DATA_SIZE, DMA_DIRECTION_FROM_DEVICE, req); } -static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req) +static uint16_t nvme_identify_nslist(NvmeCtrl *n, uint8_t cns, uint8_t csi, + NvmeRequest *req) { NvmeIdentify *c = (NvmeIdentify *)&req->cmd; static const int data_len = NVME_IDENTIFY_DATA_SIZE; @@ -1634,7 +1711,7 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req) uint16_t ret; int j = 0; - trace_pci_nvme_identify_nslist(min_nsid); + trace_pci_nvme_identify_nslist(min_nsid, csi); /* * Both 0xffffffff (NVME_NSID_BROADCAST) and 0xfffffffe are invalid values @@ -1646,11 +1723,21 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req) return NVME_INVALID_NSID | NVME_DNR; } + if (cns == NVME_ID_CNS_NS_ACTIVE_LIST_IOCS && !csi) { + return NVME_INVALID_FIELD | NVME_DNR; + } + list = g_malloc0(data_len); for (int i = 1; i <= n->num_namespaces; i++) { - if (i <= min_nsid || !nvme_ns(n, i)) { + NvmeNamespace *ns = nvme_ns(n, i); + if (i <= min_nsid || !ns) { continue; } + + if (cns == NVME_ID_CNS_NS_ACTIVE_LIST_IOCS && csi && csi != ns->iocs) { + continue; + } + list[j++] = cpu_to_le32(i); if (j == data_len / sizeof(uint32_t)) { break; @@ -1666,6 +1753,7 @@ static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeRequest *req) { NvmeIdentify *c = (NvmeIdentify *)&req->cmd; uint32_t nsid = le32_to_cpu(c->nsid); + NvmeNamespace *ns; uint8_t list[NVME_IDENTIFY_DATA_SIZE]; struct data { @@ -1673,6 +1761,11 @@ static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeRequest *req) NvmeIdNsDescr hdr; uint8_t v[16]; } uuid; + + struct { + NvmeIdNsDescr hdr; + uint8_t v; + } iocs; }; struct data *ns_descrs = (struct data *)list; @@ -1683,7 +1776,8 @@ static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeRequest *req) return NVME_INVALID_NSID | NVME_DNR; } - if (unlikely(!nvme_ns(n, nsid))) { + ns = nvme_ns(n, nsid); + if (unlikely(!ns)) { return NVME_INVALID_FIELD | NVME_DNR; } @@ -1699,25 +1793,45 @@ static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeRequest *req) ns_descrs->uuid.hdr.nidl = NVME_NIDT_UUID_LEN; stl_be_p(&ns_descrs->uuid.v, nsid); + ns_descrs->iocs.hdr.nidt = NVME_NIDT_CSI; + ns_descrs->iocs.hdr.nidl = NVME_NIDT_CSI_LEN; + stb_p(&ns_descrs->iocs.v, ns->iocs); + return nvme_dma(n, list, NVME_IDENTIFY_DATA_SIZE, DMA_DIRECTION_FROM_DEVICE, req); } +static uint16_t nvme_identify_iocs(NvmeCtrl *n, uint16_t cntid, + NvmeRequest *req) +{ + return nvme_dma(n, (uint8_t *) n->iocscs, sizeof(n->iocscs), + DMA_DIRECTION_FROM_DEVICE, req); +} + static uint16_t nvme_identify(NvmeCtrl *n, NvmeRequest *req) { NvmeIdentify *c = (NvmeIdentify *)&req->cmd; + trace_pci_nvme_identify(nvme_cid(req), le32_to_cpu(c->nsid), + le16_to_cpu(c->cntid), c->cns, c->csi, + le16_to_cpu(c->nvmsetid)); + switch (le32_to_cpu(c->cns)) { case NVME_ID_CNS_NS: - return nvme_identify_ns(n, req); + case NVME_ID_CNS_NS_IOCS: + return nvme_identify_ns(n, c->cns, c->csi, req); case NVME_ID_CNS_CTRL: - return nvme_identify_ctrl(n, req); + case NVME_ID_CNS_CTRL_IOCS: + return nvme_identify_ctrl(n, c->cns, c->csi, req); case NVME_ID_CNS_NS_ACTIVE_LIST: - return nvme_identify_nslist(n, req); + case NVME_ID_CNS_NS_ACTIVE_LIST_IOCS: + return nvme_identify_nslist(n, c->cns, c->csi, req); case NVME_ID_CNS_NS_DESCR_LIST: return nvme_identify_ns_descr_list(n, req); + case NVME_ID_CNS_IOCS: + return nvme_identify_iocs(n, c->cntid, req); default: - trace_pci_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns)); + trace_pci_nvme_err_invalid_identify_cns(c->cns); return NVME_INVALID_FIELD | NVME_DNR; } } @@ -1726,7 +1840,7 @@ static uint16_t nvme_abort(NvmeCtrl *n, NvmeRequest *req) { uint16_t sqid = le32_to_cpu(req->cmd.cdw10) & 0xffff; - req->cqe.result = 1; + req->cqe.dw0 = 1; if (nvme_check_sqid(n, sqid)) { return NVME_INVALID_FIELD | NVME_DNR; } @@ -1911,6 +2025,9 @@ defaults: result |= NVME_INTVC_NOCOALESCING; } + break; + case NVME_COMMAND_SET_PROFILE: + result = cpu_to_le32(n->features.iocsci & 0x1ff); break; default: result = nvme_feature_default[fid]; @@ -1918,7 +2035,8 @@ defaults: } out: - req->cqe.result = cpu_to_le32(result); + req->cqe.dw0 = cpu_to_le32(result); + return NVME_SUCCESS; } @@ -1941,6 +2059,7 @@ static uint16_t nvme_set_feature_timestamp(NvmeCtrl *n, NvmeRequest *req) static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) { NvmeNamespace *ns = NULL; + NvmeIdNsNvm *id_ns; NvmeCmd *cmd = &req->cmd; uint32_t dw10 = le32_to_cpu(cmd->cdw10); @@ -2017,7 +2136,8 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) continue; } - if (NVME_ID_NS_NSFEAT_DULBE(ns->id_ns.nsfeat)) { + id_ns = nvme_ns_id_nvm(ns); + if (NVME_ID_NS_NSFEAT_DULBE(id_ns->nsfeat)) { ns->features.err_rec = dw11; } } @@ -2033,6 +2153,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) for (int i = 1; i <= n->num_namespaces; i++) { ns = nvme_ns(n, i); + if (!ns) { continue; } @@ -2063,14 +2184,34 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) ((dw11 >> 16) & 0xFFFF) + 1, n->params.max_ioqpairs, n->params.max_ioqpairs); - req->cqe.result = cpu_to_le32((n->params.max_ioqpairs - 1) | - ((n->params.max_ioqpairs - 1) << 16)); + req->cqe.dw0 = cpu_to_le32((n->params.max_ioqpairs - 1) | + ((n->params.max_ioqpairs - 1) << 16)); break; case NVME_ASYNCHRONOUS_EVENT_CONF: n->features.async_config = dw11; break; case NVME_TIMESTAMP: return nvme_set_feature_timestamp(n, req); + case NVME_COMMAND_SET_PROFILE: + if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_ALL) { + uint16_t iocsci = dw11 & 0x1ff; + uint64_t iocsc = n->iocscs[iocsci]; + + for (int i = 1; i <= n->num_namespaces; i++) { + ns = nvme_ns(n, i); + if (!ns) { + continue; + } + + if (!(iocsc & (1 << ns->iocs))) { + return NVME_IOCS_COMB_REJECTED | NVME_DNR; + } + } + + n->features.iocsci = iocsci; + } + + break; default: return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR; } @@ -2217,6 +2358,8 @@ static int nvme_start_ctrl(NvmeCtrl *n) uint32_t page_bits = NVME_CC_MPS(n->bar.cc) + 12; uint32_t page_size = 1 << page_bits; + NvmeIdCtrl *id_ctrl = &n->id_ctrl; + if (unlikely(n->cq[0])) { trace_pci_nvme_err_startfail_cq(); return -1; @@ -2256,28 +2399,28 @@ static int nvme_start_ctrl(NvmeCtrl *n) return -1; } if (unlikely(NVME_CC_IOCQES(n->bar.cc) < - NVME_CTRL_CQES_MIN(n->id_ctrl.cqes))) { + NVME_CTRL_CQES_MIN(id_ctrl->cqes))) { trace_pci_nvme_err_startfail_cqent_too_small( NVME_CC_IOCQES(n->bar.cc), NVME_CTRL_CQES_MIN(n->bar.cap)); return -1; } if (unlikely(NVME_CC_IOCQES(n->bar.cc) > - NVME_CTRL_CQES_MAX(n->id_ctrl.cqes))) { + NVME_CTRL_CQES_MAX(id_ctrl->cqes))) { trace_pci_nvme_err_startfail_cqent_too_large( NVME_CC_IOCQES(n->bar.cc), NVME_CTRL_CQES_MAX(n->bar.cap)); return -1; } if (unlikely(NVME_CC_IOSQES(n->bar.cc) < - NVME_CTRL_SQES_MIN(n->id_ctrl.sqes))) { + NVME_CTRL_SQES_MIN(id_ctrl->sqes))) { trace_pci_nvme_err_startfail_sqent_too_small( NVME_CC_IOSQES(n->bar.cc), NVME_CTRL_SQES_MIN(n->bar.cap)); return -1; } if (unlikely(NVME_CC_IOSQES(n->bar.cc) > - NVME_CTRL_SQES_MAX(n->id_ctrl.sqes))) { + NVME_CTRL_SQES_MAX(id_ctrl->sqes))) { trace_pci_nvme_err_startfail_sqent_too_large( NVME_CC_IOSQES(n->bar.cc), NVME_CTRL_SQES_MAX(n->bar.cap)); @@ -2738,6 +2881,8 @@ static void nvme_init_state(NvmeCtrl *n) n->features.temp_thresh_hi = NVME_TEMPERATURE_WARNING; n->starttime_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); n->aer_reqs = g_new0(NvmeRequest *, n->params.aerl + 1); + n->iocscs[0] = 1 << NVME_IOCS_NVM; + n->features.iocsci = 0; } int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) @@ -2942,7 +3087,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) NVME_CAP_SET_MQES(n->bar.cap, 0x7ff); NVME_CAP_SET_CQR(n->bar.cap, 1); NVME_CAP_SET_TO(n->bar.cap, 0xf); - NVME_CAP_SET_CSS(n->bar.cap, 1); + NVME_CAP_SET_CSS(n->bar.cap, (NVME_CAP_CSS_NVM | NVME_CAP_CSS_CSI)); NVME_CAP_SET_MPSMAX(n->bar.cap, 4); n->bar.vs = NVME_SPEC_VER; @@ -3002,6 +3147,11 @@ static void nvme_exit(PCIDevice *pci_dev) if (n->pmrdev) { host_memory_backend_set_mapped(n->pmrdev, false); } + + for (int i = 0; i < NVME_IOCS_MAX; i++) { + g_free(n->id_ctrl_iocss[i]); + } + msix_uninit_exclusive_bar(pci_dev); } diff --git a/hw/block/trace-events b/hw/block/trace-events index 774513469274..b002eb7c8a5c 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -48,10 +48,12 @@ pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d" pci_nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16"" pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16"" +pci_nvme_identify(uint16_t cid, uint32_t nsid, uint16_t cntid, uint8_t cns, uint8_t csi, uint16_t nvmsetid) "cid %"PRIu16" nsid %"PRIu32" cntid 0x%"PRIx16" cns 0x%"PRIx8" csi 0x%"PRIx8" nvmsetid %"PRIu16"" pci_nvme_identify_ctrl(void) "identify controller" -pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32"" -pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32"" +pci_nvme_identify_ns(uint32_t ns, uint8_t csi) "nsid %"PRIu32" csi 0x%"PRIx8"" +pci_nvme_identify_nslist(uint32_t ns, uint8_t csi) "nsid %"PRIu32" csi 0x%"PRIx8"" pci_nvme_identify_ns_descr_list(uint32_t ns) "nsid %"PRIu32"" +pci_nvme_identify_io_cmd_set(uint16_t cid) "cid %"PRIu16"" pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64"" pci_nvme_getfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32"" pci_nvme_setfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32"" From patchwork Thu Sep 24 20:45:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 304469 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DA11EC4363D for ; Thu, 24 Sep 2020 21:21:47 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 1E12B2311E for ; Thu, 24 Sep 2020 21:21:47 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1E12B2311E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:60618 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYgT-0008Ez-Sb for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 17:21:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38614) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7X-0004XR-Sq; Thu, 24 Sep 2020 16:45:39 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:32803) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7R-0007nE-GZ; Thu, 24 Sep 2020 16:45:37 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id 9F968580100; Thu, 24 Sep 2020 16:45:32 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:32 -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=fm1; bh=x5lAhYM4DIK26 nOUHLcDkay1bTygPFvF11BcZQASjuI=; b=CFhg7kl3HqCQYOA+pyfUZiVs3ePKH B61q7czVlwJWUyOdrf4B/YnaZ9SRZEX/RZ0rtu4wu5ANnnT0PEcjlU4rrDkoKi79 yZdiKr9olykVmWauN1nT5f7/pAHIUb6nm7kdxHwIge3dICmKElJyHxBvVuDqPGDx gUu/fwHAkSHfBFEm/v6UOorqRZ45Qdnf+2x6ycwQSXfbO1mtFc1CyhhF7uuvJqlx NXkPb5ujfNmORJ/4dm0fOSdPDmOS/9EVfetwQ1LTqFrIb12SIZsrvA9DvUOAjPJn /o5ZktGkoGvTbguMMA5gjmU1rTSHws8k7Wnizr2m5wTbPmoo32nHeky3g== 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= fm3; bh=x5lAhYM4DIK26nOUHLcDkay1bTygPFvF11BcZQASjuI=; b=hiStEgoV faPrcy92K5WHnrLYYhzf9sCJzhRLL9M9mjfIXiIpzdrV59S3dSpc3a6Pj4Xb3pG4 mb0JkpGv1SzLvLYYXdXrN14pRxmnLiicyufLaoTTAfahqHwozlzyEYnJWKiT4u/k qFCzz7xoq++GGpwd9y2N+PedWGBDLhltqTkScblEVQpgbklsctp+1WfFIfW9kX5A YSX9O+U1GJGW3pwmfAWRodIleFMa9iU16QngkfyI9w5sB8WoLrZaxI0pUUKMkGP4 1JhJvm01hNpIQAVLDmw6XFrX6BJ+lwmqH3wqlXQb/3uXMtwqmI9Pg0RLuzcbZ1W3 JYAp2YQtYrfMQQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeekudehfeethfdvvdegieffheekueeghefhudfghffhhfevjeejffeuhedugedu udenucffohhmrghinhepuhhtihhlihiirghtihhonhdrmhgrphenucfkphepkedtrdduie ejrdelkedrudeltdenucevlhhushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhl fhhrohhmpehithhssehirhhrvghlvghvrghnthdrughk 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 012D4306467D; Thu, 24 Sep 2020 16:45:29 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 09/16] hw/block/nvme: add basic read/write for zoned namespaces Date: Thu, 24 Sep 2020 22:45:09 +0200 Message-Id: <20200924204516.1881843-10-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen This adds basic read and write for zoned namespaces. A zoned namespace is created by setting the iocs namespace parameter to 0x2 and specifying the zns.zcap parameter (zone capacity) in number of logical blocks per zone. If a zone size (zns.zsze) is not specified, the namespace device will set the zone size to be the next power of two and fit in as many zones as possible on the underlying namespace blockdev. This behavior is not required by the specification, but ensures that the device can be initialized by the Linux kernel nvme driver, which requires a power of two zone size. If the namespace has an associated 'pstate' blockdev it will be used to store the zone states persistently. Only zone state changes are persisted, that is, zone write pointer updates are only persistent if the zone is explicitly closed. On boot up, any zones that were in an Opened state will be transitioned to Full. Signed-off-by: Klaus Jensen --- docs/specs/nvme.txt | 7 ++ hw/block/nvme-ns.h | 104 ++++++++++++++++++++ include/block/nvme.h | 59 ++++++++++- hw/block/nvme-ns.c | 145 +++++++++++++++++++++++++-- hw/block/nvme.c | 221 +++++++++++++++++++++++++++++++++++++++++- hw/block/trace-events | 8 ++ 6 files changed, 534 insertions(+), 10 deletions(-) diff --git a/docs/specs/nvme.txt b/docs/specs/nvme.txt index 890990510b14..82def65d4c78 100644 --- a/docs/specs/nvme.txt +++ b/docs/specs/nvme.txt @@ -22,6 +22,13 @@ nvme-ns Options `iocs`; The "I/O Command Set" associated with the namespace. E.g. 0x0 for the NVM Command Set (the default), or 0x2 for the Zoned Namespace Command Set. + `zns.zcap`; If `iocs` is 0x2, this specifies the zone capacity. It is + specified in units of logical blocks. + + `zns.zsze`; If `iocs` is 0x2, this specifies the zone size. It is specified + in units of the logical blocks. If not specified, the value depends on + zns.zcap; if the zone capacity is a power of two, the zone size will be + set to that, otherwise it will default to the next power of two. Reference Specifications ------------------------ diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index 06c0bc8b32a4..c15bfcfc5a08 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -23,8 +23,19 @@ typedef struct NvmeNamespaceParams { uint32_t nsid; uint8_t iocs; uint8_t lbads; + + struct { + uint64_t zcap; + uint64_t zsze; + } zns; } NvmeNamespaceParams; +typedef struct NvmeZone { + NvmeZoneDescriptor *zd; + + uint64_t wp_staging; +} NvmeZone; + typedef struct NvmeNamespace { DeviceState parent_obj; BlockConf blkconf; @@ -40,6 +51,10 @@ typedef struct NvmeNamespace { unsigned long *map; int64_t offset; } utilization; + + struct { + int64_t offset; + } zns; } pstate; NvmeNamespaceParams params; @@ -47,8 +62,20 @@ typedef struct NvmeNamespace { struct { uint32_t err_rec; } features; + + struct { + int num_zones; + + NvmeZone *zones; + NvmeZoneDescriptor *zd; + } zns; } NvmeNamespace; +static inline bool nvme_ns_zoned(NvmeNamespace *ns) +{ + return ns->iocs == NVME_IOCS_ZONED; +} + static inline uint32_t nvme_nsid(NvmeNamespace *ns) { if (ns) { @@ -63,17 +90,39 @@ static inline NvmeIdNsNvm *nvme_ns_id_nvm(NvmeNamespace *ns) return ns->id_ns[NVME_IOCS_NVM]; } +static inline NvmeIdNsZns *nvme_ns_id_zoned(NvmeNamespace *ns) +{ + return ns->id_ns[NVME_IOCS_ZONED]; +} + static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns) { NvmeIdNsNvm *id_ns = nvme_ns_id_nvm(ns); return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; } +static inline NvmeLBAFE *nvme_ns_lbafe(NvmeNamespace *ns) +{ + NvmeIdNsNvm *id_ns = nvme_ns_id_nvm(ns); + NvmeIdNsZns *id_ns_zns = nvme_ns_id_zoned(ns); + return &id_ns_zns->lbafe[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; +} + static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns) { return nvme_ns_lbaf(ns)->ds; } +static inline uint64_t nvme_ns_zsze(NvmeNamespace *ns) +{ + return nvme_ns_lbafe(ns)->zsze; +} + +static inline uint64_t nvme_ns_zsze_bytes(NvmeNamespace *ns) +{ + return nvme_ns_zsze(ns) << nvme_ns_lbads(ns); +} + /* calculate the number of LBAs that the namespace can accomodate */ static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns) { @@ -86,8 +135,63 @@ static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba) return lba << nvme_ns_lbads(ns); } +static inline int nvme_ns_zone_idx(NvmeNamespace *ns, uint64_t lba) +{ + return lba / nvme_ns_zsze(ns); +} + +static inline NvmeZone *nvme_ns_get_zone(NvmeNamespace *ns, uint64_t lba) +{ + int idx = nvme_ns_zone_idx(ns, lba); + if (unlikely(idx >= ns->zns.num_zones)) { + return NULL; + } + + return &ns->zns.zones[idx]; +} + +static inline NvmeZoneState nvme_zs(NvmeZone *zone) +{ + return (zone->zd->zs >> 4) & 0xf; +} + +static inline void nvme_zs_set(NvmeZone *zone, NvmeZoneState zs) +{ + zone->zd->zs = zs << 4; +} + +static inline bool nvme_ns_zone_wp_valid(NvmeZone *zone) +{ + switch (nvme_zs(zone)) { + case NVME_ZS_ZSF: + case NVME_ZS_ZSRO: + case NVME_ZS_ZSO: + return false; + default: + return false; + } +} + +static inline uint64_t nvme_zslba(NvmeZone *zone) +{ + return le64_to_cpu(zone->zd->zslba); +} + +static inline uint64_t nvme_zcap(NvmeZone *zone) +{ + return le64_to_cpu(zone->zd->zcap); +} + +static inline uint64_t nvme_wp(NvmeZone *zone) +{ + return le64_to_cpu(zone->zd->wp); +} + typedef struct NvmeCtrl NvmeCtrl; +const char *nvme_zs_str(NvmeZone *zone); +const char *nvme_zs_to_str(NvmeZoneState zs); + int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp); void nvme_ns_drain(NvmeNamespace *ns); void nvme_ns_flush(NvmeNamespace *ns); diff --git a/include/block/nvme.h b/include/block/nvme.h index 792fccf8c81f..2e523c9d97b4 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -390,8 +390,9 @@ enum NvmePmrmscMask { (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT) enum NvmeCommandSet { - NVME_IOCS_NVM = 0x0, - NVME_IOCS_MAX = 0x1, + NVME_IOCS_NVM = 0x0, + NVME_IOCS_ZONED = 0x2, + NVME_IOCS_MAX = 0x3, }; enum NvmeSglDescriptorType { @@ -703,6 +704,11 @@ enum NvmeStatusCodes { NVME_CONFLICTING_ATTRS = 0x0180, NVME_INVALID_PROT_INFO = 0x0181, NVME_WRITE_TO_RO = 0x0182, + NVME_ZONE_BOUNDARY_ERROR = 0x01b8, + NVME_ZONE_IS_FULL = 0x01b9, + NVME_ZONE_IS_READ_ONLY = 0x01ba, + NVME_ZONE_IS_OFFLINE = 0x01bb, + NVME_ZONE_INVALID_WRITE = 0x01bc, NVME_WRITE_FAULT = 0x0280, NVME_UNRECOVERED_READ = 0x0281, NVME_E2E_GUARD_ERROR = 0x0282, @@ -781,6 +787,31 @@ enum { NVME_EFFECTS_UUID_SEL = 1 << 19, }; +typedef enum NvmeZoneType { + NVME_ZT_SEQ = 0x2, +} NvmeZoneType; + +typedef enum NvmeZoneState { + NVME_ZS_ZSE = 0x1, + NVME_ZS_ZSIO = 0x2, + NVME_ZS_ZSEO = 0x3, + NVME_ZS_ZSC = 0x4, + NVME_ZS_ZSRO = 0xd, + NVME_ZS_ZSF = 0xe, + NVME_ZS_ZSO = 0xf, +} NvmeZoneState; + +typedef struct QEMU_PACKED NvmeZoneDescriptor { + uint8_t zt; + uint8_t zs; + uint8_t za; + uint8_t rsvd3[5]; + uint64_t zcap; + uint64_t zslba; + uint64_t wp; + uint8_t rsvd32[32]; +} NvmeZoneDescriptor; + enum NvmeSmartWarn { NVME_SMART_SPARE = 1 << 0, NVME_SMART_TEMPERATURE = 1 << 1, @@ -794,6 +825,7 @@ enum NvmeLogIdentifier { NVME_LOG_SMART_INFO = 0x02, NVME_LOG_FW_SLOT_INFO = 0x03, NVME_LOG_EFFECTS = 0x05, + NVME_LOG_CHANGED_ZONE_LIST = 0xbf, }; typedef struct QEMU_PACKED NvmePSD { @@ -1099,9 +1131,27 @@ enum NvmeIdNsDps { DPS_FIRST_EIGHT = 8, }; +typedef struct QEMU_PACKED NvmeLBAFE { + uint64_t zsze; + uint8_t zdes; + uint8_t rsvd9[7]; +} NvmeLBAFE; + +typedef struct QEMU_PACKED NvmeIdNsZns { + uint16_t zoc; + uint16_t ozcs; + uint32_t mar; + uint32_t mor; + uint32_t rrl; + uint32_t frl; + uint8_t rsvd20[2796]; + NvmeLBAFE lbafe[16]; + uint8_t rsvd3072[768]; + uint8_t vs[256]; +} NvmeIdNsZns; + static inline void _nvme_check_size(void) { - QEMU_BUILD_BUG_ON(sizeof(NvmeBar) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeAerResult) != 4); QEMU_BUILD_BUG_ON(sizeof(NvmeCqe) != 16); QEMU_BUILD_BUG_ON(sizeof(NvmeDsmRange) != 16); @@ -1118,8 +1168,11 @@ static inline void _nvme_check_size(void) QEMU_BUILD_BUG_ON(sizeof(NvmeSmartLog) != 512); QEMU_BUILD_BUG_ON(sizeof(NvmeIdCtrl) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeIdNsNvm) != 4096); + QEMU_BUILD_BUG_ON(sizeof(NvmeIdNsZns) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeSglDescriptor) != 16); QEMU_BUILD_BUG_ON(sizeof(NvmeIdNsDescr) != 4); QEMU_BUILD_BUG_ON(sizeof(NvmeEffectsLog) != 4096); + QEMU_BUILD_BUG_ON(sizeof(NvmeZoneDescriptor) != 64); + QEMU_BUILD_BUG_ON(sizeof(NvmeLBAFE) != 16); } #endif diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 68b2ce3d17c5..872c46f2f2f0 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -30,6 +30,26 @@ #include "nvme.h" #include "nvme-ns.h" +const char *nvme_zs_str(NvmeZone *zone) +{ + return nvme_zs_to_str(nvme_zs(zone)); +} + +const char *nvme_zs_to_str(NvmeZoneState zs) +{ + switch (zs) { + case NVME_ZS_ZSE: return "ZSE"; + case NVME_ZS_ZSIO: return "ZSIO"; + case NVME_ZS_ZSEO: return "ZSEO"; + case NVME_ZS_ZSC: return "ZSC"; + case NVME_ZS_ZSRO: return "ZSRO"; + case NVME_ZS_ZSF: return "ZSF"; + case NVME_ZS_ZSO: return "ZSO"; + } + + return NULL; +} + static int nvme_blk_truncate(BlockBackend *blk, size_t len, Error **errp) { int ret; @@ -55,6 +75,47 @@ static int nvme_blk_truncate(BlockBackend *blk, size_t len, Error **errp) return 0; } +static void nvme_ns_zns_init_zones(NvmeNamespace *ns) +{ + NvmeZone *zone; + NvmeZoneDescriptor *zd; + uint64_t zslba, zsze = nvme_ns_zsze(ns); + + for (int i = 0; i < ns->zns.num_zones; i++) { + zslba = i * zsze; + zone = nvme_ns_get_zone(ns, zslba); + zone->zd = &ns->zns.zd[i]; + + zd = zone->zd; + + zd->zt = NVME_ZT_SEQ; + nvme_zs_set(zone, NVME_ZS_ZSE); + zd->zcap = ns->params.zns.zcap; + zone->wp_staging = zslba; + zd->wp = zd->zslba = cpu_to_le64(zslba); + } +} + +static void nvme_ns_init_zoned(NvmeNamespace *ns) +{ + NvmeIdNsNvm *id_ns = nvme_ns_id_nvm(ns); + NvmeIdNsZns *id_ns_zns = nvme_ns_id_zoned(ns); + + for (int i = 0; i <= id_ns->nlbaf; i++) { + id_ns_zns->lbafe[i].zsze = ns->params.zns.zsze ? + ns->params.zns.zsze : cpu_to_le64(pow2ceil(ns->params.zns.zcap)); + } + + ns->zns.num_zones = nvme_ns_nlbas(ns) / nvme_ns_zsze(ns); + ns->zns.zones = g_malloc0_n(ns->zns.num_zones, sizeof(NvmeZone)); + ns->zns.zd = g_malloc0_n(ns->zns.num_zones, sizeof(NvmeZoneDescriptor)); + + id_ns->ncap = ns->zns.num_zones * ns->params.zns.zcap; + + id_ns_zns->mar = 0xffffffff; + id_ns_zns->mor = 0xffffffff; +} + static void nvme_ns_init(NvmeNamespace *ns) { NvmeIdNsNvm *id_ns; @@ -71,9 +132,14 @@ static void nvme_ns_init(NvmeNamespace *ns) id_ns->lbaf[0].ds = ns->params.lbads; id_ns->nsze = cpu_to_le64(nvme_ns_nlbas(ns)); + id_ns->ncap = id_ns->nsze; + + if (ns->iocs == NVME_IOCS_ZONED) { + ns->id_ns[NVME_IOCS_ZONED] = g_new0(NvmeIdNsZns, 1); + nvme_ns_init_zoned(ns); + } /* no thin provisioning */ - id_ns->ncap = id_ns->nsze; id_ns->nuse = id_ns->ncap; } @@ -82,7 +148,7 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) BlockBackend *blk = ns->pstate.blk; uint64_t perm, shared_perm; ssize_t len; - size_t pstate_len; + size_t util_len, zd_len, pstate_len; int ret; perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; @@ -93,8 +159,10 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) return ret; } - pstate_len = ROUND_UP(DIV_ROUND_UP(nvme_ns_nlbas(ns), 8), - BDRV_SECTOR_SIZE); + util_len = DIV_ROUND_UP(nvme_ns_nlbas(ns), 8); + zd_len = nvme_ns_zoned(ns) ? + ns->zns.num_zones * sizeof(NvmeZoneDescriptor) : 0; + pstate_len = ROUND_UP(util_len + zd_len, BDRV_SECTOR_SIZE); len = blk_getlength(blk); if (len < 0) { @@ -105,6 +173,8 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) unsigned long *map = bitmap_new(nvme_ns_nlbas(ns)); ns->pstate.utilization.offset = 0; + ns->pstate.zns.offset = util_len; + if (!len) { ret = nvme_blk_truncate(blk, pstate_len, errp); if (ret < 0) { @@ -112,6 +182,10 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) } ns->pstate.utilization.map = map; + + if (nvme_ns_zoned(ns)) { + nvme_ns_zns_init_zones(ns); + } } else { if (len != pstate_len) { error_setg(errp, "pstate size mismatch " @@ -120,7 +194,7 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) return -1; } - ret = blk_pread(blk, 0, map, pstate_len); + ret = blk_pread(blk, 0, map, util_len); if (ret < 0) { error_setg_errno(errp, -ret, "could not read pstate"); return ret; @@ -132,7 +206,48 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) ns->pstate.utilization.map = map; #endif - return 0; + if (nvme_ns_zoned(ns)) { + ret = blk_pread(blk, util_len, ns->zns.zd, zd_len); + if (ret < 0) { + error_setg_errno(errp, -ret, "could not read pstate"); + return ret; + } + + for (int i = 0; i < ns->zns.num_zones; i++) { + NvmeZone *zone = &ns->zns.zones[i]; + zone->zd = &ns->zns.zd[i]; + + zone->wp_staging = nvme_wp(zone); + + switch (nvme_zs(zone)) { + case NVME_ZS_ZSE: + case NVME_ZS_ZSF: + case NVME_ZS_ZSRO: + case NVME_ZS_ZSO: + continue; + + case NVME_ZS_ZSC: + if (nvme_wp(zone) == nvme_zslba(zone)) { + nvme_zs_set(zone, NVME_ZS_ZSE); + } + + continue; + + case NVME_ZS_ZSIO: + case NVME_ZS_ZSEO: + zone->zd->wp = zone->zd->zslba; + nvme_zs_set(zone, NVME_ZS_ZSF); + } + } + } + } + + if (nvme_ns_zoned(ns)) { + ret = blk_pwrite(blk, util_len, ns->zns.zd, zd_len, 0); + if (ret < 0) { + error_setg_errno(errp, -ret, "could not write pstate"); + return ret; + } } return 0; @@ -178,6 +293,20 @@ static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp) switch (ns->params.iocs) { case NVME_IOCS_NVM: break; + + case NVME_IOCS_ZONED: + if (!ns->params.zns.zcap) { + error_setg(errp, "zns.zcap must be specified"); + return -1; + } + + if (ns->params.zns.zsze && ns->params.zns.zsze < ns->params.zns.zcap) { + error_setg(errp, "zns.zsze cannot be less than zns.zcap"); + return -1; + } + + break; + default: error_setg(errp, "unsupported iocs"); return -1; @@ -209,6 +338,8 @@ int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) */ NvmeIdNsNvm *id_ns = nvme_ns_id_nvm(ns); id_ns->nsfeat |= 0x4; + } else if (nvme_ns_zoned(ns)) { + nvme_ns_zns_init_zones(ns); } if (nvme_register_namespace(n, ns, errp)) { @@ -256,6 +387,8 @@ static Property nvme_ns_props[] = { DEFINE_PROP_UINT8("lbads", NvmeNamespace, params.lbads, BDRV_SECTOR_BITS), DEFINE_PROP_DRIVE("pstate", NvmeNamespace, pstate.blk), DEFINE_PROP_UINT8("iocs", NvmeNamespace, params.iocs, NVME_IOCS_NVM), + DEFINE_PROP_UINT64("zns.zcap", NvmeNamespace, params.zns.zcap, 0), + DEFINE_PROP_UINT64("zns.zsze", NvmeNamespace, params.zns.zsze, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index f5578ea3bd63..b0179291b966 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -155,6 +155,16 @@ static const NvmeEffectsLog nvme_effects[NVME_IOCS_MAX] = { NVME_EFFECTS_NVM_INITIALIZER, }, }, + + [NVME_IOCS_ZONED] = { + .acs = { + NVME_EFFECTS_ADMIN_INITIALIZER, + }, + + .iocs = { + NVME_EFFECTS_NVM_INITIALIZER, + }, + }, }; static void nvme_process_sq(void *opaque); @@ -911,6 +921,112 @@ static void nvme_clear_events(NvmeCtrl *n, uint8_t event_type) } } +static uint16_t nvme_check_zone_readable(NvmeCtrl *n, NvmeRequest *req, + NvmeZone *zone) +{ + NvmeZoneState zs = nvme_zs(zone); + uint64_t zslba = nvme_zslba(zone); + + if (zs == NVME_ZS_ZSO) { + trace_pci_nvme_err_invalid_zone_condition(nvme_cid(req), zslba, + NVME_ZS_ZSO); + return NVME_ZONE_IS_OFFLINE | NVME_DNR; + } + + return NVME_SUCCESS; +} + +static uint16_t nvme_check_zone_read(NvmeCtrl *n, uint64_t slba, uint32_t nlb, + NvmeRequest *req, NvmeZone *zone) +{ + NvmeNamespace *ns = req->ns; + uint64_t zslba = nvme_zslba(zone); + uint64_t zsze = nvme_ns_zsze(ns); + uint16_t status; + + status = nvme_check_zone_readable(n, req, zone); + if (status) { + return status; + } + + if ((slba + nlb) > (zslba + zsze)) { + trace_pci_nvme_err_zone_boundary(nvme_cid(req), slba, nlb, zsze); + return NVME_ZONE_BOUNDARY_ERROR | NVME_DNR; + } + + return NVME_SUCCESS; +} + +static uint16_t nvme_check_zone_writeable(NvmeCtrl *n, NvmeRequest *req, + NvmeZone *zone) +{ + NvmeZoneState zs = nvme_zs(zone); + uint64_t zslba = nvme_zslba(zone); + + if (zs == NVME_ZS_ZSO) { + trace_pci_nvme_err_invalid_zone_condition(nvme_cid(req), zslba, + NVME_ZS_ZSO); + return NVME_ZONE_IS_OFFLINE | NVME_DNR; + } + + switch (zs) { + case NVME_ZS_ZSE: + case NVME_ZS_ZSC: + case NVME_ZS_ZSIO: + case NVME_ZS_ZSEO: + return NVME_SUCCESS; + case NVME_ZS_ZSF: + trace_pci_nvme_err_zone_is_full(nvme_cid(req), zslba); + return NVME_ZONE_IS_FULL | NVME_DNR; + case NVME_ZS_ZSRO: + trace_pci_nvme_err_zone_is_read_only(nvme_cid(req), zslba); + return NVME_ZONE_IS_READ_ONLY | NVME_DNR; + default: + break; + } + + trace_pci_nvme_err_invalid_zone_condition(nvme_cid(req), zslba, zs); + return NVME_INTERNAL_DEV_ERROR | NVME_DNR; +} + +static uint16_t nvme_check_zone_write(NvmeCtrl *n, uint64_t slba, uint32_t nlb, + NvmeRequest *req, NvmeZone *zone) +{ + uint64_t zslba, wp, zcap; + uint16_t status; + + zslba = nvme_zslba(zone); + wp = zone->wp_staging; + zcap = nvme_zcap(zone); + + status = nvme_check_zone_writeable(n, req, zone); + if (status) { + return status; + } + + if ((wp - zslba) + nlb > zcap) { + trace_pci_nvme_err_zone_boundary(nvme_cid(req), slba, nlb, zcap); + return NVME_ZONE_BOUNDARY_ERROR | NVME_DNR; + } + + if (slba != wp) { + trace_pci_nvme_err_zone_invalid_write(nvme_cid(req), slba, wp); + return NVME_ZONE_INVALID_WRITE | NVME_DNR; + } + + return NVME_SUCCESS; +} + +static inline uint16_t nvme_check_zone(NvmeCtrl *n, uint64_t slba, + uint32_t nlb, NvmeRequest *req, + NvmeZone *zone) { + if (nvme_req_is_write(req)) { + return nvme_check_zone_write(n, slba, nlb, req, zone); + } + + return nvme_check_zone_read(n, slba, nlb, req, zone); +} + static inline uint16_t nvme_check_mdts(NvmeCtrl *n, size_t len) { uint8_t mdts = n->params.mdts; @@ -989,6 +1105,42 @@ static int nvme_allocate(NvmeNamespace *ns, uint64_t slba, uint32_t nlb) return ret; } +static int nvme_zns_commit_zone(NvmeNamespace *ns, NvmeZone *zone) +{ + uint64_t zslba; + int64_t offset; + + if (!ns->pstate.blk) { + return 0; + } + + trace_pci_nvme_zns_commit_zone(nvme_nsid(ns), nvme_zslba(zone)); + + zslba = nvme_zslba(zone); + offset = ns->pstate.zns.offset + + nvme_ns_zone_idx(ns, zslba) * sizeof(NvmeZoneDescriptor); + + return blk_pwrite(ns->pstate.blk, offset, zone->zd, + sizeof(NvmeZoneDescriptor), 0); +} + +static void nvme_zns_advance_wp(NvmeRequest *req) +{ + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + uint64_t slba = le64_to_cpu(rw->slba); + uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; + NvmeZone *zone = nvme_ns_get_zone(req->ns, slba); + uint64_t wp = nvme_wp(zone); + + wp += nlb; + zone->zd->wp = cpu_to_le64(wp); + if (wp == nvme_zslba(zone) + nvme_zcap(zone)) { + nvme_zs_set(zone, NVME_ZS_ZSF); + if (nvme_zns_commit_zone(req->ns, zone) < 0) { + req->status = NVME_INTERNAL_DEV_ERROR; + } + } +} static void nvme_rw_cb(void *opaque, int ret) { @@ -1005,6 +1157,10 @@ static void nvme_rw_cb(void *opaque, int ret) if (!ret) { block_acct_done(stats, acct); + + if (nvme_ns_zoned(ns) && nvme_req_is_write(req)) { + nvme_zns_advance_wp(req); + } } else { uint16_t status; @@ -1030,6 +1186,26 @@ static void nvme_rw_cb(void *opaque, int ret) error_report_err(local_err); req->status = status; + + if (nvme_ns_zoned(ns)) { + NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; + uint64_t slba = le64_to_cpu(rw->slba); + + NvmeZone *zone = nvme_ns_get_zone(ns, slba); + + /* + * Transition the zone to read-only on write fault and offline + * on unrecovered read. + */ + NvmeZoneState zs = status == NVME_WRITE_FAULT ? + NVME_ZS_ZSRO : NVME_ZS_ZSO; + + nvme_zs_set(zone, zs); + + if (nvme_zns_commit_zone(ns, zone) < 0) { + req->status = NVME_INTERNAL_DEV_ERROR; + } + } } nvme_enqueue_req_completion(nvme_cq(req), req); @@ -1103,6 +1279,7 @@ static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) { NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; NvmeNamespace *ns = req->ns; + NvmeZone *zone = NULL; uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; @@ -1114,6 +1291,20 @@ static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) trace_pci_nvme_rwz(nvme_cid(req), nvme_io_opc_str(rw->opcode), nvme_nsid(ns), nlb, len, slba); + if (nvme_ns_zoned(ns)) { + zone = nvme_ns_get_zone(ns, slba); + if (!zone) { + trace_pci_nvme_err_invalid_zone(nvme_cid(req), slba); + status = NVME_INVALID_FIELD | NVME_DNR; + goto invalid; + } + + status = nvme_check_zone(n, slba, nlb, req, zone); + if (status) { + goto invalid; + } + } + status = nvme_check_bounds(n, ns, slba, nlb); if (status) { NvmeIdNsNvm *id_ns = nvme_ns_id_nvm(ns); @@ -1145,6 +1336,31 @@ static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) } if (is_write) { + if (zone) { + if (zone->wp_staging != nvme_wp(zone)) { + trace_pci_nvme_err_zone_pending_writes(nvme_cid(req), + nvme_zslba(zone), + nvme_wp(zone), + zone->wp_staging); + } + + switch (nvme_zs(zone)) { + case NVME_ZS_ZSE: + case NVME_ZS_ZSC: + nvme_zs_set(zone, NVME_ZS_ZSIO); + + if (nvme_zns_commit_zone(req->ns, zone) < 0) { + status = NVME_INTERNAL_DEV_ERROR; + goto invalid; + } + + default: + break; + } + + zone->wp_staging += nlb; + } + if (nvme_allocate(ns, slba, nlb) < 0) { status = NVME_INTERNAL_DEV_ERROR; goto invalid; @@ -2881,7 +3097,7 @@ static void nvme_init_state(NvmeCtrl *n) n->features.temp_thresh_hi = NVME_TEMPERATURE_WARNING; n->starttime_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); n->aer_reqs = g_new0(NvmeRequest *, n->params.aerl + 1); - n->iocscs[0] = 1 << NVME_IOCS_NVM; + n->iocscs[0] = (1 << NVME_IOCS_NVM) | (1 << NVME_IOCS_ZONED); n->features.iocsci = 0; } @@ -3032,6 +3248,9 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) uint8_t *pci_conf = pci_dev->config; char *subnqn; + n->id_ctrl_iocss[NVME_IOCS_NVM] = g_new0(NvmeIdCtrl, 1); + n->id_ctrl_iocss[NVME_IOCS_ZONED] = g_new0(NvmeIdCtrl, 1); + id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); strpadcpy((char *)id->mn, sizeof(id->mn), "QEMU NVMe Ctrl", ' '); diff --git a/hw/block/trace-events b/hw/block/trace-events index b002eb7c8a5c..d46a7a4942bb 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -72,6 +72,7 @@ pci_nvme_enqueue_event_noqueue(int queued) "queued %d" pci_nvme_enqueue_event_masked(uint8_t typ) "type 0x%"PRIx8"" pci_nvme_no_outstanding_aers(void) "ignoring event; no outstanding AERs" pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint16_t status) "cid %"PRIu16" cqid %"PRIu16" status 0x%"PRIx16"" +pci_nvme_zns_commit_zone(uint32_t nsid, uint64_t zslba) "nsid 0x%"PRIx32" zslba 0x%"PRIx64"" pci_nvme_mmio_read(uint64_t addr) "addr 0x%"PRIx64"" pci_nvme_mmio_write(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64"" pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16"" @@ -97,6 +98,11 @@ pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64"" pci_nvme_err_addr_write(uint64_t addr) "addr 0x%"PRIx64"" pci_nvme_err_cfs(void) "controller fatal status" pci_nvme_err_aio(uint16_t cid, const char *errname, uint16_t status) "cid %"PRIu16" err '%s' status 0x%"PRIx16"" +pci_nvme_err_zone_is_full(uint16_t cid, uint64_t slba) "cid %"PRIu16" lba 0x%"PRIx64"" +pci_nvme_err_zone_is_read_only(uint16_t cid, uint64_t slba) "cid %"PRIu16" lba 0x%"PRIx64"" +pci_nvme_err_zone_invalid_write(uint16_t cid, uint64_t slba, uint64_t wp) "cid %"PRIu16" lba 0x%"PRIx64" wp 0x%"PRIx64"" +pci_nvme_err_zone_boundary(uint16_t cid, uint64_t slba, uint32_t nlb, uint64_t zcap) "cid %"PRIu16" lba 0x%"PRIx64" nlb %"PRIu32" zcap 0x%"PRIx64"" +pci_nvme_err_zone_pending_writes(uint16_t cid, uint64_t zslba, uint64_t wp, uint64_t wp_staging) "cid %"PRIu16" zslba 0x%"PRIx64" wp 0x%"PRIx64" wp_staging 0x%"PRIx64"" pci_nvme_err_invalid_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8"" pci_nvme_err_invalid_num_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8"" pci_nvme_err_invalid_sgl_excess_length(uint16_t cid) "cid %"PRIu16"" @@ -125,6 +131,8 @@ pci_nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx1 pci_nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32"" pci_nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32"" pci_nvme_err_invalid_log_page(uint16_t cid, uint16_t lid) "cid %"PRIu16" lid 0x%"PRIx16"" +pci_nvme_err_invalid_zone(uint16_t cid, uint64_t lba) "cid %"PRIu16" lba 0x%"PRIx64"" +pci_nvme_err_invalid_zone_condition(uint16_t cid, uint64_t zslba, uint8_t condition) "cid %"PRIu16" zslba 0x%"PRIx64" condition 0x%"PRIx8"" pci_nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues" pci_nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues" pci_nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null" From patchwork Thu Sep 24 20:45:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 272797 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8A90C4363D for ; Thu, 24 Sep 2020 21:10:12 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 418A822208 for ; Thu, 24 Sep 2020 21:10:12 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 418A822208 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:49086 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYVH-0002UL-27 for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 17:10:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38618) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7Y-0004ZC-SS; Thu, 24 Sep 2020 16:45:41 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:43295) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7T-0007nP-6b; Thu, 24 Sep 2020 16:45:40 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id 56D7E580509; Thu, 24 Sep 2020 16:45:33 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:33 -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=fm1; bh=iHh5SVDa7WZAZ iIwnoJA5VT73xcAn9ABMOivHzmv5kI=; b=Q3zTLCUcu109+KkBGezVZvmh7I++L XA+KF2WiEFCHttgugLeU9MeGCxFEAD2PaC+cspU2YiBci+BELee8O/a7rBeX7/7P FFVI98pVEzlkm3hZXjQHmVcbHqMxbpXxqJm8t0VgdyZvZB2ARfwh9je5ZpM4s7Cl St9FGl0MNDvlFgtG7WjYlc5r5k0UNOvjkEvEm7xw6LKXUnTq6V7S0F6GvIoZjdM0 b01Ovdc1bDZ6mqnxQgEkkiMg+lYbFEk+z7GNcReeutsAbK+80j+31n0WRHMmhtsn rF62E6yvCFGex0eYGCsj4jDIUndlHsa7npSUfxUKJBOAL1bcIeXoqUhvw== 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= fm3; bh=iHh5SVDa7WZAZiIwnoJA5VT73xcAn9ABMOivHzmv5kI=; b=jbfIktMg vgKLO7b/Zcw1uGwhgC1tdVJnQ7g6XHSQNPvJ9JyKurQOXMLW0MHWPF3kl7Mbay5P jXw6FCJmRKtXGFY+wFL7LegPI6AF05gAldImg4K7zIffETx+zCWaPpP0gy85u4f6 /0sqw8QyudQ4Kkw1VQ06kBCZfvz2GxgrDEYx88l8iTI5FZ0nt58DFf69erpwAx0e 3kS/QVUPEtvKG051pOIANBqY4Jg98uKimDJAgWvAE7ff9wqATGh7BPhj1XF9uupQ cxDpgbWHVUodUW6lMm3eeEdp3zA42q3ylcdUDO+ZMhbj4wHo1U7cNfxWQVZ/LWJX sJPxQ3raBFsX2A== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeeuleetgeeiuefhgfekfefgveejiefgteekiedtgfdtieefhfdthfefueffvefg keenucfkphepkedtrdduieejrdelkedrudeltdenucevlhhushhtvghrufhiiigvpeegne curfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirhhrvghlvghvrghnthdrughk 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 4709D3064686; Thu, 24 Sep 2020 16:45:31 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 10/16] hw/block/nvme: add the zone management receive command Date: Thu, 24 Sep 2020 22:45:10 +0200 Message-Id: <20200924204516.1881843-11-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Add the Zone Management Receive command. Signed-off-by: Klaus Jensen --- hw/block/nvme-ns.h | 8 +++ hw/block/nvme.h | 1 + include/block/nvme.h | 46 ++++++++++++++ hw/block/nvme-ns.c | 35 ++++++++++- hw/block/nvme.c | 135 ++++++++++++++++++++++++++++++++++++++++++ hw/block/trace-events | 1 + 6 files changed, 223 insertions(+), 3 deletions(-) diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index c15bfcfc5a08..5a695334a052 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -27,11 +27,13 @@ typedef struct NvmeNamespaceParams { struct { uint64_t zcap; uint64_t zsze; + uint8_t zdes; } zns; } NvmeNamespaceParams; typedef struct NvmeZone { NvmeZoneDescriptor *zd; + uint8_t *zde; uint64_t wp_staging; } NvmeZone; @@ -68,6 +70,7 @@ typedef struct NvmeNamespace { NvmeZone *zones; NvmeZoneDescriptor *zd; + uint8_t *zde; } zns; } NvmeNamespace; @@ -160,6 +163,11 @@ static inline void nvme_zs_set(NvmeZone *zone, NvmeZoneState zs) zone->zd->zs = zs << 4; } +static inline size_t nvme_ns_zdes_bytes(NvmeNamespace *ns) +{ + return ns->params.zns.zdes << 6; +} + static inline bool nvme_ns_zone_wp_valid(NvmeZone *zone) { switch (nvme_zs(zone)) { diff --git a/hw/block/nvme.h b/hw/block/nvme.h index f66ed9ab7eff..523eef0bcad8 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -71,6 +71,7 @@ static inline const char *nvme_io_opc_str(uint8_t opc) case NVME_CMD_WRITE: return "NVME_NVM_CMD_WRITE"; case NVME_CMD_READ: return "NVME_NVM_CMD_READ"; case NVME_CMD_WRITE_ZEROES: return "NVME_NVM_CMD_WRITE_ZEROES"; + case NVME_CMD_ZONE_MGMT_RECV: return "NVME_ZONED_CMD_ZONE_MGMT_RECV"; default: return "NVME_NVM_CMD_UNKNOWN"; } } diff --git a/include/block/nvme.h b/include/block/nvme.h index 2e523c9d97b4..9bacf48ee9e9 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -481,6 +481,7 @@ enum NvmeIoCommands { NVME_CMD_COMPARE = 0x05, NVME_CMD_WRITE_ZEROES = 0x08, NVME_CMD_DSM = 0x09, + NVME_CMD_ZONE_MGMT_RECV = 0x7a, }; typedef struct QEMU_PACKED NvmeDeleteQ { @@ -593,6 +594,44 @@ enum { NVME_RW_PRINFO_PRCHK_REF = 1 << 10, }; +typedef struct QEMU_PACKED NvmeZoneManagementRecvCmd { + uint8_t opcode; + uint8_t flags; + uint16_t cid; + uint32_t nsid; + uint8_t rsvd8[16]; + NvmeCmdDptr dptr; + uint64_t slba; + uint32_t numdw; + uint8_t zra; + uint8_t zrasp; + uint8_t zrasf; + uint8_t rsvd55[9]; +} NvmeZoneManagementRecvCmd; + +typedef enum NvmeZoneManagementRecvAction { + NVME_CMD_ZONE_MGMT_RECV_REPORT_ZONES = 0x0, + NVME_CMD_ZONE_MGMT_RECV_EXTENDED_REPORT_ZONES = 0x1, +} NvmeZoneManagementRecvAction; + +typedef enum NvmeZoneManagementRecvActionSpecificField { + NVME_CMD_ZONE_MGMT_RECV_LIST_ALL = 0x0, + NVME_CMD_ZONE_MGMT_RECV_LIST_ZSE = 0x1, + NVME_CMD_ZONE_MGMT_RECV_LIST_ZSIO = 0x2, + NVME_CMD_ZONE_MGMT_RECV_LIST_ZSEO = 0x3, + NVME_CMD_ZONE_MGMT_RECV_LIST_ZSC = 0x4, + NVME_CMD_ZONE_MGMT_RECV_LIST_ZSF = 0x5, + NVME_CMD_ZONE_MGMT_RECV_LIST_ZSRO = 0x6, + NVME_CMD_ZONE_MGMT_RECV_LIST_ZSO = 0x7, +} NvmeZoneManagementRecvActionSpecificField; + +#define NVME_CMD_ZONE_MGMT_RECEIVE_PARTIAL 0x1 + +typedef struct QEMU_PACKED NvmeZoneReportHeader { + uint64_t num_zones; + uint8_t rsvd[56]; +} NvmeZoneReportHeader; + typedef struct QEMU_PACKED NvmeDsmCmd { uint8_t opcode; uint8_t flags; @@ -812,6 +851,12 @@ typedef struct QEMU_PACKED NvmeZoneDescriptor { uint8_t rsvd32[32]; } NvmeZoneDescriptor; +#define NVME_ZA_ZDEV (1 << 7) + +#define NVME_ZA_SET(za, attrs) ((za) |= (attrs)) +#define NVME_ZA_CLEAR(za, attrs) ((za) &= ~(attrs)) +#define NVME_ZA_CLEAR_ALL(za) ((za) = 0x0) + enum NvmeSmartWarn { NVME_SMART_SPARE = 1 << 0, NVME_SMART_TEMPERATURE = 1 << 1, @@ -1162,6 +1207,7 @@ static inline void _nvme_check_size(void) QEMU_BUILD_BUG_ON(sizeof(NvmeIdentify) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeRwCmd) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeDsmCmd) != 64); + QEMU_BUILD_BUG_ON(sizeof(NvmeZoneManagementRecvCmd) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeRangeType) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeErrorLog) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeFwSlotInfoLog) != 512); diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 872c46f2f2f0..0fb196c7103e 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -85,6 +85,9 @@ static void nvme_ns_zns_init_zones(NvmeNamespace *ns) zslba = i * zsze; zone = nvme_ns_get_zone(ns, zslba); zone->zd = &ns->zns.zd[i]; + if (ns->params.zns.zdes) { + zone->zde = &ns->zns.zde[i]; + } zd = zone->zd; @@ -104,11 +107,15 @@ static void nvme_ns_init_zoned(NvmeNamespace *ns) for (int i = 0; i <= id_ns->nlbaf; i++) { id_ns_zns->lbafe[i].zsze = ns->params.zns.zsze ? ns->params.zns.zsze : cpu_to_le64(pow2ceil(ns->params.zns.zcap)); + id_ns_zns->lbafe[i].zdes = ns->params.zns.zdes; } ns->zns.num_zones = nvme_ns_nlbas(ns) / nvme_ns_zsze(ns); ns->zns.zones = g_malloc0_n(ns->zns.num_zones, sizeof(NvmeZone)); ns->zns.zd = g_malloc0_n(ns->zns.num_zones, sizeof(NvmeZoneDescriptor)); + if (ns->params.zns.zdes) { + ns->zns.zde = g_malloc0_n(ns->zns.num_zones, nvme_ns_zdes_bytes(ns)); + } id_ns->ncap = ns->zns.num_zones * ns->params.zns.zcap; @@ -148,7 +155,7 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) BlockBackend *blk = ns->pstate.blk; uint64_t perm, shared_perm; ssize_t len; - size_t util_len, zd_len, pstate_len; + size_t util_len, zd_len, zde_len, pstate_len; int ret; perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; @@ -162,7 +169,9 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) util_len = DIV_ROUND_UP(nvme_ns_nlbas(ns), 8); zd_len = nvme_ns_zoned(ns) ? ns->zns.num_zones * sizeof(NvmeZoneDescriptor) : 0; - pstate_len = ROUND_UP(util_len + zd_len, BDRV_SECTOR_SIZE); + zde_len = nvme_ns_zoned(ns) ? + ns->zns.num_zones * nvme_ns_zdes_bytes(ns) : 0; + pstate_len = ROUND_UP(util_len + zd_len + zde_len, BDRV_SECTOR_SIZE); len = blk_getlength(blk); if (len < 0) { @@ -213,9 +222,19 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) return ret; } + if (zde_len) { + ret = blk_pread(blk, util_len + zd_len, ns->zns.zde, + zde_len); + if (ret < 0) { + error_setg_errno(errp, -ret, "could not read pstate"); + return ret; + } + } + for (int i = 0; i < ns->zns.num_zones; i++) { NvmeZone *zone = &ns->zns.zones[i]; zone->zd = &ns->zns.zd[i]; + zone->zde = &ns->zns.zde[i]; zone->wp_staging = nvme_wp(zone); @@ -227,7 +246,8 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) continue; case NVME_ZS_ZSC: - if (nvme_wp(zone) == nvme_zslba(zone)) { + if (nvme_wp(zone) == nvme_zslba(zone) && + !(zone->zd->za & NVME_ZA_ZDEV)) { nvme_zs_set(zone, NVME_ZS_ZSE); } @@ -248,6 +268,14 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) error_setg_errno(errp, -ret, "could not write pstate"); return ret; } + + if (zde_len) { + ret = blk_pwrite(blk, util_len + zd_len, ns->zns.zde, zde_len, 0); + if (ret < 0) { + error_setg_errno(errp, -ret, "could not write pstate"); + return ret; + } + } } return 0; @@ -389,6 +417,7 @@ static Property nvme_ns_props[] = { DEFINE_PROP_UINT8("iocs", NvmeNamespace, params.iocs, NVME_IOCS_NVM), DEFINE_PROP_UINT64("zns.zcap", NvmeNamespace, params.zns.zcap, 0), DEFINE_PROP_UINT64("zns.zsze", NvmeNamespace, params.zns.zsze, 0), + DEFINE_PROP_UINT8("zns.zdes", NvmeNamespace, params.zns.zdes, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index b0179291b966..43ae89a0a6cb 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -163,6 +163,7 @@ static const NvmeEffectsLog nvme_effects[NVME_IOCS_MAX] = { .iocs = { NVME_EFFECTS_NVM_INITIALIZER, + [NVME_CMD_ZONE_MGMT_RECV] = NVME_EFFECTS_CSUPP, }, }, }; @@ -1201,6 +1202,9 @@ static void nvme_rw_cb(void *opaque, int ret) NVME_ZS_ZSRO : NVME_ZS_ZSO; nvme_zs_set(zone, zs); + if (zs == NVME_ZS_ZSO) { + NVME_ZA_CLEAR_ALL(zone->zd->za); + } if (nvme_zns_commit_zone(ns, zone) < 0) { req->status = NVME_INTERNAL_DEV_ERROR; @@ -1269,6 +1273,135 @@ static uint16_t nvme_do_aio(BlockBackend *blk, int64_t offset, size_t len, return NVME_NO_COMPLETE; } +static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req) +{ + NvmeZoneManagementRecvCmd *recv; + NvmeZoneManagementRecvAction zra; + NvmeZoneManagementRecvActionSpecificField zrasp; + NvmeNamespace *ns = req->ns; + NvmeZone *zone; + + uint8_t *buf, *bufp, zs_list; + uint64_t slba; + int num_zones = 0, zidx = 0, zidx_begin; + uint16_t zes, status; + size_t len; + + recv = (NvmeZoneManagementRecvCmd *) &req->cmd; + + zra = recv->zra; + zrasp = recv->zrasp; + slba = le64_to_cpu(recv->slba); + len = (le32_to_cpu(recv->numdw) + 1) << 2; + + if (!nvme_ns_zoned(ns)) { + return NVME_INVALID_OPCODE | NVME_DNR; + } + + trace_pci_nvme_zone_mgmt_recv(nvme_cid(req), nvme_nsid(ns), slba, len, + zra, zrasp, recv->zrasf); + + if (!len) { + return NVME_SUCCESS; + } + + switch (zrasp) { + case NVME_CMD_ZONE_MGMT_RECV_LIST_ALL: + zs_list = 0; + break; + + case NVME_CMD_ZONE_MGMT_RECV_LIST_ZSE: + zs_list = NVME_ZS_ZSE; + break; + + case NVME_CMD_ZONE_MGMT_RECV_LIST_ZSIO: + zs_list = NVME_ZS_ZSIO; + break; + + case NVME_CMD_ZONE_MGMT_RECV_LIST_ZSEO: + zs_list = NVME_ZS_ZSEO; + break; + + case NVME_CMD_ZONE_MGMT_RECV_LIST_ZSC: + zs_list = NVME_ZS_ZSC; + break; + + case NVME_CMD_ZONE_MGMT_RECV_LIST_ZSF: + zs_list = NVME_ZS_ZSF; + break; + + case NVME_CMD_ZONE_MGMT_RECV_LIST_ZSRO: + zs_list = NVME_ZS_ZSRO; + break; + + case NVME_CMD_ZONE_MGMT_RECV_LIST_ZSO: + zs_list = NVME_ZS_ZSO; + break; + default: + return NVME_INVALID_FIELD | NVME_DNR; + } + + status = nvme_check_mdts(n, len); + if (status) { + return status; + } + + if (!nvme_ns_get_zone(ns, slba)) { + trace_pci_nvme_err_invalid_zone(nvme_cid(req), slba); + return NVME_INVALID_FIELD | NVME_DNR; + } + + zidx_begin = zidx = nvme_ns_zone_idx(ns, slba); + zes = sizeof(NvmeZoneDescriptor); + if (zra == NVME_CMD_ZONE_MGMT_RECV_EXTENDED_REPORT_ZONES) { + zes += nvme_ns_zdes_bytes(ns); + } + + buf = bufp = g_malloc0(len); + bufp += sizeof(NvmeZoneReportHeader); + + while ((bufp + zes) - buf <= len && zidx < ns->zns.num_zones) { + zone = &ns->zns.zones[zidx++]; + + if (zs_list && zs_list != nvme_zs(zone)) { + continue; + } + + num_zones++; + + memcpy(bufp, zone->zd, sizeof(NvmeZoneDescriptor)); + + if (zra == NVME_CMD_ZONE_MGMT_RECV_EXTENDED_REPORT_ZONES) { + memcpy(bufp + sizeof(NvmeZoneDescriptor), zone->zde, + nvme_ns_zdes_bytes(ns)); + } + + bufp += zes; + } + + if (!(recv->zrasf & NVME_CMD_ZONE_MGMT_RECEIVE_PARTIAL)) { + if (!zs_list) { + num_zones = ns->zns.num_zones - zidx_begin; + } else { + num_zones = 0; + for (int i = zidx_begin; i < ns->zns.num_zones; i++) { + zone = &ns->zns.zones[i]; + + if (zs_list == nvme_zs(zone)) { + num_zones++; + } + } + } + } + + stq_le_p(buf, (uint64_t)num_zones); + + status = nvme_dma(n, buf, len, DMA_DIRECTION_FROM_DEVICE, req); + g_free(buf); + + return status; +} + static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req) { NvmeNamespace *ns = req->ns; @@ -1408,6 +1541,8 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) case NVME_CMD_WRITE: case NVME_CMD_READ: return nvme_rwz(n, req); + case NVME_CMD_ZONE_MGMT_RECV: + return nvme_zone_mgmt_recv(n, req); default: trace_pci_nvme_err_invalid_opc(req->cmd.opcode); return NVME_INVALID_OPCODE | NVME_DNR; diff --git a/hw/block/trace-events b/hw/block/trace-events index d46a7a4942bb..a2671dadb1e8 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -42,6 +42,7 @@ pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode, cons 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_rwz(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t len, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" len %"PRIu64" lba 0x%"PRIx64"" pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_zone_mgmt_recv(uint16_t cid, uint32_t nsid, uint64_t slba, uint64_t len, uint8_t zra, uint8_t zrasp, uint8_t zrasf) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" len %"PRIu64" zra 0x%"PRIx8" zrasp 0x%"PRIx8" zrasf 0x%"PRIx8"" pci_nvme_allocate(uint32_t ns, uint64_t slba, uint32_t nlb) "nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" pci_nvme_do_aio(uint16_t cid, uint8_t opc, const char *opname, const char *blkname, int64_t offset, size_t len) "cid %"PRIu16" opc 0x%"PRIx8" opname '%s' blk '%s' offset %"PRId64" len %zu" pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16"" From patchwork Thu Sep 24 20:45:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 272803 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 02EE3C4727E for ; Thu, 24 Sep 2020 20:50:06 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 4F455221EB for ; Thu, 24 Sep 2020 20:50:04 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4F455221EB Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:49478 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYBn-00075I-T2 for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 16:50:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38720) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7s-0004oL-4F; Thu, 24 Sep 2020 16:46:04 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:50613) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7n-0007nW-Pu; Thu, 24 Sep 2020 16:45:59 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id 011B258050F; Thu, 24 Sep 2020 16:45:35 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:35 -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=fm1; bh=BgPkIH18OMgQX udcnjf7YrQrNRZbzRyLvu+71yK4H2s=; b=QpHeY6Iyi4iictfEGG0Qq7Ep61viE 419/eYCz+tQTUSL+L2a3+YDZFjpWPTZg5oDkG6yyp5BQ3ZsJul3HdwyKzK6USyJ+ SXGGZg+FSvo9XgKdK+Ybh9AgYpHfKUSfDabTF9k9WVS4XOrceZ6II7qVNzbRJcvd Sx9VwFCFfTHLIBz+KYVzfCr8mQCtV731qQykO+hPVUFcV7x6hMVBykve8NByZ0Uc AP0JUovi8dZgbsu9Fr40plpnNQO2ruyQJZWBM0PKNgIQ9w1CIwtfXNGZtdH7YyQ4 McaxPbW+ocy1GIJFUI+VZK7uVgiNiGRMq9QrYtQ+p/ATo/BRv8gCo2jzw== 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= fm3; bh=BgPkIH18OMgQXudcnjf7YrQrNRZbzRyLvu+71yK4H2s=; b=WrQI+d36 qXKMGVS420/IGHdzOHEFaGvWUY1YewM3EZ9uqdVmHnh4cpAOknp/3mU/R7m5bK2V fhuscjz7BO6b+m1MpcJ+luEGfmZXy/dNaFNySybxHiBRrcJa84PKLbat00EPAc5d Me1O8KZ6GFpUXzUevqYEZwrDNXbMVLK3lKim/EpGYebu2hr2cQae7/RR2B6iQib2 v8hpyRhJJigilL0wWlWx/N4Gk9Ch/h2CWizSmxCAVHiwbW2BnzeNv/pzOVa9XWWI JtdbnIt/JYC8MNO4VRdt8BqFZ4HwHpsFyG8htTHcBsRMELOWA9XRro5Xgry/LnMt Twt2m3wrDe75yA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeekudehfeethfdvvdegieffheekueeghefhudfghffhhfevjeejffeuhedugedu udenucffohhmrghinhepuhhtihhlihiirghtihhonhdrmhgrphenucfkphepkedtrdduie ejrdelkedrudeltdenucevlhhushhtvghrufhiiigvpedunecurfgrrhgrmhepmhgrihhl fhhrohhmpehithhssehirhhrvghlvghvrghnthdrughk 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 8E5803064683; Thu, 24 Sep 2020 16:45:32 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 11/16] hw/block/nvme: add the zone management send command Date: Thu, 24 Sep 2020 22:45:11 +0200 Message-Id: <20200924204516.1881843-12-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Add the Zone Management Send command. Signed-off-by: Klaus Jensen --- hw/block/nvme.h | 1 + include/block/nvme.h | 29 +++ hw/block/nvme.c | 552 ++++++++++++++++++++++++++++++++++++++++-- hw/block/trace-events | 11 + 4 files changed, 574 insertions(+), 19 deletions(-) diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 523eef0bcad8..c704663e0a3e 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -71,6 +71,7 @@ static inline const char *nvme_io_opc_str(uint8_t opc) case NVME_CMD_WRITE: return "NVME_NVM_CMD_WRITE"; case NVME_CMD_READ: return "NVME_NVM_CMD_READ"; case NVME_CMD_WRITE_ZEROES: return "NVME_NVM_CMD_WRITE_ZEROES"; + case NVME_CMD_ZONE_MGMT_SEND: return "NVME_ZONED_CMD_ZONE_MGMT_SEND"; case NVME_CMD_ZONE_MGMT_RECV: return "NVME_ZONED_CMD_ZONE_MGMT_RECV"; default: return "NVME_NVM_CMD_UNKNOWN"; } diff --git a/include/block/nvme.h b/include/block/nvme.h index 9bacf48ee9e9..967b42eb5da7 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -481,6 +481,7 @@ enum NvmeIoCommands { NVME_CMD_COMPARE = 0x05, NVME_CMD_WRITE_ZEROES = 0x08, NVME_CMD_DSM = 0x09, + NVME_CMD_ZONE_MGMT_SEND = 0x79, NVME_CMD_ZONE_MGMT_RECV = 0x7a, }; @@ -594,6 +595,32 @@ enum { NVME_RW_PRINFO_PRCHK_REF = 1 << 10, }; +typedef struct QEMU_PACKED NvmeZoneManagementSendCmd { + uint8_t opcode; + uint8_t flags; + uint16_t cid; + uint32_t nsid; + uint32_t rsvd8[4]; + NvmeCmdDptr dptr; + uint64_t slba; + uint32_t rsvd48; + uint8_t zsa; + uint8_t zsflags; + uint16_t rsvd54; + uint32_t rsvd56[2]; +} NvmeZoneManagementSendCmd; + +#define NVME_CMD_ZONE_MGMT_SEND_SELECT_ALL(zsflags) ((zsflags) & 0x1) + +typedef enum NvmeZoneManagementSendAction { + NVME_CMD_ZONE_MGMT_SEND_CLOSE = 0x1, + NVME_CMD_ZONE_MGMT_SEND_FINISH = 0x2, + NVME_CMD_ZONE_MGMT_SEND_OPEN = 0x3, + NVME_CMD_ZONE_MGMT_SEND_RESET = 0x4, + NVME_CMD_ZONE_MGMT_SEND_OFFLINE = 0x5, + NVME_CMD_ZONE_MGMT_SEND_SET_ZDE = 0x10, +} NvmeZoneManagementSendAction; + typedef struct QEMU_PACKED NvmeZoneManagementRecvCmd { uint8_t opcode; uint8_t flags; @@ -748,6 +775,7 @@ enum NvmeStatusCodes { NVME_ZONE_IS_READ_ONLY = 0x01ba, NVME_ZONE_IS_OFFLINE = 0x01bb, NVME_ZONE_INVALID_WRITE = 0x01bc, + NVME_INVALID_ZONE_STATE_TRANSITION = 0x01bf, NVME_WRITE_FAULT = 0x0280, NVME_UNRECOVERED_READ = 0x0281, NVME_E2E_GUARD_ERROR = 0x0282, @@ -1207,6 +1235,7 @@ static inline void _nvme_check_size(void) QEMU_BUILD_BUG_ON(sizeof(NvmeIdentify) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeRwCmd) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeDsmCmd) != 64); + QEMU_BUILD_BUG_ON(sizeof(NvmeZoneManagementSendCmd) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeZoneManagementRecvCmd) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeRangeType) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeErrorLog) != 64); diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 43ae89a0a6cb..51611ed32600 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -164,6 +164,8 @@ static const NvmeEffectsLog nvme_effects[NVME_IOCS_MAX] = { .iocs = { NVME_EFFECTS_NVM_INITIALIZER, [NVME_CMD_ZONE_MGMT_RECV] = NVME_EFFECTS_CSUPP, + [NVME_CMD_ZONE_MGMT_SEND] = NVME_EFFECTS_CSUPP | + NVME_EFFECTS_LBCC, }, }, }; @@ -1064,21 +1066,20 @@ static inline uint16_t nvme_check_dulbe(NvmeNamespace *ns, uint64_t slba, return NVME_SUCCESS; } -static int nvme_allocate(NvmeNamespace *ns, uint64_t slba, uint32_t nlb) +static int __nvme_allocate(NvmeNamespace *ns, uint64_t slba, uint32_t nlb, + bool deallocate) { int nlongs, first; int64_t offset; unsigned long *map, *src; int ret; - if (!(ns->pstate.blk && nvme_check_dulbe(ns, slba, nlb))) { - return 0; + if (deallocate) { + bitmap_clear(ns->pstate.utilization.map, slba, nlb); + } else { + bitmap_set(ns->pstate.utilization.map, slba, nlb); } - trace_pci_nvme_allocate(nvme_nsid(ns), slba, nlb); - - bitmap_set(ns->pstate.utilization.map, slba, nlb); - nlongs = BITS_TO_LONGS(nlb) + 1; first = slba / BITS_PER_LONG; offset = ns->pstate.utilization.offset + first * sizeof(unsigned long); @@ -1106,6 +1107,28 @@ static int nvme_allocate(NvmeNamespace *ns, uint64_t slba, uint32_t nlb) return ret; } +static int nvme_allocate(NvmeNamespace *ns, uint64_t slba, uint32_t nlb) +{ + if (!(ns->pstate.blk && nvme_check_dulbe(ns, slba, nlb))) { + return 0; + } + + trace_pci_nvme_allocate(nvme_nsid(ns), slba, nlb); + + return __nvme_allocate(ns, slba, nlb, false /* deallocate */); +} + +static int nvme_deallocate(NvmeNamespace *ns, uint64_t slba, uint32_t nlb) +{ + if (!ns->pstate.blk) { + return 0; + } + + trace_pci_nvme_deallocate(nvme_nsid(ns), slba, nlb); + + return __nvme_allocate(ns, slba, nlb, true /* deallocate */); +} + static int nvme_zns_commit_zone(NvmeNamespace *ns, NvmeZone *zone) { uint64_t zslba; @@ -1125,6 +1148,139 @@ static int nvme_zns_commit_zone(NvmeNamespace *ns, NvmeZone *zone) sizeof(NvmeZoneDescriptor), 0); } +static int nvme_zns_commit_zde(NvmeNamespace *ns, NvmeZone *zone) +{ + uint64_t zslba; + int zidx; + size_t zdes_bytes; + int64_t offset; + + if (!ns->pstate.blk) { + return 0; + } + + zslba = nvme_zslba(zone); + zidx = nvme_ns_zone_idx(ns, zslba); + zdes_bytes = nvme_ns_zdes_bytes(ns); + offset = ns->pstate.zns.offset + + ns->zns.num_zones * sizeof(NvmeZoneDescriptor) + + zidx * zdes_bytes; + + return blk_pwrite(ns->pstate.blk, offset, zone->zde, zdes_bytes, 0); +} + +static inline void nvme_zone_reset_wp(NvmeZone *zone) +{ + zone->zd->wp = zone->zd->zslba; + zone->wp_staging = nvme_zslba(zone); +} + +static uint16_t nvme_zrm_transition(NvmeNamespace *ns, NvmeZone *zone, + NvmeZoneState to) +{ + NvmeZoneState from = nvme_zs(zone); + + /* fast path */ + if (from == to) { + return NVME_SUCCESS; + } + + switch (from) { + case NVME_ZS_ZSE: + break; + + case NVME_ZS_ZSIO: + case NVME_ZS_ZSEO: + switch (to) { + case NVME_ZS_ZSEO: + break; + + case NVME_ZS_ZSE: + nvme_zone_reset_wp(zone); + + /* fallthrough */ + + case NVME_ZS_ZSO: + NVME_ZA_CLEAR_ALL(zone->zd->za); + + /* fallthrough */ + + case NVME_ZS_ZSF: + case NVME_ZS_ZSRO: + case NVME_ZS_ZSC: + break; + + default: + return NVME_INVALID_ZONE_STATE_TRANSITION | NVME_DNR; + } + + break; + + case NVME_ZS_ZSC: + switch (to) { + case NVME_ZS_ZSE: + nvme_zone_reset_wp(zone); + + /* fallthrough */ + + case NVME_ZS_ZSO: + NVME_ZA_CLEAR_ALL(zone->zd->za); + + /* fallthrough */ + + case NVME_ZS_ZSF: + case NVME_ZS_ZSRO: + case NVME_ZS_ZSIO: + case NVME_ZS_ZSEO: + break; + + default: + return NVME_INVALID_ZONE_STATE_TRANSITION | NVME_DNR; + } + + break; + + case NVME_ZS_ZSRO: + switch (to) { + case NVME_ZS_ZSO: + NVME_ZA_CLEAR_ALL(zone->zd->za); + break; + + default: + return NVME_INVALID_ZONE_STATE_TRANSITION | NVME_DNR; + } + + break; + + case NVME_ZS_ZSF: + switch (to) { + case NVME_ZS_ZSE: + nvme_zone_reset_wp(zone); + + /* fallthrough */ + + case NVME_ZS_ZSO: + NVME_ZA_CLEAR_ALL(zone->zd->za); + + /* fallthrough */ + + case NVME_ZS_ZSRO: + break; + + default: + return NVME_INVALID_ZONE_STATE_TRANSITION | NVME_DNR; + } + + break; + + default: + return NVME_INVALID_ZONE_STATE_TRANSITION | NVME_DNR; + } + + nvme_zs_set(zone, to); + return NVME_SUCCESS; +} + static void nvme_zns_advance_wp(NvmeRequest *req) { NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; @@ -1136,7 +1292,7 @@ static void nvme_zns_advance_wp(NvmeRequest *req) wp += nlb; zone->zd->wp = cpu_to_le64(wp); if (wp == nvme_zslba(zone) + nvme_zcap(zone)) { - nvme_zs_set(zone, NVME_ZS_ZSF); + nvme_zrm_transition(req->ns, zone, NVME_ZS_ZSF); if (nvme_zns_commit_zone(req->ns, zone) < 0) { req->status = NVME_INTERNAL_DEV_ERROR; } @@ -1201,11 +1357,7 @@ static void nvme_rw_cb(void *opaque, int ret) NvmeZoneState zs = status == NVME_WRITE_FAULT ? NVME_ZS_ZSRO : NVME_ZS_ZSO; - nvme_zs_set(zone, zs); - if (zs == NVME_ZS_ZSO) { - NVME_ZA_CLEAR_ALL(zone->zd->za); - } - + nvme_zrm_transition(ns, zone, zs); if (nvme_zns_commit_zone(ns, zone) < 0) { req->status = NVME_INTERNAL_DEV_ERROR; } @@ -1273,6 +1425,364 @@ static uint16_t nvme_do_aio(BlockBackend *blk, int64_t offset, size_t len, return NVME_NO_COMPLETE; } +static uint16_t nvme_zone_mgmt_send_close(NvmeCtrl *n, NvmeRequest *req, + NvmeZone *zone) +{ + NvmeNamespace *ns = req->ns; + uint16_t status; + + trace_pci_nvme_zone_mgmt_send_close(nvme_cid(req), nvme_nsid(ns), + nvme_zslba(zone), nvme_zs_str(zone)); + + switch (nvme_zs(zone)) { + case NVME_ZS_ZSC: + return NVME_SUCCESS; + + case NVME_ZS_ZSE: + /* + * The state machine in nvme_zrm_transition allows zones to transition + * from ZSE to ZSC. That transition is only valid if done as part Set + * Zone Descriptor, so do an early check here. + */ + return NVME_INVALID_ZONE_STATE_TRANSITION | NVME_DNR; + + default: + break; + } + + status = nvme_zrm_transition(ns, zone, NVME_ZS_ZSC); + if (status) { + return status; + } + + if (nvme_zns_commit_zone(ns, zone) < 0) { + return NVME_INTERNAL_DEV_ERROR; + } + + return NVME_SUCCESS; +} + +static uint16_t nvme_zone_mgmt_send_finish(NvmeCtrl *n, NvmeRequest *req, + NvmeZone *zone) +{ + NvmeNamespace *ns = req->ns; + uint16_t status; + + trace_pci_nvme_zone_mgmt_send_finish(nvme_cid(req), nvme_nsid(ns), + nvme_zslba(zone), nvme_zs_str(zone)); + + if (nvme_zs(zone) == NVME_ZS_ZSF) { + return NVME_SUCCESS; + } + + status = nvme_zrm_transition(ns, zone, NVME_ZS_ZSF); + if (status) { + return status; + } + + if (nvme_zns_commit_zone(ns, zone) < 0) { + return NVME_INTERNAL_DEV_ERROR; + } + + return NVME_SUCCESS; +} + +static uint16_t nvme_zone_mgmt_send_open(NvmeCtrl *n, NvmeRequest *req, + NvmeZone *zone) +{ + NvmeNamespace *ns = req->ns; + uint16_t status; + + trace_pci_nvme_zone_mgmt_send_open(nvme_cid(req), nvme_nsid(ns), + nvme_zslba(zone), nvme_zs_str(zone)); + + if (nvme_zs(zone) == NVME_ZS_ZSEO) { + return NVME_SUCCESS; + } + + status = nvme_zrm_transition(ns, zone, NVME_ZS_ZSEO); + if (status) { + return status; + } + + if (nvme_zns_commit_zone(ns, zone) < 0) { + return NVME_INTERNAL_DEV_ERROR; + } + + return NVME_SUCCESS; +} + +static uint16_t nvme_zone_mgmt_send_reset(NvmeCtrl *n, NvmeRequest *req, + NvmeZone *zone) +{ + NvmeNamespace *ns = req->ns; + uint64_t zslba = nvme_zslba(zone); + uint64_t zcap = nvme_zcap(zone); + + trace_pci_nvme_zone_mgmt_send_reset(nvme_cid(req), nvme_nsid(ns), + nvme_zslba(zone), nvme_zs_str(zone)); + + switch (nvme_zs(zone)) { + case NVME_ZS_ZSIO: + case NVME_ZS_ZSEO: + case NVME_ZS_ZSC: + case NVME_ZS_ZSF: + if (blk_pdiscard(ns->blkconf.blk, nvme_l2b(ns, zslba), + nvme_l2b(ns, zcap)) < 0) { + return NVME_INTERNAL_DEV_ERROR; + } + + if (nvme_deallocate(ns, zslba, zcap) < 0) { + return NVME_INTERNAL_DEV_ERROR; + } + + nvme_zrm_transition(ns, zone, NVME_ZS_ZSE); + if (nvme_zns_commit_zone(ns, zone) < 0) { + return NVME_INTERNAL_DEV_ERROR; + } + + /* fallthrough */ + + case NVME_ZS_ZSE: + return NVME_SUCCESS; + + default: + break; + } + + return NVME_INVALID_ZONE_STATE_TRANSITION | NVME_DNR; +} + +static uint16_t nvme_zone_mgmt_send_offline(NvmeCtrl *n, NvmeRequest *req, + NvmeZone *zone) +{ + NvmeNamespace *ns = req->ns; + + trace_pci_nvme_zone_mgmt_send_offline(nvme_cid(req), nvme_nsid(ns), + nvme_zslba(zone), nvme_zs_str(zone)); + + switch (nvme_zs(zone)) { + case NVME_ZS_ZSRO: + if (nvme_deallocate(ns, nvme_zslba(zone), nvme_zcap(zone)) < 0) { + return NVME_INTERNAL_DEV_ERROR; + } + + nvme_zrm_transition(ns, zone, NVME_ZS_ZSO); + if (nvme_zns_commit_zone(ns, zone) < 0) { + return NVME_INTERNAL_DEV_ERROR; + } + + /* fallthrough */ + + case NVME_ZS_ZSO: + return NVME_SUCCESS; + + default: + break; + } + + return NVME_INVALID_ZONE_STATE_TRANSITION | NVME_DNR; +} + +static uint16_t nvme_zone_mgmt_send_set_zde(NvmeCtrl *n, NvmeRequest *req, + NvmeZone *zone) +{ + NvmeNamespace *ns = req->ns; + uint16_t status; + + trace_pci_nvme_zone_mgmt_send_set_zde(nvme_cid(req), nvme_nsid(ns), + nvme_zslba(zone), nvme_zs_str(zone)); + + if (nvme_zs(zone) != NVME_ZS_ZSE) { + trace_pci_nvme_err_invalid_zone_condition(nvme_cid(req), + nvme_zslba(zone), + nvme_zs(zone)); + return NVME_INVALID_ZONE_STATE_TRANSITION | NVME_DNR; + } + + status = nvme_check_mdts(n, nvme_ns_zdes_bytes(ns)); + if (status) { + return status; + } + + status = nvme_dma(n, zone->zde, nvme_ns_zdes_bytes(ns), + DMA_DIRECTION_TO_DEVICE, req); + if (status) { + return status; + } + + status = nvme_zrm_transition(ns, zone, NVME_ZS_ZSC); + if (status) { + return status; + } + + if (nvme_zns_commit_zde(ns, zone) < 0) { + return NVME_INTERNAL_DEV_ERROR; + } + + NVME_ZA_SET(zone->zd->za, NVME_ZA_ZDEV); + + if (nvme_zns_commit_zone(ns, zone) < 0) { + return NVME_INTERNAL_DEV_ERROR; + } + + return NVME_SUCCESS; +} + +static uint16_t nvme_zone_mgmt_send_all(NvmeCtrl *n, NvmeRequest *req) +{ + NvmeZoneManagementSendCmd *send = (NvmeZoneManagementSendCmd *) &req->cmd; + NvmeNamespace *ns = req->ns; + NvmeZone *zone; + + uint16_t status = NVME_SUCCESS; + + trace_pci_nvme_zone_mgmt_send_all(nvme_cid(req), nvme_nsid(ns), send->zsa); + + switch (send->zsa) { + case NVME_CMD_ZONE_MGMT_SEND_SET_ZDE: + return NVME_INVALID_FIELD | NVME_DNR; + + case NVME_CMD_ZONE_MGMT_SEND_CLOSE: + for (int i = 0; i < ns->zns.num_zones; i++) { + zone = &ns->zns.zones[i]; + + switch (nvme_zs(zone)) { + case NVME_ZS_ZSIO: + case NVME_ZS_ZSEO: + status = nvme_zone_mgmt_send_close(n, req, zone); + if (status) { + return status; + } + + default: + continue; + } + } + + break; + + case NVME_CMD_ZONE_MGMT_SEND_FINISH: + for (int i = 0; i < ns->zns.num_zones; i++) { + zone = &ns->zns.zones[i]; + + switch (nvme_zs(zone)) { + case NVME_ZS_ZSIO: + case NVME_ZS_ZSEO: + case NVME_ZS_ZSC: + status = nvme_zone_mgmt_send_finish(n, req, zone); + if (status) { + return status; + } + + default: + continue; + } + } + + break; + + case NVME_CMD_ZONE_MGMT_SEND_OPEN: + for (int i = 0; i < ns->zns.num_zones; i++) { + zone = &ns->zns.zones[i]; + + if (nvme_zs(zone) == NVME_ZS_ZSC) { + status = nvme_zone_mgmt_send_open(n, req, zone); + if (status) { + return status; + } + } + } + + break; + + case NVME_CMD_ZONE_MGMT_SEND_RESET: + for (int i = 0; i < ns->zns.num_zones; i++) { + zone = &ns->zns.zones[i]; + + switch (nvme_zs(zone)) { + case NVME_ZS_ZSIO: + case NVME_ZS_ZSEO: + case NVME_ZS_ZSC: + case NVME_ZS_ZSF: + status = nvme_zone_mgmt_send_reset(n, req, zone); + if (status) { + return status; + } + + default: + continue; + } + } + + break; + + case NVME_CMD_ZONE_MGMT_SEND_OFFLINE: + for (int i = 0; i < ns->zns.num_zones; i++) { + zone = &ns->zns.zones[i]; + + if (nvme_zs(zone) == NVME_ZS_ZSRO) { + status = nvme_zone_mgmt_send_offline(n, req, zone); + if (status) { + return status; + } + } + } + + break; + } + + return NVME_SUCCESS; +} + +static uint16_t nvme_zone_mgmt_send(NvmeCtrl *n, NvmeRequest *req) +{ + NvmeZoneManagementSendCmd *send = (NvmeZoneManagementSendCmd *) &req->cmd; + NvmeZoneManagementSendAction zsa = send->zsa; + NvmeNamespace *ns = req->ns; + NvmeZone *zone; + uint64_t zslba = le64_to_cpu(send->slba); + + if (!nvme_ns_zoned(ns)) { + return NVME_INVALID_OPCODE | NVME_DNR; + } + + trace_pci_nvme_zone_mgmt_send(nvme_cid(req), ns->params.nsid, zslba, zsa, + send->zsflags); + + if (NVME_CMD_ZONE_MGMT_SEND_SELECT_ALL(send->zsflags)) { + return nvme_zone_mgmt_send_all(n, req); + } + + if (zslba & (nvme_ns_zsze(ns) - 1)) { + trace_pci_nvme_err_invalid_zslba(nvme_cid(req), zslba); + return NVME_INVALID_FIELD | NVME_DNR; + } + + zone = nvme_ns_get_zone(ns, zslba); + if (!zone) { + trace_pci_nvme_err_invalid_zone(nvme_cid(req), zslba); + return NVME_INVALID_FIELD | NVME_DNR; + } + + switch (zsa) { + case NVME_CMD_ZONE_MGMT_SEND_CLOSE: + return nvme_zone_mgmt_send_close(n, req, zone); + case NVME_CMD_ZONE_MGMT_SEND_FINISH: + return nvme_zone_mgmt_send_finish(n, req, zone); + case NVME_CMD_ZONE_MGMT_SEND_OPEN: + return nvme_zone_mgmt_send_open(n, req, zone); + case NVME_CMD_ZONE_MGMT_SEND_RESET: + return nvme_zone_mgmt_send_reset(n, req, zone); + case NVME_CMD_ZONE_MGMT_SEND_OFFLINE: + return nvme_zone_mgmt_send_offline(n, req, zone); + case NVME_CMD_ZONE_MGMT_SEND_SET_ZDE: + return nvme_zone_mgmt_send_set_zde(n, req, zone); + } + + return NVME_INVALID_FIELD | NVME_DNR; +} + static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req) { NvmeZoneManagementRecvCmd *recv; @@ -1478,17 +1988,19 @@ static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) } switch (nvme_zs(zone)) { - case NVME_ZS_ZSE: - case NVME_ZS_ZSC: - nvme_zs_set(zone, NVME_ZS_ZSIO); + case NVME_ZS_ZSIO: + case NVME_ZS_ZSEO: + break; + default: + status = nvme_zrm_transition(ns, zone, NVME_ZS_ZSIO); + if (status) { + goto invalid; + } if (nvme_zns_commit_zone(req->ns, zone) < 0) { status = NVME_INTERNAL_DEV_ERROR; goto invalid; } - - default: - break; } zone->wp_staging += nlb; @@ -1541,6 +2053,8 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) case NVME_CMD_WRITE: case NVME_CMD_READ: return nvme_rwz(n, req); + case NVME_CMD_ZONE_MGMT_SEND: + return nvme_zone_mgmt_send(n, req); case NVME_CMD_ZONE_MGMT_RECV: return nvme_zone_mgmt_recv(n, req); default: diff --git a/hw/block/trace-events b/hw/block/trace-events index a2671dadb1e8..d6342f5c555d 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -42,8 +42,18 @@ pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode, cons 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_rwz(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t len, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" len %"PRIu64" lba 0x%"PRIx64"" pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_zone_mgmt_send(uint16_t cid, uint32_t nsid, uint64_t zslba, uint8_t zsa, uint8_t zsflags) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64" zsa 0x%"PRIx8" zsflags 0x%"PRIx8"" +pci_nvme_zone_mgmt_send_all(uint16_t cid, uint32_t nsid, uint8_t za) "cid %"PRIu16" nsid %"PRIu32" za 0x%"PRIx8"" +pci_nvme_zone_mgmt_send_close(uint16_t cid, uint32_t nsid, uint64_t zslba, const char *zc) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64" zc \"%s\"" +pci_nvme_zone_mgmt_send_finish(uint16_t cid, uint32_t nsid, uint64_t zslba, const char *zc) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64" zc \"%s\"" +pci_nvme_zone_mgmt_send_open(uint16_t cid, uint32_t nsid, uint64_t zslba, const char *zc) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64" zc \"%s\"" +pci_nvme_zone_mgmt_send_reset(uint16_t cid, uint32_t nsid, uint64_t zslba, const char *zc) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64" zc \"%s\"" +pci_nvme_zone_mgmt_send_reset_cb(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" +pci_nvme_zone_mgmt_send_offline(uint16_t cid, uint32_t nsid, uint64_t zslba, const char *zc) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64" zc \"%s\"" +pci_nvme_zone_mgmt_send_set_zde(uint16_t cid, uint32_t nsid, uint64_t zslba, const char *zc) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64" zc \"%s\"" pci_nvme_zone_mgmt_recv(uint16_t cid, uint32_t nsid, uint64_t slba, uint64_t len, uint8_t zra, uint8_t zrasp, uint8_t zrasf) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" len %"PRIu64" zra 0x%"PRIx8" zrasp 0x%"PRIx8" zrasf 0x%"PRIx8"" pci_nvme_allocate(uint32_t ns, uint64_t slba, uint32_t nlb) "nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" +pci_nvme_deallocate(uint32_t ns, uint64_t slba, uint32_t nlb) "nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" pci_nvme_do_aio(uint16_t cid, uint8_t opc, const char *opname, const char *blkname, int64_t offset, size_t len) "cid %"PRIu16" opc 0x%"PRIx8" opname '%s' blk '%s' offset %"PRId64" len %zu" pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16"" pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d" @@ -134,6 +144,7 @@ pci_nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx pci_nvme_err_invalid_log_page(uint16_t cid, uint16_t lid) "cid %"PRIu16" lid 0x%"PRIx16"" pci_nvme_err_invalid_zone(uint16_t cid, uint64_t lba) "cid %"PRIu16" lba 0x%"PRIx64"" pci_nvme_err_invalid_zone_condition(uint16_t cid, uint64_t zslba, uint8_t condition) "cid %"PRIu16" zslba 0x%"PRIx64" condition 0x%"PRIx8"" +pci_nvme_err_invalid_zslba(uint16_t cid, uint64_t zslba) "cid %"PRIu16" zslba 0x%"PRIx64"" pci_nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues" pci_nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues" pci_nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null" From patchwork Thu Sep 24 20:45:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 272800 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 88453C4363D for ; Thu, 24 Sep 2020 20:58:57 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 395022399A for ; Thu, 24 Sep 2020 20:58:57 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 395022399A Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:33404 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYKN-0003rk-Vy for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 16:58:56 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38744) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7u-0004oS-57; Thu, 24 Sep 2020 16:46:05 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:57013) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7p-0007nc-EB; Thu, 24 Sep 2020 16:46:01 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id AF1A8580510; Thu, 24 Sep 2020 16:45:35 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:35 -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=fm1; bh=jJX1S5EFJOtee HHyJzPlCusHlpDaqRHoENFD4XbGnPA=; b=hXz3+vJAX81aNeTIt/DyfGQMrW8jU 0sykkaLTRyJJguUaddj6DdJgySLA99pk/990deqhQ1FQkU5TPoD5Xprtoaa5HeKx wFgklJnMF5YkZTPC829CwNI2gYMmamVAgs9XVI/wVRwGDkdq0dgdw+mRjIC+Riul 03xbbS7UG/lC9thye1XYCqpzLTTZe5fZZj1F9WoalZ9kjd5dycmlB5gwC8LOr6V6 agNfT7WmrmLskSAu0vDZKmM9hwb1uDHb7NbnoOLm6WbFYAc7U9jan6nfiGYRHjTB NfI24iJuoHRDPm3Vo5DofVDkenDtfWhVoEMbpcUT4HAL5crsAzttoJgKQ== 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= fm3; bh=jJX1S5EFJOteeHHyJzPlCusHlpDaqRHoENFD4XbGnPA=; b=afnq3BG6 Be/ntPoXLTtPOwq7cRgEv2TOzu0NInNFXpVwbKKwjNBwywwYCEzgX2z4Ca4l69pX i9UbGFdjUlMkH8ETJuEbdenWiO7hhv+I+lGgTe7UCku79HYvPD2LZ02mYjH5ruHK qS49fiqyKk4qH83XERhYGMyfuBfv/e1BzLjCC+dfwz+L8+A7EeWD5Sd78BosJt+E 6Bdd7ixO+lsAVEnQ194nnZURqAYtyQZPrRc7ZqMRDM4tm33LAloRAc1yJZp9IlZu miEsmJFUuz0gCvAxvvFRrVkFV6ORp3Cneg1ZBMA1ZS+E6b73AE3hLupJFbsq5OSb t9IYMKmI/muTrw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeeuleetgeeiuefhgfekfefgveejiefgteekiedtgfdtieefhfdthfefueffvefg keenucfkphepkedtrdduieejrdelkedrudeltdenucevlhhushhtvghrufhiiigvpeejne curfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirhhrvghlvghvrghnthdrughk 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 D4800306467D; Thu, 24 Sep 2020 16:45:33 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 12/16] hw/block/nvme: add the zone append command Date: Thu, 24 Sep 2020 22:45:12 +0200 Message-Id: <20200924204516.1881843-13-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Add the Zone Append command. Signed-off-by: Klaus Jensen --- hw/block/nvme.h | 6 +++++ include/block/nvme.h | 7 ++++++ hw/block/nvme.c | 52 +++++++++++++++++++++++++++++++++++++++++-- hw/block/trace-events | 1 + 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/hw/block/nvme.h b/hw/block/nvme.h index c704663e0a3e..8cd2d936548e 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -16,6 +16,10 @@ typedef struct NvmeParams { uint32_t aer_max_queued; uint8_t mdts; bool use_intel_id; + + struct { + uint8_t zasl; + } zns; } NvmeParams; typedef struct NvmeAsyncEvent { @@ -41,6 +45,7 @@ static inline bool nvme_req_is_write(NvmeRequest *req) switch (req->cmd.opcode) { case NVME_CMD_WRITE: case NVME_CMD_WRITE_ZEROES: + case NVME_CMD_ZONE_APPEND: return true; default: return false; @@ -73,6 +78,7 @@ static inline const char *nvme_io_opc_str(uint8_t opc) case NVME_CMD_WRITE_ZEROES: return "NVME_NVM_CMD_WRITE_ZEROES"; case NVME_CMD_ZONE_MGMT_SEND: return "NVME_ZONED_CMD_ZONE_MGMT_SEND"; case NVME_CMD_ZONE_MGMT_RECV: return "NVME_ZONED_CMD_ZONE_MGMT_RECV"; + case NVME_CMD_ZONE_APPEND: return "NVME_ZONED_CMD_ZONE_APPEND"; default: return "NVME_NVM_CMD_UNKNOWN"; } } diff --git a/include/block/nvme.h b/include/block/nvme.h index 967b42eb5da7..5f8914f594f4 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -483,6 +483,7 @@ enum NvmeIoCommands { NVME_CMD_DSM = 0x09, NVME_CMD_ZONE_MGMT_SEND = 0x79, NVME_CMD_ZONE_MGMT_RECV = 0x7a, + NVME_CMD_ZONE_APPEND = 0x7d, }; typedef struct QEMU_PACKED NvmeDeleteQ { @@ -1018,6 +1019,11 @@ enum NvmeIdCtrlLpa { NVME_LPA_EXTENDED = 1 << 2, }; +typedef struct QEMU_PACKED NvmeIdCtrlZns { + uint8_t zasl; + uint8_t rsvd1[4095]; +} NvmeIdCtrlZns; + #define NVME_CTRL_SQES_MIN(sqes) ((sqes) & 0xf) #define NVME_CTRL_SQES_MAX(sqes) (((sqes) >> 4) & 0xf) #define NVME_CTRL_CQES_MIN(cqes) ((cqes) & 0xf) @@ -1242,6 +1248,7 @@ static inline void _nvme_check_size(void) QEMU_BUILD_BUG_ON(sizeof(NvmeFwSlotInfoLog) != 512); QEMU_BUILD_BUG_ON(sizeof(NvmeSmartLog) != 512); QEMU_BUILD_BUG_ON(sizeof(NvmeIdCtrl) != 4096); + QEMU_BUILD_BUG_ON(sizeof(NvmeIdCtrlZns) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeIdNsNvm) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeIdNsZns) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeSglDescriptor) != 16); diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 51611ed32600..294bc2fb719d 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -166,6 +166,8 @@ static const NvmeEffectsLog nvme_effects[NVME_IOCS_MAX] = { [NVME_CMD_ZONE_MGMT_RECV] = NVME_EFFECTS_CSUPP, [NVME_CMD_ZONE_MGMT_SEND] = NVME_EFFECTS_CSUPP | NVME_EFFECTS_LBCC, + [NVME_CMD_ZONE_APPEND] = NVME_EFFECTS_CSUPP | + NVME_EFFECTS_LBCC, }, }, }; @@ -1041,6 +1043,21 @@ static inline uint16_t nvme_check_mdts(NvmeCtrl *n, size_t len) return NVME_SUCCESS; } +static inline uint16_t nvme_check_zasl(NvmeCtrl *n, size_t len) +{ + uint8_t zasl = n->params.zns.zasl; + + if (!zasl) { + return nvme_check_mdts(n, len); + } + + if (len > n->page_size << zasl) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + return NVME_SUCCESS; +} + static inline uint16_t nvme_check_bounds(NvmeCtrl *n, NvmeNamespace *ns, uint64_t slba, uint32_t nlb) { @@ -1393,6 +1410,7 @@ static uint16_t nvme_do_aio(BlockBackend *blk, int64_t offset, size_t len, break; case NVME_CMD_WRITE: + case NVME_CMD_ZONE_APPEND: is_write = true; /* fallthrough */ @@ -1928,7 +1946,7 @@ static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; size_t len = nvme_l2b(ns, nlb); - bool is_write = nvme_req_is_write(req); + bool is_append, is_write = nvme_req_is_write(req); uint16_t status; trace_pci_nvme_rwz(nvme_cid(req), nvme_io_opc_str(rw->opcode), @@ -1942,6 +1960,25 @@ static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) goto invalid; } + if (req->cmd.opcode == NVME_CMD_ZONE_APPEND) { + is_append = true; + uint64_t wp = zone->wp_staging; + + if (slba != nvme_zslba(zone)) { + trace_pci_nvme_err_invalid_zslba(nvme_cid(req), slba); + return NVME_INVALID_FIELD | NVME_DNR; + } + + status = nvme_check_zasl(n, len); + if (status) { + trace_pci_nvme_err_zasl(nvme_cid(req), len); + goto invalid; + } + + slba = wp; + rw->slba = req->cqe.qw0 = cpu_to_le64(wp); + } + status = nvme_check_zone(n, slba, nlb, req, zone); if (status) { goto invalid; @@ -1980,7 +2017,7 @@ static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) if (is_write) { if (zone) { - if (zone->wp_staging != nvme_wp(zone)) { + if (!is_append && (zone->wp_staging != nvme_wp(zone))) { trace_pci_nvme_err_zone_pending_writes(nvme_cid(req), nvme_zslba(zone), nvme_wp(zone), @@ -2052,6 +2089,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) case NVME_CMD_WRITE_ZEROES: case NVME_CMD_WRITE: case NVME_CMD_READ: + case NVME_CMD_ZONE_APPEND: return nvme_rwz(n, req); case NVME_CMD_ZONE_MGMT_SEND: return nvme_zone_mgmt_send(n, req); @@ -3718,6 +3756,11 @@ static void nvme_check_constraints(NvmeCtrl *n, Error **errp) return; } + if (params->zns.zasl && params->zns.zasl > params->mdts) { + error_setg(errp, "zns.zasl must be less than or equal to mdts"); + return; + } + if (!n->params.cmb_size_mb && n->pmrdev) { if (host_memory_backend_is_mapped(n->pmrdev)) { error_setg(errp, "can't use already busy memdev: %s", @@ -3894,12 +3937,16 @@ static void nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp) static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) { NvmeIdCtrl *id = &n->id_ctrl; + NvmeIdCtrlZns *id_zns; uint8_t *pci_conf = pci_dev->config; char *subnqn; n->id_ctrl_iocss[NVME_IOCS_NVM] = g_new0(NvmeIdCtrl, 1); n->id_ctrl_iocss[NVME_IOCS_ZONED] = g_new0(NvmeIdCtrl, 1); + id_zns = n->id_ctrl_iocss[NVME_IOCS_ZONED]; + id_zns->zasl = n->params.zns.zasl; + id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); strpadcpy((char *)id->mn, sizeof(id->mn), "QEMU NVMe Ctrl", ' '); @@ -4036,6 +4083,7 @@ static Property nvme_props[] = { DEFINE_PROP_UINT32("aer_max_queued", NvmeCtrl, params.aer_max_queued, 64), DEFINE_PROP_UINT8("mdts", NvmeCtrl, params.mdts, 7), DEFINE_PROP_BOOL("use-intel-id", NvmeCtrl, params.use_intel_id, false), + DEFINE_PROP_UINT8("zns.zasl", NvmeCtrl, params.zns.zasl, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/trace-events b/hw/block/trace-events index d6342f5c555d..929409b79b41 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -103,6 +103,7 @@ pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" # nvme traces for error conditions pci_nvme_err_mdts(uint16_t cid, size_t len) "cid %"PRIu16" len %zu" +pci_nvme_err_zasl(uint16_t cid, size_t len) "cid %"PRIu16" len %zu" pci_nvme_err_req_status(uint16_t cid, uint32_t nsid, uint16_t status, uint8_t opc) "cid %"PRIu16" nsid %"PRIu32" status 0x%"PRIx16" opc 0x%"PRIx8"" pci_nvme_err_dulbe(uint16_t cid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" slba 0x%"PRIx64" nlb %"PRIu32"" pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64"" From patchwork Thu Sep 24 20:45:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 272799 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 51F3AC4727D for ; Thu, 24 Sep 2020 21:05:09 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id B1EE72399A for ; Thu, 24 Sep 2020 21:05:08 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B1EE72399A Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:40604 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYQN-00076e-OS for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 17:05:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38784) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY80-0004ps-1m; Thu, 24 Sep 2020 16:46:10 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:44649) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7r-0007ni-16; Thu, 24 Sep 2020 16:46:04 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id DD21F580512; Thu, 24 Sep 2020 16:45:36 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:36 -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=fm1; bh=/InMfmGWiht9c kFzlBfmOp7xYg2i7a0LZ/IF7fQZo5o=; b=qA9G2P+IKfuxJwOlms7X/tQ/LQutV JQJXwT4fuT7tQ02PwHVDQF+7bYND/AozfXBmHGm4UB28JkNmrBm+bp3jRd7fYRfD bxKwERvzEv+6EsPPRfaKqSu6QJ3lztawOpYIUozr09WRUWVIqmyMSJdEsOHpaib9 7uuIsiJLhlE6Zgo9g5hQ2PfCXf5ihmx2qpseoCdDTKyugUT5Xg82SDBbPdzOMXon 8zF3fTUdP3YO4BfiDo3UUGgVC57Zs924XwwusDItq+A4j6Vpux4EycUwKfWQ6dv/ wO9tnAs2QfBra/TEKz+UXNeDI0TbfwA1aRguTUKMEtyQYcbncBeh5qC7g== 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= fm3; bh=/InMfmGWiht9ckFzlBfmOp7xYg2i7a0LZ/IF7fQZo5o=; b=KC1hheak xA6ggx978aK8w1gKepYnD3CJ0daNIZp04go3VwD/IgGT2XLVweoAHE7+bBU+Ro+C Xh73p2hzdyWnXc8G0nTRGqfDNMTUfdu8MV99lA/zUM/OqNNRWH4ZgyOq2Dr/q666 KwWC6nX9wENENFv8G63dEb9XyqVzQei4KvmsDZMTUj0TBx84EJDlz0n7M9tSyzmz Bj+EFOSqS0vUbzW6v89l9jcgUfz6Ux101qu2R/td30iW9mF6BlizE9g+GHhTHiB0 4sgz3iYRnPePIJGKJjvwUP8n7tI40RzRgHu9OatsQiMeVJhst0o0Hjp6rwpv/Sq2 MwnX+/o6eStGcQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeejfeejjeejffelfeeuhffftddvgfegudejvddvffdtvdfhgeejkeehuefhjeej ueenucffohhmrghinheprhgvshhouhhrtggvshdrrggtthhivhgvpdhrvghsohhurhgtvg hsrdhophgvnhenucfkphepkedtrdduieejrdelkedrudeltdenucevlhhushhtvghrufhi iigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirhhrvghlvghvrghnth drughk 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 265253064680; Thu, 24 Sep 2020 16:45:35 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 13/16] hw/block/nvme: track and enforce zone resources Date: Thu, 24 Sep 2020 22:45:13 +0200 Message-Id: <20200924204516.1881843-14-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Track number of open/active resources. Signed-off-by: Klaus Jensen --- docs/specs/nvme.txt | 7 +++++ hw/block/nvme-ns.h | 7 +++++ include/block/nvme.h | 2 ++ hw/block/nvme-ns.c | 25 +++++++++++++++-- hw/block/nvme.c | 65 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 3 deletions(-) diff --git a/docs/specs/nvme.txt b/docs/specs/nvme.txt index 82def65d4c78..921dbce2dc01 100644 --- a/docs/specs/nvme.txt +++ b/docs/specs/nvme.txt @@ -30,6 +30,13 @@ nvme-ns Options zns.zcap; if the zone capacity is a power of two, the zone size will be set to that, otherwise it will default to the next power of two. + `zns.mar`; Specifies the number of active resources available. This is a 0s + based value. + + `zns.mor`; Specifies the number of open resources available. This is a 0s + based value. + + Reference Specifications ------------------------ diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index 5a695334a052..f520ffa89c98 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -28,6 +28,8 @@ typedef struct NvmeNamespaceParams { uint64_t zcap; uint64_t zsze; uint8_t zdes; + uint32_t mar; + uint32_t mor; } zns; } NvmeNamespaceParams; @@ -71,6 +73,11 @@ typedef struct NvmeNamespace { NvmeZone *zones; NvmeZoneDescriptor *zd; uint8_t *zde; + + struct { + uint32_t open; + uint32_t active; + } resources; } zns; } NvmeNamespace; diff --git a/include/block/nvme.h b/include/block/nvme.h index 5f8914f594f4..d51f397e7ff1 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -776,6 +776,8 @@ enum NvmeStatusCodes { NVME_ZONE_IS_READ_ONLY = 0x01ba, NVME_ZONE_IS_OFFLINE = 0x01bb, NVME_ZONE_INVALID_WRITE = 0x01bc, + NVME_TOO_MANY_ACTIVE_ZONES = 0x01bd, + NVME_TOO_MANY_OPEN_ZONES = 0x01be, NVME_INVALID_ZONE_STATE_TRANSITION = 0x01bf, NVME_WRITE_FAULT = 0x0280, NVME_UNRECOVERED_READ = 0x0281, diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 0fb196c7103e..588fe7a1f018 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -119,8 +119,13 @@ static void nvme_ns_init_zoned(NvmeNamespace *ns) id_ns->ncap = ns->zns.num_zones * ns->params.zns.zcap; - id_ns_zns->mar = 0xffffffff; - id_ns_zns->mor = 0xffffffff; + id_ns_zns->mar = cpu_to_le32(ns->params.zns.mar); + id_ns_zns->mor = cpu_to_le32(ns->params.zns.mor); + + ns->zns.resources.active = ns->params.zns.mar != 0xffffffff ? + ns->params.zns.mar + 1 : ns->zns.num_zones; + ns->zns.resources.open = ns->params.zns.mor != 0xffffffff ? + ns->params.zns.mor + 1 : ns->zns.num_zones; } static void nvme_ns_init(NvmeNamespace *ns) @@ -249,9 +254,15 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) if (nvme_wp(zone) == nvme_zslba(zone) && !(zone->zd->za & NVME_ZA_ZDEV)) { nvme_zs_set(zone, NVME_ZS_ZSE); + continue; } - continue; + if (ns->zns.resources.active) { + ns->zns.resources.active--; + continue; + } + + /* fallthrough */ case NVME_ZS_ZSIO: case NVME_ZS_ZSEO: @@ -333,6 +344,12 @@ static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp) return -1; } + if (ns->params.zns.mor > ns->params.zns.mar) { + error_setg(errp, "maximum open resources (zns.mor) must be less " + "than or equal to maximum active resources (zns.mar)"); + return -1; + } + break; default: @@ -418,6 +435,8 @@ static Property nvme_ns_props[] = { DEFINE_PROP_UINT64("zns.zcap", NvmeNamespace, params.zns.zcap, 0), DEFINE_PROP_UINT64("zns.zsze", NvmeNamespace, params.zns.zsze, 0), DEFINE_PROP_UINT8("zns.zdes", NvmeNamespace, params.zns.zdes, 0), + DEFINE_PROP_UINT32("zns.mar", NvmeNamespace, params.zns.mar, 0xffffffff), + DEFINE_PROP_UINT32("zns.mor", NvmeNamespace, params.zns.mor, 0xffffffff), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 294bc2fb719d..79732b8a8574 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1204,6 +1204,40 @@ static uint16_t nvme_zrm_transition(NvmeNamespace *ns, NvmeZone *zone, switch (from) { case NVME_ZS_ZSE: + switch (to) { + case NVME_ZS_ZSF: + case NVME_ZS_ZSRO: + case NVME_ZS_ZSO: + break; + + case NVME_ZS_ZSC: + if (!ns->zns.resources.active) { + return NVME_TOO_MANY_ACTIVE_ZONES; + } + + ns->zns.resources.active--; + + break; + + case NVME_ZS_ZSIO: + case NVME_ZS_ZSEO: + if (!ns->zns.resources.active) { + return NVME_TOO_MANY_ACTIVE_ZONES; + } + + if (!ns->zns.resources.open) { + return NVME_TOO_MANY_OPEN_ZONES; + } + + ns->zns.resources.active--; + ns->zns.resources.open--; + + break; + + default: + return NVME_INVALID_ZONE_STATE_TRANSITION | NVME_DNR; + } + break; case NVME_ZS_ZSIO: @@ -1224,7 +1258,13 @@ static uint16_t nvme_zrm_transition(NvmeNamespace *ns, NvmeZone *zone, case NVME_ZS_ZSF: case NVME_ZS_ZSRO: + ns->zns.resources.active++; + + /* fallthrough */ + case NVME_ZS_ZSC: + ns->zns.resources.open++; + break; default: @@ -1247,8 +1287,18 @@ static uint16_t nvme_zrm_transition(NvmeNamespace *ns, NvmeZone *zone, case NVME_ZS_ZSF: case NVME_ZS_ZSRO: + ns->zns.resources.active++; + + break; + case NVME_ZS_ZSIO: case NVME_ZS_ZSEO: + if (!ns->zns.resources.open) { + return NVME_TOO_MANY_OPEN_ZONES; + } + + ns->zns.resources.open--; + break; default: @@ -1652,6 +1702,7 @@ static uint16_t nvme_zone_mgmt_send_all(NvmeCtrl *n, NvmeRequest *req) NvmeZoneManagementSendCmd *send = (NvmeZoneManagementSendCmd *) &req->cmd; NvmeNamespace *ns = req->ns; NvmeZone *zone; + int count; uint16_t status = NVME_SUCCESS; @@ -1701,6 +1752,20 @@ static uint16_t nvme_zone_mgmt_send_all(NvmeCtrl *n, NvmeRequest *req) break; case NVME_CMD_ZONE_MGMT_SEND_OPEN: + count = 0; + + for (int i = 0; i < ns->zns.num_zones; i++) { + zone = &ns->zns.zones[i]; + + if (nvme_zs(zone) == NVME_ZS_ZSC) { + count++; + } + } + + if (count > ns->zns.resources.open) { + return NVME_TOO_MANY_OPEN_ZONES; + } + for (int i = 0; i < ns->zns.num_zones; i++) { zone = &ns->zns.zones[i]; From patchwork Thu Sep 24 20:45:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 304470 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A3788C4363D for ; Thu, 24 Sep 2020 21:18:54 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id A7671235FD for ; Thu, 24 Sep 2020 21:18:53 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A7671235FD Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:56988 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYdg-0006WD-Bh for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 17:18:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38824) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY84-0004qO-Or; Thu, 24 Sep 2020 16:46:14 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:52279) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7s-0007np-7N; Thu, 24 Sep 2020 16:46:07 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id 6CCA8580514; Thu, 24 Sep 2020 16:45:38 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:38 -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=fm1; bh=TctV81Y8sVtLo HMBw7M1QPWdKaHiBqaHlOXgy7pZfIs=; b=DMk32m1BSxNn2qJuI1J6w6IxYV0pY uVBoK+eEIZyMXUvFfYYajbESzpzgjZUC77T45xyA3CXOzH0z/QgVUGDse9QjiXlV EiXsILxOwYR8VQIxe5PYk0w/JxnburqybHv227/x9er5CUdcD7Rr5jLBezBsTJZc I9ZmHEFd6rEO3BDhA1+baRbXbahn+N0mIUX10NgikHsAoj39VWk/4LJZpQcySmCT louN6MULFC/JXngS7vO0ez3ttVJx1HzqjwQsgaeUnqv5JVlQD4rY8URAK/TF7MVM EYmMyi7CwA0gntPJfxK8rOMUNSDjWMMIJ3PzVEPeXjp2n7KED2YByCALg== 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= fm3; bh=TctV81Y8sVtLoHMBw7M1QPWdKaHiBqaHlOXgy7pZfIs=; b=A0jds+zy buG8w2zedcNEmQ7yrdYakgWBnUW0Vs9TWubv97fzSB448iS3dswYVRfOEWks9mK2 1AB3quNsrE2W2ZRn7ypR9wkskvd2sBIEwPQzKxVxSg5XqEkAztuTLMTkhX6ZGIgE G47KMUausr/4IbbzAxR0O7aPQjZqXMjzkb0jabVDKY4Df0cXoNyKk9rKRsd+0tFx PNx5jlSr5iXQCpd9gSr/U5Ei+0+8OtPVwhIpqfFmzGtzLVldnBQIX/IeMz7DeKhV L0sgSwfSYJdwdjHoYiTJFJ/8a22KpzncItAECQHKsBJOETESRiGvnGxA2qbR+DJQ I64sYDDEMGr9tg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpedvffffudfghfefffdvvddvtdevhffffffgueffkefggfekjefgheduheetvefg heenucffohhmrghinheprhgvshhouhhrtggvshdrohhpvghnpdhrvghsohhurhgtvghsrd grtghtihhvvgenucfkphepkedtrdduieejrdelkedrudeltdenucevlhhushhtvghrufhi iigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirhhrvghlvghvrghnth drughk 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 6AA953064682; Thu, 24 Sep 2020 16:45:36 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 14/16] hw/block/nvme: allow open to close transitions by controller Date: Thu, 24 Sep 2020 22:45:14 +0200 Message-Id: <20200924204516.1881843-15-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Allow the controller to release open resources by transitioning implicitly and explicitly opened zones to closed. This is done using a naive "least recently opened" strategy. Signed-off-by: Klaus Jensen --- hw/block/nvme-ns.h | 5 +++ hw/block/nvme-ns.c | 5 +++ hw/block/nvme.c | 102 +++++++++++++++++++++++++++++++++++------- hw/block/trace-events | 5 +++ 4 files changed, 102 insertions(+), 15 deletions(-) diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index f520ffa89c98..1fdcdf706ff6 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -38,6 +38,8 @@ typedef struct NvmeZone { uint8_t *zde; uint64_t wp_staging; + + QTAILQ_ENTRY(NvmeZone) lru_entry; } NvmeZone; typedef struct NvmeNamespace { @@ -77,6 +79,9 @@ typedef struct NvmeNamespace { struct { uint32_t open; uint32_t active; + + QTAILQ_HEAD(, NvmeZone) lru_open; + QTAILQ_HEAD(, NvmeZone) lru_active; } resources; } zns; } NvmeNamespace; diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 588fe7a1f018..547090282660 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -126,6 +126,9 @@ static void nvme_ns_init_zoned(NvmeNamespace *ns) ns->params.zns.mar + 1 : ns->zns.num_zones; ns->zns.resources.open = ns->params.zns.mor != 0xffffffff ? ns->params.zns.mor + 1 : ns->zns.num_zones; + + QTAILQ_INIT(&ns->zns.resources.lru_open); + QTAILQ_INIT(&ns->zns.resources.lru_active); } static void nvme_ns_init(NvmeNamespace *ns) @@ -259,6 +262,8 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) if (ns->zns.resources.active) { ns->zns.resources.active--; + QTAILQ_INSERT_TAIL(&ns->zns.resources.lru_active, zone, + lru_entry); continue; } diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 79732b8a8574..a43a593ab89e 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1192,12 +1192,61 @@ static inline void nvme_zone_reset_wp(NvmeZone *zone) zone->wp_staging = nvme_zslba(zone); } -static uint16_t nvme_zrm_transition(NvmeNamespace *ns, NvmeZone *zone, - NvmeZoneState to) +static uint16_t nvme_zrm_transition(NvmeCtrl *n, NvmeNamespace *ns, + NvmeZone *zone, NvmeZoneState to, + NvmeRequest *req); + +static uint16_t nvme_zrm_release_open(NvmeCtrl *n, NvmeNamespace *ns, + NvmeRequest *req) +{ + NvmeZone *candidate; + NvmeZoneState zs; + uint16_t status; + + trace_pci_nvme_zone_zrm_release_open(nvme_cid(req), ns->params.nsid); + + QTAILQ_FOREACH(candidate, &ns->zns.resources.lru_open, lru_entry) { + zs = nvme_zs(candidate); + + trace_pci_nvme_zone_zrm_candidate(nvme_cid(req), ns->params.nsid, + nvme_zslba(candidate), + nvme_wp(candidate), zs); + + /* skip explicitly opened zones */ + if (zs == NVME_ZS_ZSEO) { + continue; + } + + /* the zone cannot be closed if it is currently writing */ + if (candidate->wp_staging != nvme_wp(candidate)) { + continue; + } + + status = nvme_zrm_transition(n, ns, candidate, NVME_ZS_ZSC, req); + if (status) { + return status; + } + + if (nvme_zns_commit_zone(ns, candidate) < 0) { + return NVME_INTERNAL_DEV_ERROR; + } + + return NVME_SUCCESS; + } + + return NVME_TOO_MANY_OPEN_ZONES; +} + +static uint16_t nvme_zrm_transition(NvmeCtrl *n, NvmeNamespace *ns, + NvmeZone *zone, NvmeZoneState to, + NvmeRequest *req) { NvmeZoneState from = nvme_zs(zone); + uint16_t status; + + trace_pci_nvme_zone_zrm_transition(nvme_cid(req), ns->params.nsid, + nvme_zslba(zone), nvme_zs(zone), to); - /* fast path */ if (from == to) { return NVME_SUCCESS; } @@ -1212,25 +1261,32 @@ static uint16_t nvme_zrm_transition(NvmeNamespace *ns, NvmeZone *zone, case NVME_ZS_ZSC: if (!ns->zns.resources.active) { + trace_pci_nvme_err_too_many_active_zones(nvme_cid(req)); return NVME_TOO_MANY_ACTIVE_ZONES; } ns->zns.resources.active--; + QTAILQ_INSERT_TAIL(&ns->zns.resources.lru_active, zone, lru_entry); break; case NVME_ZS_ZSIO: case NVME_ZS_ZSEO: if (!ns->zns.resources.active) { + trace_pci_nvme_err_too_many_active_zones(nvme_cid(req)); return NVME_TOO_MANY_ACTIVE_ZONES; } if (!ns->zns.resources.open) { - return NVME_TOO_MANY_OPEN_ZONES; + status = nvme_zrm_release_open(n, ns, req); + if (status) { + return status; + } } ns->zns.resources.active--; ns->zns.resources.open--; + QTAILQ_INSERT_TAIL(&ns->zns.resources.lru_open, zone, lru_entry); break; @@ -1259,11 +1315,15 @@ static uint16_t nvme_zrm_transition(NvmeNamespace *ns, NvmeZone *zone, case NVME_ZS_ZSF: case NVME_ZS_ZSRO: ns->zns.resources.active++; + ns->zns.resources.open++; + QTAILQ_REMOVE(&ns->zns.resources.lru_open, zone, lru_entry); - /* fallthrough */ + break; case NVME_ZS_ZSC: ns->zns.resources.open++; + QTAILQ_REMOVE(&ns->zns.resources.lru_open, zone, lru_entry); + QTAILQ_INSERT_TAIL(&ns->zns.resources.lru_active, zone, lru_entry); break; @@ -1288,16 +1348,22 @@ static uint16_t nvme_zrm_transition(NvmeNamespace *ns, NvmeZone *zone, case NVME_ZS_ZSF: case NVME_ZS_ZSRO: ns->zns.resources.active++; + QTAILQ_REMOVE(&ns->zns.resources.lru_active, zone, lru_entry); break; case NVME_ZS_ZSIO: case NVME_ZS_ZSEO: if (!ns->zns.resources.open) { - return NVME_TOO_MANY_OPEN_ZONES; + status = nvme_zrm_release_open(n, ns, req); + if (status) { + return status; + } } ns->zns.resources.open--; + QTAILQ_REMOVE(&ns->zns.resources.lru_active, zone, lru_entry); + QTAILQ_INSERT_TAIL(&ns->zns.resources.lru_open, zone, lru_entry); break; @@ -1321,6 +1387,9 @@ static uint16_t nvme_zrm_transition(NvmeNamespace *ns, NvmeZone *zone, case NVME_ZS_ZSF: switch (to) { + case NVME_ZS_ZSF: + return NVME_SUCCESS; + case NVME_ZS_ZSE: nvme_zone_reset_wp(zone); @@ -1359,7 +1428,9 @@ static void nvme_zns_advance_wp(NvmeRequest *req) wp += nlb; zone->zd->wp = cpu_to_le64(wp); if (wp == nvme_zslba(zone) + nvme_zcap(zone)) { - nvme_zrm_transition(req->ns, zone, NVME_ZS_ZSF); + NvmeCtrl *n = nvme_ctrl(req); + + nvme_zrm_transition(n, req->ns, zone, NVME_ZS_ZSF, req); if (nvme_zns_commit_zone(req->ns, zone) < 0) { req->status = NVME_INTERNAL_DEV_ERROR; } @@ -1416,6 +1487,7 @@ static void nvme_rw_cb(void *opaque, int ret) uint64_t slba = le64_to_cpu(rw->slba); NvmeZone *zone = nvme_ns_get_zone(ns, slba); + NvmeCtrl *n = nvme_ctrl(req); /* * Transition the zone to read-only on write fault and offline @@ -1424,7 +1496,7 @@ static void nvme_rw_cb(void *opaque, int ret) NvmeZoneState zs = status == NVME_WRITE_FAULT ? NVME_ZS_ZSRO : NVME_ZS_ZSO; - nvme_zrm_transition(ns, zone, zs); + nvme_zrm_transition(n, ns, zone, zs, req); if (nvme_zns_commit_zone(ns, zone) < 0) { req->status = NVME_INTERNAL_DEV_ERROR; } @@ -1518,7 +1590,7 @@ static uint16_t nvme_zone_mgmt_send_close(NvmeCtrl *n, NvmeRequest *req, break; } - status = nvme_zrm_transition(ns, zone, NVME_ZS_ZSC); + status = nvme_zrm_transition(n, ns, zone, NVME_ZS_ZSC, req); if (status) { return status; } @@ -1543,7 +1615,7 @@ static uint16_t nvme_zone_mgmt_send_finish(NvmeCtrl *n, NvmeRequest *req, return NVME_SUCCESS; } - status = nvme_zrm_transition(ns, zone, NVME_ZS_ZSF); + status = nvme_zrm_transition(n, ns, zone, NVME_ZS_ZSF, req); if (status) { return status; } @@ -1568,7 +1640,7 @@ static uint16_t nvme_zone_mgmt_send_open(NvmeCtrl *n, NvmeRequest *req, return NVME_SUCCESS; } - status = nvme_zrm_transition(ns, zone, NVME_ZS_ZSEO); + status = nvme_zrm_transition(n, ns, zone, NVME_ZS_ZSEO, req); if (status) { return status; } @@ -1604,7 +1676,7 @@ static uint16_t nvme_zone_mgmt_send_reset(NvmeCtrl *n, NvmeRequest *req, return NVME_INTERNAL_DEV_ERROR; } - nvme_zrm_transition(ns, zone, NVME_ZS_ZSE); + nvme_zrm_transition(n, ns, zone, NVME_ZS_ZSE, req); if (nvme_zns_commit_zone(ns, zone) < 0) { return NVME_INTERNAL_DEV_ERROR; } @@ -1635,7 +1707,7 @@ static uint16_t nvme_zone_mgmt_send_offline(NvmeCtrl *n, NvmeRequest *req, return NVME_INTERNAL_DEV_ERROR; } - nvme_zrm_transition(ns, zone, NVME_ZS_ZSO); + nvme_zrm_transition(n, ns, zone, NVME_ZS_ZSO, req); if (nvme_zns_commit_zone(ns, zone) < 0) { return NVME_INTERNAL_DEV_ERROR; } @@ -1679,7 +1751,7 @@ static uint16_t nvme_zone_mgmt_send_set_zde(NvmeCtrl *n, NvmeRequest *req, return status; } - status = nvme_zrm_transition(ns, zone, NVME_ZS_ZSC); + status = nvme_zrm_transition(n, ns, zone, NVME_ZS_ZSC, req); if (status) { return status; } @@ -2094,7 +2166,7 @@ static uint16_t nvme_rwz(NvmeCtrl *n, NvmeRequest *req) case NVME_ZS_ZSEO: break; default: - status = nvme_zrm_transition(ns, zone, NVME_ZS_ZSIO); + status = nvme_zrm_transition(n, ns, zone, NVME_ZS_ZSIO, req); if (status) { goto invalid; } diff --git a/hw/block/trace-events b/hw/block/trace-events index 929409b79b41..18f7b24ef5e9 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -88,6 +88,9 @@ pci_nvme_mmio_read(uint64_t addr) "addr 0x%"PRIx64"" pci_nvme_mmio_write(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64"" pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16"" pci_nvme_mmio_doorbell_sq(uint16_t sqid, uint16_t new_tail) "sqid %"PRIu16" new_tail %"PRIu16"" +pci_nvme_zone_zrm_transition(uint16_t cid, uint32_t nsid, uint64_t zslba, uint8_t from, uint8_t to) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64" from 0x%"PRIx8" to 0x%"PRIx8"" +pci_nvme_zone_zrm_candidate(uint16_t cid, uint32_t nsid, uint64_t zslba, uint64_t wp, uint8_t zc) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64" wp 0x%"PRIx64" zc 0x%"PRIx8"" +pci_nvme_zone_zrm_release_open(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64"" pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64"" pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64"" @@ -115,6 +118,8 @@ pci_nvme_err_zone_is_read_only(uint16_t cid, uint64_t slba) "cid %"PRIu16" lba 0 pci_nvme_err_zone_invalid_write(uint16_t cid, uint64_t slba, uint64_t wp) "cid %"PRIu16" lba 0x%"PRIx64" wp 0x%"PRIx64"" pci_nvme_err_zone_boundary(uint16_t cid, uint64_t slba, uint32_t nlb, uint64_t zcap) "cid %"PRIu16" lba 0x%"PRIx64" nlb %"PRIu32" zcap 0x%"PRIx64"" pci_nvme_err_zone_pending_writes(uint16_t cid, uint64_t zslba, uint64_t wp, uint64_t wp_staging) "cid %"PRIu16" zslba 0x%"PRIx64" wp 0x%"PRIx64" wp_staging 0x%"PRIx64"" +pci_nvme_err_too_many_active_zones(uint16_t cid) "cid %"PRIu16"" +pci_nvme_err_too_many_open_zones(uint16_t cid) "cid %"PRIu16"" pci_nvme_err_invalid_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8"" pci_nvme_err_invalid_num_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8"" pci_nvme_err_invalid_sgl_excess_length(uint16_t cid) "cid %"PRIu16"" From patchwork Thu Sep 24 20:45:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 304468 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6A184C4363D for ; Thu, 24 Sep 2020 21:29:24 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 1FC0223899 for ; Thu, 24 Sep 2020 21:29:22 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1FC0223899 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:42552 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYnp-0004Wn-LR for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 17:29:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38850) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY8A-0004rE-HX; Thu, 24 Sep 2020 16:46:20 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:49809) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7s-0007nz-W5; Thu, 24 Sep 2020 16:46:12 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id E613B580100; Thu, 24 Sep 2020 16:45:39 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:39 -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=fm1; bh=YPMTy5VauD8fw 3RCtj4eD6/YQHE7icVqOIkeeHteLak=; b=onpnjY6BpC76U77nbqkLp9J+PvaAD GBGv8LB421q4LHzu2lxWthW3GuOpaIQfffcMfpk+nnlq4YYvaPcy/EQ+ycA9sYOJ eBiGiYFlaqsmCYEnOVhbhy/9HDU6t7OU/nKg1YunIhFieWjWFJFHo482Q9XaC4hg lGXRh4cI+bsTMn8/5IN9tcDHdMEOia8+KBKDhBK5qw6EXhnHlzCktp2gotiSx4x2 e+pDfAtWefdSBPuvuvCMcJcwT9mFUzBPS+YyYcp4+N54RK1Lt4fcTQM1rYL2qR+M Br6I59Oe6f6I4PYirCDogncst4asB9KzkBXCBLShRBUe7MO3kq4vCEQUA== 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= fm3; bh=YPMTy5VauD8fw3RCtj4eD6/YQHE7icVqOIkeeHteLak=; b=HxpxVMZm h0WWe130N9fcAf82A1jgsGm9rTBwIz/y4BY6eyQOTSIrZpbRGDEj5qSbNAcK+Mk3 5FE3L09X8xuV6bAoKJD4WIxVeJ9TWECW6RcXRhj95Rt8AFDefjjNK/1tPWn8KoG8 jHvBjcKND5KfySSC3qCmYH8W1AH4HGo17Q63BtSVTIV+0jNJtOUUesQfDfRQ0M9k NxbCOr/YiMJylorHMbxv5IilHFb0PruEGlSop9NCP+ryM2xyipOuM/9L4TUhmcyE gT0VfxsYUBTePYhpSs3+Ss8MQiYCiKrcSSc7yzridHT8+pK9zOGm605/R/eM2HpW 467u68t6jxZnLw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeejfeejjeejffelfeeuhffftddvgfegudejvddvffdtvdfhgeejkeehuefhjeej ueenucffohhmrghinheprhgvshhouhhrtggvshdrrggtthhivhgvpdhrvghsohhurhgtvg hsrdhophgvnhenucfkphepkedtrdduieejrdelkedrudeltdenucevlhhushhtvghrufhi iigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirhhrvghlvghvrghnth drughk 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 B64FE3064680; Thu, 24 Sep 2020 16:45:37 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 15/16] hw/block/nvme: support zone active excursions Date: Thu, 24 Sep 2020 22:45:15 +0200 Message-Id: <20200924204516.1881843-16-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Allow the controller to release active resources by transitioning zones to the full state if enabled. Signed-off-by: Klaus Jensen --- docs/specs/nvme.txt | 5 ++ hw/block/nvme-ns.h | 3 + include/block/nvme.h | 30 ++++++-- hw/block/nvme-ns.c | 3 + hw/block/nvme.c | 170 ++++++++++++++++++++++++++++++++++++++---- hw/block/trace-events | 5 +- 6 files changed, 197 insertions(+), 19 deletions(-) diff --git a/docs/specs/nvme.txt b/docs/specs/nvme.txt index 921dbce2dc01..a286d9c07025 100644 --- a/docs/specs/nvme.txt +++ b/docs/specs/nvme.txt @@ -36,6 +36,11 @@ nvme-ns Options `zns.mor`; Specifies the number of open resources available. This is a 0s based value. + `zns.zoc`; Specifies Zone Operation Characteristics (ZOC). Only 0x2 is + supported, which allows Zone Active Excursions. If enabled, the controller + will release active resources when needed by transitioning zones to the + Full state. + Reference Specifications ------------------------ diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index 1fdcdf706ff6..d9093fdad984 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -30,6 +30,7 @@ typedef struct NvmeNamespaceParams { uint8_t zdes; uint32_t mar; uint32_t mor; + uint16_t zoc; } zns; } NvmeNamespaceParams; @@ -83,6 +84,8 @@ typedef struct NvmeNamespace { QTAILQ_HEAD(, NvmeZone) lru_open; QTAILQ_HEAD(, NvmeZone) lru_active; } resources; + + NvmeChangedZoneList changed_list; } zns; } NvmeNamespace; diff --git a/include/block/nvme.h b/include/block/nvme.h index d51f397e7ff1..0948a262b2df 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -687,6 +687,7 @@ typedef struct QEMU_PACKED NvmeDsmRange { enum NvmeAsyncEventRequest { NVME_AER_TYPE_ERROR = 0, NVME_AER_TYPE_SMART = 1, + NVME_AER_TYPE_NOTICE = 2, NVME_AER_TYPE_IO_SPECIFIC = 6, NVME_AER_TYPE_VENDOR_SPECIFIC = 7, NVME_AER_INFO_ERR_INVALID_DB_REGISTER = 0, @@ -698,13 +699,15 @@ enum NvmeAsyncEventRequest { NVME_AER_INFO_SMART_RELIABILITY = 0, NVME_AER_INFO_SMART_TEMP_THRESH = 1, NVME_AER_INFO_SMART_SPARE_THRESH = 2, + NVME_AER_INFO_NOTICE_ZONE_DESCR_CHANGED = 0xef, }; typedef struct QEMU_PACKED NvmeAerResult { - uint8_t event_type; - uint8_t event_info; - uint8_t log_page; - uint8_t resv; + uint8_t event_type; + uint8_t event_info; + uint8_t log_page; + uint8_t resv; + uint32_t nsid; } NvmeAerResult; typedef struct QEMU_PACKED NvmeCqe { @@ -882,6 +885,15 @@ typedef struct QEMU_PACKED NvmeZoneDescriptor { uint8_t rsvd32[32]; } NvmeZoneDescriptor; +#define NVME_CHANGED_ZONE_LIST_MAX_IDS 511 + +typedef struct QEMU_PACKED NvmeChangedZoneList { + uint16_t num_ids; + uint8_t rsvd2[6]; + uint64_t ids[NVME_CHANGED_ZONE_LIST_MAX_IDS]; +} NvmeChangedZoneList; + +#define NVME_ZA_ZFC (1 << 0) #define NVME_ZA_ZDEV (1 << 7) #define NVME_ZA_SET(za, attrs) ((za) |= (attrs)) @@ -996,6 +1008,10 @@ typedef struct QEMU_PACKED NvmeIdCtrl { uint8_t vs[1024]; } NvmeIdCtrl; +enum NvmeIdCtrlOaes { + NVME_OAES_ZDCN = 1 << 27, +}; + enum NvmeIdCtrlOacs { NVME_OACS_SECURITY = 1 << 0, NVME_OACS_FORMAT = 1 << 1, @@ -1064,6 +1080,7 @@ typedef struct QEMU_PACKED NvmeIdCtrlZns { #define NVME_AEC_SMART(aec) (aec & 0xff) #define NVME_AEC_NS_ATTR(aec) ((aec >> 8) & 0x1) #define NVME_AEC_FW_ACTIVATION(aec) ((aec >> 9) & 0x1) +#define NVME_AEC_ZDCN(aec) ((aec >> 27) & 0x1) #define NVME_ERR_REC_TLER(err_rec) (err_rec & 0xffff) #define NVME_ERR_REC_DULBE(err_rec) (err_rec & 0x10000) @@ -1231,9 +1248,11 @@ typedef struct QEMU_PACKED NvmeIdNsZns { uint8_t vs[256]; } NvmeIdNsZns; +#define NVME_ID_NS_ZNS_ZOC_ZAE (1 << 1) + static inline void _nvme_check_size(void) { - QEMU_BUILD_BUG_ON(sizeof(NvmeAerResult) != 4); + QEMU_BUILD_BUG_ON(sizeof(NvmeAerResult) != 8); QEMU_BUILD_BUG_ON(sizeof(NvmeCqe) != 16); QEMU_BUILD_BUG_ON(sizeof(NvmeDsmRange) != 16); QEMU_BUILD_BUG_ON(sizeof(NvmeCmd) != 64); @@ -1258,5 +1277,6 @@ static inline void _nvme_check_size(void) QEMU_BUILD_BUG_ON(sizeof(NvmeEffectsLog) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeZoneDescriptor) != 64); QEMU_BUILD_BUG_ON(sizeof(NvmeLBAFE) != 16); + QEMU_BUILD_BUG_ON(sizeof(NvmeChangedZoneList) != 4096); } #endif diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 547090282660..9a9f728d791f 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -104,6 +104,8 @@ static void nvme_ns_init_zoned(NvmeNamespace *ns) NvmeIdNsNvm *id_ns = nvme_ns_id_nvm(ns); NvmeIdNsZns *id_ns_zns = nvme_ns_id_zoned(ns); + id_ns_zns->zoc = cpu_to_le16(ns->params.zns.zoc); + for (int i = 0; i <= id_ns->nlbaf; i++) { id_ns_zns->lbafe[i].zsze = ns->params.zns.zsze ? ns->params.zns.zsze : cpu_to_le64(pow2ceil(ns->params.zns.zcap)); @@ -442,6 +444,7 @@ static Property nvme_ns_props[] = { DEFINE_PROP_UINT8("zns.zdes", NvmeNamespace, params.zns.zdes, 0), DEFINE_PROP_UINT32("zns.mar", NvmeNamespace, params.zns.mar, 0xffffffff), DEFINE_PROP_UINT32("zns.mor", NvmeNamespace, params.zns.mor, 0xffffffff), + DEFINE_PROP_UINT16("zns.zoc", NvmeNamespace, params.zns.zoc, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index a43a593ab89e..ecc88e858eee 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -880,10 +880,11 @@ static void nvme_process_aers(void *opaque) req = n->aer_reqs[n->outstanding_aers]; - result = (NvmeAerResult *) &req->cqe.dw0; + result = (NvmeAerResult *) &req->cqe.qw0; result->event_type = event->result.event_type; result->event_info = event->result.event_info; result->log_page = event->result.log_page; + result->nsid = event->result.nsid; g_free(event); trace_pci_nvme_aer_post_cqe(result->event_type, result->event_info, @@ -893,12 +894,14 @@ static void nvme_process_aers(void *opaque) } } -static void nvme_enqueue_event(NvmeCtrl *n, uint8_t event_type, - uint8_t event_info, uint8_t log_page) +static void nvme_enqueue_event(NvmeCtrl *n, NvmeNamespace *ns, + uint8_t event_type, uint8_t event_info, + uint8_t log_page) { NvmeAsyncEvent *event; - trace_pci_nvme_enqueue_event(event_type, event_info, log_page); + trace_pci_nvme_enqueue_event(ns ? ns->params.nsid : -1, event_type, + event_info, log_page); if (n->aer_queued == n->params.aer_max_queued) { trace_pci_nvme_enqueue_event_noqueue(n->aer_queued); @@ -912,6 +915,11 @@ static void nvme_enqueue_event(NvmeCtrl *n, uint8_t event_type, .log_page = log_page, }; + if (event_info == NVME_AER_INFO_NOTICE_ZONE_DESCR_CHANGED) { + assert(ns); + event->result.nsid = ns->params.nsid; + } + QTAILQ_INSERT_TAIL(&n->aer_queue, event, entry); n->aer_queued++; @@ -1192,10 +1200,54 @@ static inline void nvme_zone_reset_wp(NvmeZone *zone) zone->wp_staging = nvme_zslba(zone); } +static void nvme_zone_changed(NvmeCtrl *n, NvmeNamespace *ns, NvmeZone *zone, + NvmeRequest *req) +{ + uint16_t num_ids = le16_to_cpu(ns->zns.changed_list.num_ids); + + trace_pci_nvme_zone_changed(nvme_cid(req), ns->params.nsid, + nvme_zslba(zone)); + + if (num_ids < NVME_CHANGED_ZONE_LIST_MAX_IDS) { + for (int i = 0; i < num_ids; i++) { + if (ns->zns.changed_list.ids[i] == zone->zd->zslba) { + goto out; + } + } + + ns->zns.changed_list.ids[num_ids] = zone->zd->zslba; + ns->zns.changed_list.num_ids = cpu_to_le16(num_ids + 1); + } else { + memset(&ns->zns.changed_list, 0x0, sizeof(NvmeChangedZoneList)); + ns->zns.changed_list.num_ids = cpu_to_le16(0xffff); + } + +out: + nvme_zns_commit_zone(ns, zone); + + if (NVME_AEC_ZDCN(n->features.async_config)) { + nvme_enqueue_event(n, ns, NVME_AER_TYPE_NOTICE, + NVME_AER_INFO_NOTICE_ZONE_DESCR_CHANGED, + NVME_LOG_CHANGED_ZONE_LIST); + } +} + static uint16_t nvme_zrm_transition(NvmeCtrl *n, NvmeNamespace *ns, NvmeZone *zone, NvmeZoneState to, NvmeRequest *req); +static void nvme_zone_active_excursion(NvmeCtrl *n, NvmeNamespace *ns, + NvmeZone *zone, NvmeRequest *req) +{ + trace_pci_nvme_zone_active_excursion(ns->params.nsid, nvme_zslba(zone), + nvme_zs_str(zone)); + + nvme_zrm_transition(n, ns, zone, NVME_ZS_ZSF, req); + NVME_ZA_SET(zone->zd->za, NVME_ZA_ZFC); + + nvme_zone_changed(n, ns, zone, req); +} + static uint16_t nvme_zrm_release_open(NvmeCtrl *n, NvmeNamespace *ns, NvmeRequest *req) { @@ -1237,6 +1289,57 @@ static uint16_t nvme_zrm_release_open(NvmeCtrl *n, NvmeNamespace *ns, return NVME_TOO_MANY_OPEN_ZONES; } +static uint16_t nvme_zrm_release_active(NvmeCtrl *n, NvmeNamespace *ns, + NvmeRequest *req) +{ + NvmeZone *candidate = NULL; + NvmeZoneDescriptor *zd; + NvmeZoneState zs; + + trace_pci_nvme_zone_zrm_release_active(nvme_cid(req), ns->params.nsid); + + if (ns->params.zns.zoc & NVME_ID_NS_ZNS_ZOC_ZAE) { + return NVME_TOO_MANY_ACTIVE_ZONES; + } + + QTAILQ_FOREACH(candidate, &ns->zns.resources.lru_active, lru_entry) { + zd = candidate->zd; + zs = nvme_zs(candidate); + + trace_pci_nvme_zone_zrm_candidate(nvme_cid(req), ns->params.nsid, + nvme_zslba(candidate), + nvme_wp(candidate), zs); + + goto out; + } + + /* + * If all zone resources are tied up on open zones we have to transition + * one of those to full. + */ + QTAILQ_FOREACH(candidate, &ns->zns.resources.lru_open, lru_entry) { + zd = candidate->zd; + zs = nvme_zs(candidate); + + trace_pci_nvme_zone_zrm_candidate(nvme_cid(req), ns->params.nsid, + nvme_zslba(candidate), + nvme_wp(candidate), zs); + + /* the zone cannot be finished if it is currently writing */ + if (candidate->wp_staging != le64_to_cpu(zd->wp)) { + continue; + } + + break; + } + + assert(candidate); + +out: + nvme_zone_active_excursion(n, ns, candidate, req); + return NVME_SUCCESS; +} + static uint16_t nvme_zrm_transition(NvmeCtrl *n, NvmeNamespace *ns, NvmeZone *zone, NvmeZoneState to, NvmeRequest *req) @@ -1261,8 +1364,10 @@ static uint16_t nvme_zrm_transition(NvmeCtrl *n, NvmeNamespace *ns, case NVME_ZS_ZSC: if (!ns->zns.resources.active) { - trace_pci_nvme_err_too_many_active_zones(nvme_cid(req)); - return NVME_TOO_MANY_ACTIVE_ZONES; + status = nvme_zrm_release_active(n, ns, req); + if (status) { + return status; + } } ns->zns.resources.active--; @@ -1273,8 +1378,10 @@ static uint16_t nvme_zrm_transition(NvmeCtrl *n, NvmeNamespace *ns, case NVME_ZS_ZSIO: case NVME_ZS_ZSEO: if (!ns->zns.resources.active) { - trace_pci_nvme_err_too_many_active_zones(nvme_cid(req)); - return NVME_TOO_MANY_ACTIVE_ZONES; + status = nvme_zrm_release_active(n, ns, req); + if (status) { + return status; + } } if (!ns->zns.resources.open) { @@ -2498,6 +2605,40 @@ static uint16_t nvme_effects_log(NvmeCtrl *n, uint32_t buf_len, uint64_t off, DMA_DIRECTION_FROM_DEVICE, req); } +static uint16_t nvme_changed_zone_info(NvmeCtrl *n, uint32_t buf_len, + uint64_t off, NvmeRequest *req) +{ + uint32_t nsid = le32_to_cpu(req->cmd.nsid); + NvmeNamespace *ns = nvme_ns(n, nsid); + uint32_t trans_len; + uint16_t status; + + if (unlikely(!ns)) { + return NVME_INVALID_NSID | NVME_DNR; + } + + if (!nvme_ns_zoned(ns)) { + return NVME_INVALID_LOG_ID | NVME_DNR; + } + + if (off > sizeof(NvmeChangedZoneList)) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + trans_len = MIN(sizeof(NvmeChangedZoneList) - off, buf_len); + + status = nvme_dma(n, (uint8_t *)&ns->zns.changed_list + off, trans_len, + DMA_DIRECTION_FROM_DEVICE, req); + if (status) { + return status; + } + + memset(&ns->zns.changed_list, 0x0, sizeof(NvmeChangedZoneList)); + nvme_clear_events(n, NVME_AER_TYPE_NOTICE); + + return NVME_SUCCESS; +} + static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest *req) { NvmeCmd *cmd = &req->cmd; @@ -2543,6 +2684,8 @@ static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest *req) return nvme_fw_log_info(n, len, off, req); case NVME_LOG_EFFECTS: return nvme_effects_log(n, len, off, req); + case NVME_LOG_CHANGED_ZONE_LIST: + return nvme_changed_zone_info(n, len, off, req); default: trace_pci_nvme_err_invalid_log_page(nvme_cid(req), lid); return NVME_INVALID_FIELD | NVME_DNR; @@ -3161,7 +3304,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) if (((n->temperature >= n->features.temp_thresh_hi) || (n->temperature <= n->features.temp_thresh_low)) && NVME_AEC_SMART(n->features.async_config) & NVME_SMART_TEMPERATURE) { - nvme_enqueue_event(n, NVME_AER_TYPE_SMART, + nvme_enqueue_event(n, NULL, NVME_AER_TYPE_SMART, NVME_AER_INFO_SMART_TEMP_THRESH, NVME_LOG_SMART_INFO); } @@ -3725,7 +3868,7 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) * fashion. */ if (n->outstanding_aers) { - nvme_enqueue_event(n, NVME_AER_TYPE_ERROR, + nvme_enqueue_event(n, NULL, NVME_AER_TYPE_ERROR, NVME_AER_INFO_ERR_INVALID_DB_REGISTER, NVME_LOG_ERROR_INFO); } @@ -3742,7 +3885,7 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) qid, new_head); if (n->outstanding_aers) { - nvme_enqueue_event(n, NVME_AER_TYPE_ERROR, + nvme_enqueue_event(n, NULL, NVME_AER_TYPE_ERROR, NVME_AER_INFO_ERR_INVALID_DB_VALUE, NVME_LOG_ERROR_INFO); } @@ -3779,7 +3922,7 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) " sqid=%"PRIu32", ignoring", qid); if (n->outstanding_aers) { - nvme_enqueue_event(n, NVME_AER_TYPE_ERROR, + nvme_enqueue_event(n, NULL, NVME_AER_TYPE_ERROR, NVME_AER_INFO_ERR_INVALID_DB_REGISTER, NVME_LOG_ERROR_INFO); } @@ -3796,7 +3939,7 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) qid, new_tail); if (n->outstanding_aers) { - nvme_enqueue_event(n, NVME_AER_TYPE_ERROR, + nvme_enqueue_event(n, NULL, NVME_AER_TYPE_ERROR, NVME_AER_INFO_ERR_INVALID_DB_VALUE, NVME_LOG_ERROR_INFO); } @@ -4095,6 +4238,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) id->ieee[2] = 0xb3; id->mdts = n->params.mdts; id->ver = cpu_to_le32(NVME_SPEC_VER); + id->oaes = cpu_to_le32(NVME_OAES_ZDCN); id->oacs = cpu_to_le16(0); /* diff --git a/hw/block/trace-events b/hw/block/trace-events index 18f7b24ef5e9..ebd786b77868 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -78,7 +78,7 @@ pci_nvme_aer(uint16_t cid) "cid %"PRIu16"" pci_nvme_aer_aerl_exceeded(void) "aerl exceeded" pci_nvme_aer_masked(uint8_t type, uint8_t mask) "type 0x%"PRIx8" mask 0x%"PRIx8"" pci_nvme_aer_post_cqe(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8"" -pci_nvme_enqueue_event(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8"" +pci_nvme_enqueue_event(uint32_t nsid, uint8_t typ, uint8_t info, uint8_t log_page) "nsid 0x%"PRIx32" type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8"" pci_nvme_enqueue_event_noqueue(int queued) "queued %d" pci_nvme_enqueue_event_masked(uint8_t typ) "type 0x%"PRIx8"" pci_nvme_no_outstanding_aers(void) "ignoring event; no outstanding AERs" @@ -91,6 +91,9 @@ pci_nvme_mmio_doorbell_sq(uint16_t sqid, uint16_t new_tail) "sqid %"PRIu16" new_ pci_nvme_zone_zrm_transition(uint16_t cid, uint32_t nsid, uint64_t zslba, uint8_t from, uint8_t to) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64" from 0x%"PRIx8" to 0x%"PRIx8"" pci_nvme_zone_zrm_candidate(uint16_t cid, uint32_t nsid, uint64_t zslba, uint64_t wp, uint8_t zc) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64" wp 0x%"PRIx64" zc 0x%"PRIx8"" pci_nvme_zone_zrm_release_open(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" +pci_nvme_zone_zrm_release_active(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" +pci_nvme_zone_changed(uint16_t cid, uint32_t nsid, uint64_t zslba) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64"" +pci_nvme_zone_active_excursion(uint32_t nsid, uint64_t zslba, const char *zc) "nsid %"PRIu32" zslba 0x%"PRIx64" zc \"%s\"" pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64"" pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64"" pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64"" From patchwork Thu Sep 24 20:45:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Klaus Jensen X-Patchwork-Id: 272801 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 403A2C4363D for ; Thu, 24 Sep 2020 20:56:42 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 72BC0221EB for ; Thu, 24 Sep 2020 20:56:41 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 72BC0221EB Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=irrelevant.dk Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:58088 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kLYIC-0002MI-6A for qemu-devel@archiver.kernel.org; Thu, 24 Sep 2020 16:56:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38852) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY8D-0004re-GH; Thu, 24 Sep 2020 16:46:21 -0400 Received: from new2-smtp.messagingengine.com ([66.111.4.224]:38447) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kLY7u-0007o6-6v; Thu, 24 Sep 2020 16:46:17 -0400 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailnew.nyi.internal (Postfix) with ESMTP id E601D58050C; Thu, 24 Sep 2020 16:45:40 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute7.internal (MEProxy); Thu, 24 Sep 2020 16:45:40 -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=fm1; bh=mN5ShKu9d3P5r pWY9JSKX5DnpusrIBPYR17JFO82ROg=; b=b5FwoGTwKpXr4zMzkhUCaBv3FbnpX JbGK2Qc2yQ9v6w7QTFSmMyONxf8J3x7I5Ph5/A0kWM5UDu6MGJmecQu6ws7xhfzh xzVlqG3oBEpQbUenz6Hsx4hAOm2nUK0nh2t0vwvSYBAK9aVzXexNrN2wTPMakN4b t8UA3ACDaIfAEZFef5rkfZCRIaK700Ubax/fzWdVPayQNUPQgtiahgVN2ipwdwk3 DZTrR4yKYeZFAApZaLiSnyVH5MDgGJG/l04sqXQWIdMU+f9vDxet0qwrZNDmxaBW 6fjA9HP0t8KGbJrCmDjGkRKQsJYGRcXRQrJy+vOmotY28w6JEMJvAfNYg== 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= fm3; bh=mN5ShKu9d3P5rpWY9JSKX5DnpusrIBPYR17JFO82ROg=; b=miXGApZB g5YrNbuQnuAE5EoiD1RgqUiLKzJ1KM9Q/DGw+5xlpLkYDvDv3L+uU7UCyfFBMHzH jozihw4JEBVG9Pnq772yo1pB/cuUb0U1Be9pdZGP4S9qztm1fSyjmsqMQAkiuHHT oUFoqX7KN9GhCvkMWBp4X6MCQGYZYFK+eLR/0JJ980c88gedeMgCT7zcU/ExQsH8 dzFkS5ukqY6SMA8NXDs+ABUwd4fuo3mZknYjqDU92xZXuDybrtbpPKzZlZrg3Ydu wacurqNnON+V/yRQByeNUDG8qpnzYWAO2W3aRUrVWljCNFchfMsaqi5zfSMttLqe MFw7j45oxUVD2Q== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudekgdduheduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefmlhgruhhs ucflvghnshgvnhcuoehithhssehirhhrvghlvghvrghnthdrughkqeenucggtffrrghtth gvrhhnpeevgeetjeefkeegjeffueevjefhjeffheektedvhfehjedtteehtddutdeiteev veenucffohhmrghinhepiihnshdrfhhrlhdprhgvshhouhhrtggvshdrrggtthhivhgvpd hrvghsohhurhgtvghsrdhophgvnhenucfkphepkedtrdduieejrdelkedrudeltdenucev lhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehithhssehirh hrvghlvghvrghnthdrughk 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 060D93064674; Thu, 24 Sep 2020 16:45:38 -0400 (EDT) From: Klaus Jensen To: qemu-devel@nongnu.org Subject: [PATCH 16/16] hw/block/nvme: support reset/finish recommended limits Date: Thu, 24 Sep 2020 22:45:16 +0200 Message-Id: <20200924204516.1881843-17-its@irrelevant.dk> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200924204516.1881843-1-its@irrelevant.dk> References: <20200924204516.1881843-1-its@irrelevant.dk> MIME-Version: 1.0 Received-SPF: pass client-ip=66.111.4.224; envelope-from=its@irrelevant.dk; helo=new2-smtp.messagingengine.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/24 14:55:29 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] 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, 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: Fam Zheng , Kevin Wolf , qemu-block@nongnu.org, Klaus Jensen , Max Reitz , Keith Busch , Klaus Jensen Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Klaus Jensen Add the rrl,rrld,frl and frld device parameters. The frld and rrld parameters specify the delay in seconds until the device sets the Finish and Reset Zone Recommended attributes on zones when they are transitioned to Full or an Opened state respectively. The rrl and frl parameters specify the number of seconds before the device may perform an internal operation to "clear" the attributes again. Signed-off-by: Klaus Jensen --- docs/specs/nvme.txt | 9 +++++ hw/block/nvme-ns.h | 18 ++++++++-- hw/block/nvme.h | 2 ++ include/block/nvme.h | 2 ++ hw/block/nvme-ns.c | 79 +++++++++++++++++++++++++++++++++++++++++++ hw/block/nvme.c | 56 ++++++++++++++++++++++++++++-- hw/block/trace-events | 3 ++ 7 files changed, 165 insertions(+), 4 deletions(-) diff --git a/docs/specs/nvme.txt b/docs/specs/nvme.txt index a286d9c07025..c2f30cfaaea6 100644 --- a/docs/specs/nvme.txt +++ b/docs/specs/nvme.txt @@ -41,6 +41,15 @@ nvme-ns Options will release active resources when needed by transitioning zones to the Full state. + `zns.{rrld,frld}`; Specifies the Reset and Finish Recommended Limit Delays, + that is, the number of seconds until the controller sets the Reset and + Finish Zone Recommended attributes on finished and opened zones + respectively. + + `zns.{rrl,frl}`; Specifies the Reset and Finish Recommended Limits, that is, + the number of seconds until the controller clears the Reset and Finish + Zone Recommended attributes on finished and opened zones respectively. + Reference Specifications ------------------------ diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index d9093fdad984..8daf3a90d7f0 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -31,6 +31,10 @@ typedef struct NvmeNamespaceParams { uint32_t mar; uint32_t mor; uint16_t zoc; + uint32_t rrl; + uint32_t frl; + uint32_t rrld; + uint32_t frld; } zns; } NvmeNamespaceParams; @@ -40,9 +44,15 @@ typedef struct NvmeZone { uint64_t wp_staging; + struct { + int64_t timestamp; + } stats; + QTAILQ_ENTRY(NvmeZone) lru_entry; } NvmeZone; +typedef QTAILQ_HEAD(, NvmeZone) NvmeZoneList; + typedef struct NvmeNamespace { DeviceState parent_obj; BlockConf blkconf; @@ -81,11 +91,15 @@ typedef struct NvmeNamespace { uint32_t open; uint32_t active; - QTAILQ_HEAD(, NvmeZone) lru_open; - QTAILQ_HEAD(, NvmeZone) lru_active; + NvmeZoneList lru_open; + NvmeZoneList lru_active; } resources; NvmeChangedZoneList changed_list; + + NvmeZoneList lru_finished; + QEMUTimer *timer; + int64_t rrl_ns, rrld_ns, frl_ns, frld_ns; } zns; } NvmeNamespace; diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 8cd2d936548e..d840ff2cb97c 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -203,5 +203,7 @@ static inline NvmeCtrl *nvme_ctrl(NvmeRequest *req) } int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp); +void nvme_zone_changed(NvmeCtrl *n, NvmeNamespace *ns, NvmeZone *zone, + NvmeRequest *req); #endif /* HW_NVME_H */ diff --git a/include/block/nvme.h b/include/block/nvme.h index 0948a262b2df..a66da8c46f9e 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -894,6 +894,8 @@ typedef struct QEMU_PACKED NvmeChangedZoneList { } NvmeChangedZoneList; #define NVME_ZA_ZFC (1 << 0) +#define NVME_ZA_FZR (1 << 1) +#define NVME_ZA_RZR (1 << 2) #define NVME_ZA_ZDEV (1 << 7) #define NVME_ZA_SET(za, attrs) ((za) |= (attrs)) diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 9a9f728d791f..6243458a436c 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -50,6 +50,64 @@ const char *nvme_zs_to_str(NvmeZoneState zs) return NULL; } +static void nvme_ns_set_zone_attrs(NvmeCtrl *n, NvmeNamespace *ns, + NvmeZoneList *zone_list, int64_t delay, + int64_t limit, int64_t *next_timer, + uint8_t attr) +{ + NvmeZone *zone, *next; + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int64_t timestamp; + + QTAILQ_FOREACH_SAFE(zone, zone_list, lru_entry, next) { + timestamp = zone->stats.timestamp; + if (now - timestamp < delay) { + *next_timer = MIN(*next_timer, timestamp + delay); + return; + } + + if (now - timestamp < delay + limit) { + trace_pci_nvme_ns_set_zone_attr(nvme_zslba(zone), attr); + zone->zd->za |= attr; + *next_timer = MIN(*next_timer, timestamp + delay + limit); + } else { + trace_pci_nvme_ns_clear_zone_attr(nvme_zslba(zone), attr); + zone->zd->za &= ~attr; + QTAILQ_REMOVE(zone_list, zone, lru_entry); + QTAILQ_INSERT_TAIL(zone_list, zone, lru_entry); + + zone->stats.timestamp = now; + *next_timer = MIN(*next_timer, now + delay); + } + + nvme_zone_changed(n, ns, zone, NULL); + } +} + +static void nvme_ns_process_timer(void *opaque) +{ + NvmeNamespace *ns = opaque; + BusState *s = qdev_get_parent_bus(&ns->parent_obj); + NvmeCtrl *n = NVME(s->parent); + int64_t next_timer = INT64_MAX; + + trace_pci_nvme_ns_process_timer(ns->params.nsid); + + nvme_ns_set_zone_attrs(n, ns, &ns->zns.resources.lru_open, ns->zns.frld_ns, + ns->zns.frl_ns, &next_timer, NVME_ZA_FZR); + + nvme_ns_set_zone_attrs(n, ns, &ns->zns.resources.lru_active, + ns->zns.frld_ns, ns->zns.frl_ns, &next_timer, + NVME_ZA_FZR); + + nvme_ns_set_zone_attrs(n, ns, &ns->zns.lru_finished, ns->zns.rrld_ns, + ns->zns.rrl_ns, &next_timer, NVME_ZA_RZR); + + if (next_timer != INT64_MAX) { + timer_mod(ns->zns.timer, next_timer); + } +} + static int nvme_blk_truncate(BlockBackend *blk, size_t len, Error **errp) { int ret; @@ -121,6 +179,21 @@ static void nvme_ns_init_zoned(NvmeNamespace *ns) id_ns->ncap = ns->zns.num_zones * ns->params.zns.zcap; + id_ns_zns->rrl = ns->params.zns.rrl; + id_ns_zns->frl = ns->params.zns.frl; + + if (ns->params.zns.rrl || ns->params.zns.frl) { + ns->zns.rrl_ns = ns->params.zns.rrl * NANOSECONDS_PER_SECOND; + ns->zns.rrld_ns = ns->params.zns.rrld * NANOSECONDS_PER_SECOND; + ns->zns.frl_ns = ns->params.zns.frl * NANOSECONDS_PER_SECOND; + ns->zns.frld_ns = ns->params.zns.frld * NANOSECONDS_PER_SECOND; + + ns->zns.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + nvme_ns_process_timer, ns); + + QTAILQ_INIT(&ns->zns.lru_finished); + } + id_ns_zns->mar = cpu_to_le32(ns->params.zns.mar); id_ns_zns->mor = cpu_to_le32(ns->params.zns.mor); @@ -266,6 +339,8 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns, Error **errp) ns->zns.resources.active--; QTAILQ_INSERT_TAIL(&ns->zns.resources.lru_active, zone, lru_entry); + zone->stats.timestamp = + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); continue; } @@ -445,6 +520,10 @@ static Property nvme_ns_props[] = { DEFINE_PROP_UINT32("zns.mar", NvmeNamespace, params.zns.mar, 0xffffffff), DEFINE_PROP_UINT32("zns.mor", NvmeNamespace, params.zns.mor, 0xffffffff), DEFINE_PROP_UINT16("zns.zoc", NvmeNamespace, params.zns.zoc, 0), + DEFINE_PROP_UINT32("zns.rrl", NvmeNamespace, params.zns.rrl, 0), + DEFINE_PROP_UINT32("zns.frl", NvmeNamespace, params.zns.frl, 0), + DEFINE_PROP_UINT32("zns.rrld", NvmeNamespace, params.zns.rrld, 0), + DEFINE_PROP_UINT32("zns.frld", NvmeNamespace, params.zns.frld, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index ecc88e858eee..d472ed240059 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1200,8 +1200,8 @@ static inline void nvme_zone_reset_wp(NvmeZone *zone) zone->wp_staging = nvme_zslba(zone); } -static void nvme_zone_changed(NvmeCtrl *n, NvmeNamespace *ns, NvmeZone *zone, - NvmeRequest *req) +void nvme_zone_changed(NvmeCtrl *n, NvmeNamespace *ns, NvmeZone *zone, + NvmeRequest *req) { uint16_t num_ids = le16_to_cpu(ns->zns.changed_list.num_ids); @@ -1244,6 +1244,7 @@ static void nvme_zone_active_excursion(NvmeCtrl *n, NvmeNamespace *ns, nvme_zrm_transition(n, ns, zone, NVME_ZS_ZSF, req); NVME_ZA_SET(zone->zd->za, NVME_ZA_ZFC); + NVME_ZA_CLEAR(zone->zd->za, NVME_ZA_FZR); nvme_zone_changed(n, ns, zone, req); } @@ -1340,6 +1341,16 @@ out: return NVME_SUCCESS; } +static void nvme_zone_activate(NvmeNamespace *ns, NvmeZone *zone) +{ + zone->stats.timestamp = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + if (ns->params.zns.frld && !timer_pending(ns->zns.timer)) { + int64_t next_timer = zone->stats.timestamp + ns->zns.frld_ns; + timer_mod(ns->zns.timer, next_timer); + } +} + static uint16_t nvme_zrm_transition(NvmeCtrl *n, NvmeNamespace *ns, NvmeZone *zone, NvmeZoneState to, NvmeRequest *req) @@ -1373,6 +1384,8 @@ static uint16_t nvme_zrm_transition(NvmeCtrl *n, NvmeNamespace *ns, ns->zns.resources.active--; QTAILQ_INSERT_TAIL(&ns->zns.resources.lru_active, zone, lru_entry); + nvme_zone_activate(ns, zone); + break; case NVME_ZS_ZSIO: @@ -1395,6 +1408,7 @@ static uint16_t nvme_zrm_transition(NvmeCtrl *n, NvmeNamespace *ns, ns->zns.resources.open--; QTAILQ_INSERT_TAIL(&ns->zns.resources.lru_open, zone, lru_entry); + nvme_zone_activate(ns, zone); break; default: @@ -1521,6 +1535,43 @@ static uint16_t nvme_zrm_transition(NvmeCtrl *n, NvmeNamespace *ns, } nvme_zs_set(zone, to); + + if (ns->params.zns.rrld) { + switch (to) { + case NVME_ZS_ZSRO: + /* clock is already ticking if the zone was already full */ + if (from == NVME_ZS_ZSF) { + break; + } + + /* fallthrough */ + + case NVME_ZS_ZSF: + QTAILQ_INSERT_TAIL(&ns->zns.lru_finished, zone, lru_entry); + + zone->stats.timestamp = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + if (!timer_pending(ns->zns.timer)) { + int64_t next_timer = zone->stats.timestamp + ns->zns.rrld_ns; + timer_mod(ns->zns.timer, next_timer); + } + + break; + + case NVME_ZS_ZSE: + case NVME_ZS_ZSO: + if (from == NVME_ZS_ZSF) { + QTAILQ_REMOVE(&ns->zns.lru_finished, zone, lru_entry); + zone->stats.timestamp = 0; + } + + break; + + default: + break; + } + } + return NVME_SUCCESS; } @@ -1727,6 +1778,7 @@ static uint16_t nvme_zone_mgmt_send_finish(NvmeCtrl *n, NvmeRequest *req, return status; } + NVME_ZA_CLEAR(zone->zd->za, NVME_ZA_FZR); if (nvme_zns_commit_zone(ns, zone) < 0) { return NVME_INTERNAL_DEV_ERROR; } diff --git a/hw/block/trace-events b/hw/block/trace-events index ebd786b77868..917520b6f4d4 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -94,6 +94,9 @@ pci_nvme_zone_zrm_release_open(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid pci_nvme_zone_zrm_release_active(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" pci_nvme_zone_changed(uint16_t cid, uint32_t nsid, uint64_t zslba) "cid %"PRIu16" nsid %"PRIu32" zslba 0x%"PRIx64"" pci_nvme_zone_active_excursion(uint32_t nsid, uint64_t zslba, const char *zc) "nsid %"PRIu32" zslba 0x%"PRIx64" zc \"%s\"" +pci_nvme_ns_process_timer(uint32_t nsid) "nsid %"PRIu32"" +pci_nvme_ns_set_zone_attr(uint64_t zslba, uint8_t attr) "zslba 0x%"PRIx64" attr 0x%"PRIu8"" +pci_nvme_ns_clear_zone_attr(uint64_t zslba, uint8_t attr) "zslba 0x%"PRIx64" attr 0x%"PRIu8"" pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64"" pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64"" pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""