From patchwork Wed Jun 17 21:33:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Fomichev X-Patchwork-Id: 280152 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.6 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, 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 D1C0AC433E0 for ; Wed, 17 Jun 2020 21:45: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 9B0352168B for ; Wed, 17 Jun 2020 21:45:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="J5xilHuK" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9B0352168B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:46342 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jlfrk-0004X6-Qw for qemu-devel@archiver.kernel.org; Wed, 17 Jun 2020 17:45:04 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45912) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jlfhd-0003bS-KE; Wed, 17 Jun 2020 17:34:37 -0400 Received: from esa1.hgst.iphmx.com ([68.232.141.245]:29844) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jlfhb-0005Dr-6a; Wed, 17 Jun 2020 17:34:37 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1592429674; x=1623965674; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=TP+9GhGC6V6UFGFXIelPM1rn6ry/YJFB4JIxShesYoU=; b=J5xilHuK4Xa9GshogIYdN3eKBuqLoSPPNaRxZXPjk7kemrldNuPSGO+I NnsjHpcbqsEAIyN8Oo2bUUsrcjqWo3phEMvtIv0DHa8uNQteqSBEy+6cE TuD7cYVuc27cQ4xLVvXTeyFDiFVYy/dc4ADwqHYSOWZlccXsAv9AYtkOL MIAkuUu1V60VN2c5O+2NC5wczydU8KxjfRc4FU5z07aR0VbyQLB/trp8z YN1cYxiV8//mmPeT9bFN3lILjijS+v62dmUZwVnu45pUBpjxzLwp0gYGQ BH0KPgq0kNDvUvMBWx8VHm6+gLxOx/Qo1lqR+GkdRipOLTNNMVvXpHhhO A==; IronPort-SDR: SiUu3anDmdA9i+gWIdXzQBPpu9MnHba6kZuWixSWlUNPxn5CegNUbNkcD/0duRwtXbiaE+ZhcQ Ul6xOSUxpdpmU3dfGIAKiyg9Rs1CLwKYfMAtQuobkfBhYDb09Ys7qRQ59a0Ts2RwD51mVLkh6y iRrlO5zurqo1CNpRM4j2EZ6IA7euesVza7c+LbPQGs1PiU/5/hfjN49ALRB/XOuMEYOECwMtbN AWMGh4a6j0z92TP1XckwbcKeDHAzrsc3a4DjX3lEFoDIsmQIZBSC8jCbnkRj56jeKhdj3UW2c0 d/w= X-IronPort-AV: E=Sophos;i="5.73,523,1583164800"; d="scan'208";a="249439789" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 18 Jun 2020 05:34:31 +0800 IronPort-SDR: Uj8dOHpAczLcaCzxqw5+YJNuDL+cJHDAL+tJsFGZ7TZApaInAxCkjtNgu2BhzsMPJn900UkCYW 7QAFmkt1xXCDhMRr88cxtj/QBayDo/2t8= Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jun 2020 14:23:12 -0700 IronPort-SDR: h00Lh9Ktzk6vEIDdrED3Zl3dCtUJB1Xf2OJVU0xaRcnHowMxE6Kpa0xww+y4IZ4b5Mk3CrrNqP PVYGpqpsGkWQ== WDCIronportException: Internal Received: from unknown (HELO redsun50.ssa.fujisawa.hgst.com) ([10.149.66.24]) by uls-op-cesaip02.wdc.com with ESMTP; 17 Jun 2020 14:34:30 -0700 From: Dmitry Fomichev To: Kevin Wolf , Keith Busch , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Maxim Levitsky Subject: [PATCH v2 02/18] hw/block/nvme: Define 64 bit cqe.result Date: Thu, 18 Jun 2020 06:33:59 +0900 Message-Id: <20200617213415.22417-3-dmitry.fomichev@wdc.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20200617213415.22417-1-dmitry.fomichev@wdc.com> References: <20200617213415.22417-1-dmitry.fomichev@wdc.com> MIME-Version: 1.0 Received-SPF: pass client-ip=68.232.141.245; envelope-from=prvs=430b82a1d=dmitry.fomichev@wdc.com; helo=esa1.hgst.iphmx.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/06/17 17:34:28 X-ACL-Warn: Detected OS = FreeBSD 9.x or newer [fuzzy] X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN 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: Niklas Cassel , Damien Le Moal , qemu-block@nongnu.org, Dmitry Fomichev , qemu-devel@nongnu.org, Matias Bjorling Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Ajay Joshi A new write command, Zone Append, is added as a part of Zoned Namespace Command Set. Upon successful completion of this command, the controller returns the start LBA of the performed write operation in cqe.result field. Therefore, the maximum size of this variable needs to be changed from 32 to 64 bit, consuming the reserved 32 bit field that follows the result in CQE struct. Since the existing commands are expected to return a 32 bit LE value, two separate variables, result32 and result64, are now kept in a union. Signed-off-by: Ajay Joshi Signed-off-by: Dmitry Fomichev --- block/nvme.c | 2 +- block/trace-events | 2 +- hw/block/nvme.c | 6 +++--- include/block/nvme.h | 6 ++++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/block/nvme.c b/block/nvme.c index eb2f54dd9d..ca245ec574 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -287,7 +287,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(le64_to_cpu(c->result64), le16_to_cpu(c->sq_head), le16_to_cpu(c->sq_id), le16_to_cpu(c->cid), diff --git a/block/trace-events b/block/trace-events index 29dff8881c..05c1393943 100644 --- a/block/trace-events +++ b/block/trace-events @@ -156,7 +156,7 @@ vxhs_get_creds(const char *cacert, const char *client_key, const char *client_ce # nvme.c nvme_kick(void *s, int queue) "s %p queue %d" nvme_dma_flush_queue_wait(void *s) "s %p" -nvme_error(int cmd_specific, int sq_head, int sqid, int cid, int status) "cmd_specific %d sq_head %d sqid %d cid %d status 0x%x" +nvme_error(uint64_t cmd_specific, int sq_head, int sqid, int cid, int status) "cmd_specific %ld sq_head %d sqid %d cid %d status 0x%x" nvme_process_completion(void *s, int index, int inflight) "s %p queue %d inflight %d" nvme_process_completion_queue_busy(void *s, int index) "s %p queue %d" nvme_complete_command(void *s, int index, int cid) "s %p queue %d cid %d" diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 3ed9f3d321..a1bbc9acde 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -823,7 +823,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) return NVME_INVALID_FIELD | NVME_DNR; } - req->cqe.result = result; + req->cqe.result32 = result; return NVME_SUCCESS; } @@ -859,8 +859,8 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, 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.result32 = cpu_to_le32((n->params.max_ioqpairs - 1) | + ((n->params.max_ioqpairs - 1) << 16)); break; case NVME_TIMESTAMP: return nvme_set_feature_timestamp(n, cmd); diff --git a/include/block/nvme.h b/include/block/nvme.h index 1720ee1d51..9c3a04dcd7 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -577,8 +577,10 @@ typedef struct NvmeAerResult { } NvmeAerResult; typedef struct NvmeCqe { - uint32_t result; - uint32_t rsvd; + union { + uint64_t result64; + uint32_t result32; + }; uint16_t sq_head; uint16_t sq_id; uint16_t cid; From patchwork Wed Jun 17 21:34:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Fomichev X-Patchwork-Id: 280149 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.6 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, 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 5911FC433DF for ; Wed, 17 Jun 2020 21:49:38 +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 22F7D2070A for ; Wed, 17 Jun 2020 21:49:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="TqT7SBJx" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 22F7D2070A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:36202 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jlfw9-0004j3-Bd for qemu-devel@archiver.kernel.org; Wed, 17 Jun 2020 17:49:37 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45970) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jlfhh-0003jc-02; Wed, 17 Jun 2020 17:34:41 -0400 Received: from esa1.hgst.iphmx.com ([68.232.141.245]:29831) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jlfhc-0005By-QC; Wed, 17 Jun 2020 17:34:40 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1592429676; x=1623965676; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=VW+dI6TvAaMrKKR91glOG79oHU+lmwb39OiAXEN/4fk=; b=TqT7SBJxVtcEqPn95bK4p3c+0RYoiKCn32X9rqKF6FubTRoZ86WARHKF Vn23ogHj99b73pZtu5Bmzwu+EUfNhZ58hG/S5Z0Z5xE2tC+vczhI5w68Q sFePvoZiwCETJ0j99tUsDS6QhDXhVxbxLgPtIimha6JMIWXy29OBVwYA0 aUZ/kuyfiopOPyYBOSkoG57QJZ1S5p1IIwXsU2onpe9agruDC4XBHRmWE LazbRQ1OklmFcgnWpyf4nOkJF10ArVyvo5S916obd3woN7ScLD5okuziI 5TsPGi2DojEwc0SZpAj3TqXQKZuKPs1gfxzSCLK/P8PA3q1Av6QLhv75o Q==; IronPort-SDR: LcFcDANmQvIHdO6cRadgp9TNRkXGwY5AGL+EILAerRzou+WJJx6KpB0yaEp/5EBe5KUiywoTfc 7pec73PpXKWzfMQ/TzPHDCCHj9WFWF+0uTURKSV+iwgK+9MRAFKQBJUfzxBaS1ke5/bU56dfnG wHZSQcTxXNzQFJ6656k5NXJbSnAY0W7GWzsLhpna6IiZyWM0gkN1BYvA9Iw1iCaUaB+oluFFF9 0j23JY8eIrK8ih+Chje1poBnKv2MJ9IzKWcd/nseSeD3qWgXYqCzAkA1p1jxomB5IeI4f6vGC7 uz4= X-IronPort-AV: E=Sophos;i="5.73,523,1583164800"; d="scan'208";a="249439792" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 18 Jun 2020 05:34:33 +0800 IronPort-SDR: DE3CKNVxw/HIDJZEAfRfiQzuBXgLzOBZl57R7wQNmxCjQqwFKJZiKuvQ9ioyugZ1oZT0avkfBa GhbbyIzhmLne0OWFLSb/o9PF3rE5mkC9o= Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jun 2020 14:23:14 -0700 IronPort-SDR: PVyZEXqMhpOlCrTi2nPGHvEkOBSuZj5CskZFLEuomzUdCVbQXApSte5ZFlyYihDHrPjFNwsOWe jKJ7L1Wsbj/g== WDCIronportException: Internal Received: from unknown (HELO redsun50.ssa.fujisawa.hgst.com) ([10.149.66.24]) by uls-op-cesaip02.wdc.com with ESMTP; 17 Jun 2020 14:34:31 -0700 From: Dmitry Fomichev To: Kevin Wolf , Keith Busch , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Maxim Levitsky Subject: [PATCH v2 03/18] hw/block/nvme: Clean up unused AER definitions Date: Thu, 18 Jun 2020 06:34:00 +0900 Message-Id: <20200617213415.22417-4-dmitry.fomichev@wdc.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20200617213415.22417-1-dmitry.fomichev@wdc.com> References: <20200617213415.22417-1-dmitry.fomichev@wdc.com> MIME-Version: 1.0 Received-SPF: pass client-ip=68.232.141.245; envelope-from=prvs=430b82a1d=dmitry.fomichev@wdc.com; helo=esa1.hgst.iphmx.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/06/17 17:34:28 X-ACL-Warn: Detected OS = FreeBSD 9.x or newer [fuzzy] X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN 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: Niklas Cassel , Damien Le Moal , qemu-block@nongnu.org, Dmitry Fomichev , qemu-devel@nongnu.org, Matias Bjorling Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Removed unused struct NvmeAerResult and SMART-related async event codes. All other event codes are now categorized by their type. This avoids having to define the same values in a single enum, NvmeAsyncEventRequest, that is now removed. Later commits in this series will define additional values in some of these enums. No functional change. Signed-off-by: Dmitry Fomichev --- hw/block/nvme.h | 1 - include/block/nvme.h | 43 ++++++++++++++++++++++--------------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 0460cc0e62..4f0dac39ae 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -13,7 +13,6 @@ typedef struct NvmeParams { typedef struct NvmeAsyncEvent { QSIMPLEQ_ENTRY(NvmeAsyncEvent) entry; - NvmeAerResult result; } NvmeAsyncEvent; enum NvmeRequestFlags { diff --git a/include/block/nvme.h b/include/block/nvme.h index 9c3a04dcd7..3099df99eb 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -553,28 +553,30 @@ typedef struct NvmeDsmRange { uint64_t slba; } NvmeDsmRange; -enum NvmeAsyncEventRequest { - NVME_AER_TYPE_ERROR = 0, - NVME_AER_TYPE_SMART = 1, - NVME_AER_TYPE_IO_SPECIFIC = 6, - NVME_AER_TYPE_VENDOR_SPECIFIC = 7, - NVME_AER_INFO_ERR_INVALID_SQ = 0, - NVME_AER_INFO_ERR_INVALID_DB = 1, - NVME_AER_INFO_ERR_DIAG_FAIL = 2, - NVME_AER_INFO_ERR_PERS_INTERNAL_ERR = 3, - NVME_AER_INFO_ERR_TRANS_INTERNAL_ERR = 4, - NVME_AER_INFO_ERR_FW_IMG_LOAD_ERR = 5, - NVME_AER_INFO_SMART_RELIABILITY = 0, - NVME_AER_INFO_SMART_TEMP_THRESH = 1, - NVME_AER_INFO_SMART_SPARE_THRESH = 2, +enum NvmeAsyncEventType { + NVME_AER_TYPE_ERROR = 0x00, + NVME_AER_TYPE_SMART = 0x01, + NVME_AER_TYPE_NOTICE = 0x02, + NVME_AER_TYPE_CMDSET_SPECIFIC = 0x06, + NVME_AER_TYPE_VENDOR_SPECIFIC = 0x07, }; -typedef struct NvmeAerResult { - uint8_t event_type; - uint8_t event_info; - uint8_t log_page; - uint8_t resv; -} NvmeAerResult; +enum NvmeAsyncErrorInfo { + NVME_AER_ERR_INVALID_SQ = 0x00, + NVME_AER_ERR_INVALID_DB = 0x01, + NVME_AER_ERR_DIAG_FAIL = 0x02, + NVME_AER_ERR_PERS_INTERNAL_ERR = 0x03, + NVME_AER_ERR_TRANS_INTERNAL_ERR = 0x04, + NVME_AER_ERR_FW_IMG_LOAD_ERR = 0x05, +}; + +enum NvmeAsyncNoticeInfo { + NVME_AER_NOTICE_NS_CHANGED = 0x00, +}; + +enum NvmeAsyncEventCfg { + NVME_AEN_CFG_NS_ATTR = 1 << 8, +}; typedef struct NvmeCqe { union { @@ -881,7 +883,6 @@ enum NvmeIdNsDps { static inline void _nvme_check_size(void) { - QEMU_BUILD_BUG_ON(sizeof(NvmeAerResult) != 4); QEMU_BUILD_BUG_ON(sizeof(NvmeCqe) != 16); QEMU_BUILD_BUG_ON(sizeof(NvmeDsmRange) != 16); QEMU_BUILD_BUG_ON(sizeof(NvmeCmd) != 64); From patchwork Wed Jun 17 21:34:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Fomichev X-Patchwork-Id: 280141 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.6 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, 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 6B1F6C433DF for ; Wed, 17 Jun 2020 22:06:34 +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 2F7342082F for ; Wed, 17 Jun 2020 22:06:33 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="O9DllsKz" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2F7342082F Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:37012 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jlgCX-00062y-4s for qemu-devel@archiver.kernel.org; Wed, 17 Jun 2020 18:06:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45956) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jlfhf-0003fo-Ei; Wed, 17 Jun 2020 17:34:39 -0400 Received: from esa1.hgst.iphmx.com ([68.232.141.245]:29837) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jlfhd-0005DU-7t; Wed, 17 Jun 2020 17:34:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1592429676; x=1623965676; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=aqgqaLO1ZcNkybwn5HB7GQlLkwoHClg6t6ocDRLv81s=; b=O9DllsKzaIhb/iDuNHTyJc/2UQ/3R8m7CSVhPh+7H1VIZX/1syfvqKDd EqJ7IKYzjAG94qF0jMRZR+8VuVUyVInYRjZF4IasBwYbyGU5oReRy1HKj diRjK4VBEh8pAa/Q224FvDrkBUt9Tf/cI32IT+Od5z4wSMFbt7fbS+Mw5 cmyGR9ueIY7OqpKzN8jzDvjDK5rMjCyeGcQDFtpFnXiv6fk77u7+OcZqY 7nVv/FRpDBo3pI6yiW0dGTrIcQyDbNgIh+ppzoO0iDbIvO6sDWSibX2Ri UkXMIFfoGxoxiLkZI7HmA/o5OGoRutauErNrguvtr/gdruk6r9JAaoswI g==; IronPort-SDR: gXyfMwM3GvpEDv+LKNY+ILdioz+8pgRnpWHAWRKdKkHb0vt3k5mycyA1gpP9hyVsbPCwHmyrms NFCqUt7vJtB4BS0sCzaSontL8cCIfxWbBOuRTm0/dMeE2iCjrZ5vnUUQHvpPDqCeO+gyAwFdfd CK0E7jDHj1mEsomRj6NLWgdZqQNsJTPNemyZNNtV9y/rGpXNlAGssxMygH79NGscwh19aapFEy B/3sBqTqrJsLdpAOAeUJdupsj7rJFBt4yOfswileXcV13HI0c38/0/qNFZB1V8HSK+hquqqKTg fko= X-IronPort-AV: E=Sophos;i="5.73,523,1583164800"; d="scan'208";a="249439796" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 18 Jun 2020 05:34:35 +0800 IronPort-SDR: /j9pauwMqTfyxF2AJLczocKSD+4QeDzme8iweFXFXyp12Om7f4K27ymxIkjtJ8ma5q8FqM43Kg eGWGSXAl3xuBeKrVMmfj5eZHAXhKmLWrs= Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jun 2020 14:23:16 -0700 IronPort-SDR: RXZbLbNO2L+8aoDA/8kGOgeP/C1DU/k5Uosx3JCTU4VLj+0Lp1SEuTkaURo5agUru2v7DXUhpe KDbcCK97fIvQ== WDCIronportException: Internal Received: from unknown (HELO redsun50.ssa.fujisawa.hgst.com) ([10.149.66.24]) by uls-op-cesaip02.wdc.com with ESMTP; 17 Jun 2020 14:34:33 -0700 From: Dmitry Fomichev To: Kevin Wolf , Keith Busch , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Maxim Levitsky Subject: [PATCH v2 04/18] hw/block/nvme: Add Commands Supported and Effects log Date: Thu, 18 Jun 2020 06:34:01 +0900 Message-Id: <20200617213415.22417-5-dmitry.fomichev@wdc.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20200617213415.22417-1-dmitry.fomichev@wdc.com> References: <20200617213415.22417-1-dmitry.fomichev@wdc.com> MIME-Version: 1.0 Received-SPF: pass client-ip=68.232.141.245; envelope-from=prvs=430b82a1d=dmitry.fomichev@wdc.com; helo=esa1.hgst.iphmx.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/06/17 17:34:28 X-ACL-Warn: Detected OS = FreeBSD 9.x or newer [fuzzy] X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN 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: Niklas Cassel , Damien Le Moal , qemu-block@nongnu.org, Dmitry Fomichev , qemu-devel@nongnu.org, Matias Bjorling Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This log page becomes necessary to implement to allow checking for Zone Append command support in Zoned Namespace Command Set. This commit adds the code to report this log page for NVM Command Set only. The parts that are specific to zoned operation will be added later in the series. Signed-off-by: Dmitry Fomichev --- hw/block/nvme.c | 62 +++++++++++++++++++++++++++++++++++++++++++ hw/block/trace-events | 4 +++ include/block/nvme.h | 18 +++++++++++++ 3 files changed, 84 insertions(+) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index a1bbc9acde..03b8deee85 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -871,6 +871,66 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) return NVME_SUCCESS; } +static uint16_t nvme_handle_cmd_effects(NvmeCtrl *n, NvmeCmd *cmd, + uint64_t prp1, uint64_t prp2, uint64_t ofs, uint32_t len) +{ + NvmeEffectsLog cmd_eff_log = {}; + uint32_t *iocs = cmd_eff_log.iocs; + + trace_pci_nvme_cmd_supp_and_effects_log_read(); + + if (ofs != 0) { + trace_pci_nvme_err_invalid_effects_log_offset(ofs); + return NVME_INVALID_FIELD | NVME_DNR; + } + if (len != sizeof(cmd_eff_log)) { + trace_pci_nvme_err_invalid_effects_log_len(len); + return NVME_INVALID_FIELD | NVME_DNR; + } + + iocs[NVME_ADM_CMD_DELETE_SQ] = NVME_CMD_EFFECTS_CSUPP; + iocs[NVME_ADM_CMD_CREATE_SQ] = NVME_CMD_EFFECTS_CSUPP; + iocs[NVME_ADM_CMD_DELETE_CQ] = NVME_CMD_EFFECTS_CSUPP; + iocs[NVME_ADM_CMD_CREATE_CQ] = NVME_CMD_EFFECTS_CSUPP; + iocs[NVME_ADM_CMD_IDENTIFY] = NVME_CMD_EFFECTS_CSUPP; + iocs[NVME_ADM_CMD_SET_FEATURES] = NVME_CMD_EFFECTS_CSUPP; + iocs[NVME_ADM_CMD_GET_FEATURES] = NVME_CMD_EFFECTS_CSUPP; + iocs[NVME_ADM_CMD_GET_LOG_PAGE] = NVME_CMD_EFFECTS_CSUPP; + + iocs[NVME_CMD_FLUSH] = NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC; + iocs[NVME_CMD_WRITE_ZEROS] = NVME_CMD_EFFECTS_CSUPP | + NVME_CMD_EFFECTS_LBCC; + iocs[NVME_CMD_WRITE] = NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC; + iocs[NVME_CMD_READ] = NVME_CMD_EFFECTS_CSUPP; + + return nvme_dma_read_prp(n, (uint8_t *)&cmd_eff_log, len, prp1, prp2); +} + +static uint16_t nvme_get_log_page(NvmeCtrl *n, NvmeCmd *cmd) +{ + uint64_t prp1 = le64_to_cpu(cmd->prp1); + uint64_t prp2 = le64_to_cpu(cmd->prp2); + uint32_t dw10 = le32_to_cpu(cmd->cdw10); + uint32_t dw11 = le32_to_cpu(cmd->cdw11); + uint64_t dw12 = le32_to_cpu(cmd->cdw12); + uint64_t dw13 = le32_to_cpu(cmd->cdw13); + uint64_t ofs = (dw13 << 32) | dw12; + uint32_t numdl, numdu, len; + uint16_t lid = dw10 & 0xff; + + numdl = dw10 >> 16; + numdu = dw11 & 0xffff; + len = (((numdu << 16) | numdl) + 1) << 2; + + switch (lid) { + case NVME_LOG_CMD_EFFECTS: + return nvme_handle_cmd_effects(n, cmd, prp1, prp2, ofs, len); + } + + trace_pci_nvme_unsupported_log_page(lid); + return NVME_INVALID_FIELD | NVME_DNR; +} + static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) { switch (cmd->opcode) { @@ -888,6 +948,8 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) return nvme_set_feature(n, cmd, req); case NVME_ADM_CMD_GET_FEATURES: return nvme_get_feature(n, cmd, req); + case NVME_ADM_CMD_GET_LOG_PAGE: + return nvme_get_log_page(n, cmd); default: trace_pci_nvme_err_invalid_admin_opc(cmd->opcode); return NVME_INVALID_OPCODE | NVME_DNR; diff --git a/hw/block/trace-events b/hw/block/trace-events index 958fcc5508..423d491e27 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -58,6 +58,7 @@ pci_nvme_mmio_start_success(void) "setting controller enable bit succeeded" pci_nvme_mmio_stopped(void) "cleared controller enable bit" pci_nvme_mmio_shutdown_set(void) "shutdown bit set" pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" +pci_nvme_cmd_supp_and_effects_log_read(void) "commands supported and effects log read" # nvme traces for error conditions pci_nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size" @@ -69,6 +70,8 @@ pci_nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not w pci_nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8"" pci_nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8"" pci_nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64"" +pci_nvme_err_invalid_effects_log_offset(uint64_t ofs) "commands supported and effects log offset must be 0, got %"PRIu64"" +pci_nvme_err_invalid_effects_log_len(uint32_t len) "commands supported and effects log size is 4096, got %"PRIu32"" pci_nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16"" pci_nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16"" pci_nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16"" @@ -123,6 +126,7 @@ pci_nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for pci_nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring" pci_nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring" pci_nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring" +pci_nvme_unsupported_log_page(uint16_t lid) "unsupported log page 0x%"PRIx16"" # xen-block.c xen_block_realize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u" diff --git a/include/block/nvme.h b/include/block/nvme.h index 3099df99eb..6a58bac0c2 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -691,10 +691,27 @@ enum NvmeSmartWarn { NVME_SMART_FAILED_VOLATILE_MEDIA = 1 << 4, }; +typedef struct NvmeEffectsLog { + uint32_t acs[256]; + uint32_t iocs[256]; + uint8_t resv[2048]; +} NvmeEffectsLog; + +enum { + NVME_CMD_EFFECTS_CSUPP = 1 << 0, + NVME_CMD_EFFECTS_LBCC = 1 << 1, + NVME_CMD_EFFECTS_NCC = 1 << 2, + NVME_CMD_EFFECTS_NIC = 1 << 3, + NVME_CMD_EFFECTS_CCC = 1 << 4, + NVME_CMD_EFFECTS_CSE_MASK = 3 << 16, + NVME_CMD_EFFECTS_UUID_SEL = 1 << 19, +}; + enum LogIdentifier { NVME_LOG_ERROR_INFO = 0x01, NVME_LOG_SMART_INFO = 0x02, NVME_LOG_FW_SLOT_INFO = 0x03, + NVME_LOG_CMD_EFFECTS = 0x05, }; typedef struct NvmePSD { @@ -898,5 +915,6 @@ 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(NvmeIdNs) != 4096); + QEMU_BUILD_BUG_ON(sizeof(NvmeEffectsLog) != 4096); } #endif From patchwork Wed Jun 17 21:34:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Fomichev X-Patchwork-Id: 280148 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.6 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, 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 07122C433DF for ; Wed, 17 Jun 2020 21:49:49 +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 B18AB21841 for ; Wed, 17 Jun 2020 21:49:48 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="GfGe6Ltv" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B18AB21841 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:37110 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jlfwJ-00055Q-Q3 for qemu-devel@archiver.kernel.org; Wed, 17 Jun 2020 17:49:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46010) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jlfhk-0003sV-Nd; Wed, 17 Jun 2020 17:34:44 -0400 Received: from esa1.hgst.iphmx.com ([68.232.141.245]:29831) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jlfhi-0005By-1X; Wed, 17 Jun 2020 17:34:44 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1592429681; x=1623965681; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=BTlEYW/OIGNe1O/+CzIdwtV8VpzfF9Y5asbK1bA+GI8=; b=GfGe6LtvhXHf0DZSyOhoOPZuPlJ7cUzkJujI5fLFKFCoiAXMi3h2S01T wNviQ7YCYXCyFBTUlozvV62AdBgO1i4rj0hcF/Acr8OGvKUVETvIlcli7 yeSDUxQwviUBZT9Z7F3yLEt0TEmrVZoRF9zcMh/1IyuWH19BxfVR9X2WF LvEm5PyWKqcOk5G+e/Qbtxn2mjrYn0KobGiDOLdkhpes7of/TLJdSfQVJ Fqrs7SrTW9wit/o4fuZbYEaqzQ/WMyLSH80jm4aDEblprAbOUcX3r2tQm sLLIu8o8zwWZga6inqsQ1b5MivfZurFUzj22cfAw7UC8lzRBmxIOBTiUB A==; IronPort-SDR: HczuxzW3FIA+UoqAyhysVRbMqpGsjPI0+KJmMrEVd128jJ3s8e3N4GxY9jKoVDrWV4TJ5yKZdv m1rgE/BknpXyMHO8/rSBy8GZbd1HKsg5VQJK0j1dHdn7FXVigUNgslNKQBk9oaEDKO4r8w3g+3 OH2aUO61W7veBVa8208iz2YRTGdJ6xM47yoOJ3tCenRJ+IueZsUwzYOrrBITL2snHyFITDWRo7 M+A08wR+Xo3nIbe9Lz2axXs/5dPWL586/m9t2dW2CMjaIL5H9wfLAI8KK+t3f6BOQ35DoY2RQL 1NY= X-IronPort-AV: E=Sophos;i="5.73,523,1583164800"; d="scan'208";a="249439807" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 18 Jun 2020 05:34:40 +0800 IronPort-SDR: cho6mr2Lb9CH+QKBjZt5iiKNgPQN0XPjRdLJlgVBe7yFlqF5v/h12ntRbMuOBwb6mq0EHodOtO 0V0Z9akgVfANyXt4V0BJdx5Ck/R+Q4hlA= Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jun 2020 14:23:21 -0700 IronPort-SDR: xi7P+Pp5rAeX3cWRJgFBY3ZZU2T4yzgfcyMDOgXAyc7xFLRCfJ7TH8b6IcjZijUMPWwpYOZ3Km cjv0lzn2G8bg== WDCIronportException: Internal Received: from unknown (HELO redsun50.ssa.fujisawa.hgst.com) ([10.149.66.24]) by uls-op-cesaip02.wdc.com with ESMTP; 17 Jun 2020 14:34:39 -0700 From: Dmitry Fomichev To: Kevin Wolf , Keith Busch , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Maxim Levitsky Subject: [PATCH v2 07/18] hw/block/nvme: Add support for Namespace Types Date: Thu, 18 Jun 2020 06:34:04 +0900 Message-Id: <20200617213415.22417-8-dmitry.fomichev@wdc.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20200617213415.22417-1-dmitry.fomichev@wdc.com> References: <20200617213415.22417-1-dmitry.fomichev@wdc.com> MIME-Version: 1.0 Received-SPF: pass client-ip=68.232.141.245; envelope-from=prvs=430b82a1d=dmitry.fomichev@wdc.com; helo=esa1.hgst.iphmx.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/06/17 17:34:28 X-ACL-Warn: Detected OS = FreeBSD 9.x or newer [fuzzy] X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN 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: Niklas Cassel , Damien Le Moal , qemu-block@nongnu.org, Dmitry Fomichev , qemu-devel@nongnu.org, Matias Bjorling Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Niklas Cassel Namespace Types introduce a new command set, "I/O Command Sets", that allows the host to retrieve the command sets associated with a namespace. Introduce support for the command set, and enable detection for the NVM Command Set. Signed-off-by: Niklas Cassel Signed-off-by: Dmitry Fomichev --- hw/block/nvme.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++-- hw/block/nvme.h | 11 +++ 2 files changed, 216 insertions(+), 5 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 03b8deee85..453f4747a5 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -686,6 +686,26 @@ static uint16_t nvme_identify_ctrl(NvmeCtrl *n, NvmeIdentify *c) prp1, prp2); } +static uint16_t nvme_identify_ctrl_csi(NvmeCtrl *n, NvmeIdentify *c) +{ + uint64_t prp1 = le64_to_cpu(c->prp1); + uint64_t prp2 = le64_to_cpu(c->prp2); + static const int data_len = NVME_IDENTIFY_DATA_SIZE; + uint32_t *list; + uint16_t ret; + + trace_pci_nvme_identify_ctrl_csi(c->csi); + + if (c->csi == NVME_CSI_NVM) { + list = g_malloc0(data_len); + ret = nvme_dma_read_prp(n, (uint8_t *)list, data_len, prp1, prp2); + g_free(list); + return ret; + } else { + return NVME_INVALID_FIELD | NVME_DNR; + } +} + static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c) { NvmeNamespace *ns; @@ -701,11 +721,42 @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c) } ns = &n->namespaces[nsid - 1]; + assert(nsid == ns->nsid); return nvme_dma_read_prp(n, (uint8_t *)&ns->id_ns, sizeof(ns->id_ns), prp1, prp2); } +static uint16_t nvme_identify_ns_csi(NvmeCtrl *n, NvmeIdentify *c) +{ + NvmeNamespace *ns; + uint32_t nsid = le32_to_cpu(c->nsid); + uint64_t prp1 = le64_to_cpu(c->prp1); + uint64_t prp2 = le64_to_cpu(c->prp2); + static const int data_len = NVME_IDENTIFY_DATA_SIZE; + uint32_t *list; + uint16_t ret; + + trace_pci_nvme_identify_ns_csi(nsid, c->csi); + + if (unlikely(nsid == 0 || nsid > n->num_namespaces)) { + trace_pci_nvme_err_invalid_ns(nsid, n->num_namespaces); + return NVME_INVALID_NSID | NVME_DNR; + } + + ns = &n->namespaces[nsid - 1]; + assert(nsid == ns->nsid); + + if (c->csi == NVME_CSI_NVM) { + list = g_malloc0(data_len); + ret = nvme_dma_read_prp(n, (uint8_t *)list, data_len, prp1, prp2); + g_free(list); + return ret; + } else { + return NVME_INVALID_FIELD | NVME_DNR; + } +} + static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c) { static const int data_len = NVME_IDENTIFY_DATA_SIZE; @@ -733,6 +784,99 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c) return ret; } +static uint16_t nvme_identify_nslist_csi(NvmeCtrl *n, NvmeIdentify *c) +{ + static const int data_len = NVME_IDENTIFY_DATA_SIZE; + uint32_t min_nsid = le32_to_cpu(c->nsid); + uint64_t prp1 = le64_to_cpu(c->prp1); + uint64_t prp2 = le64_to_cpu(c->prp2); + uint32_t *list; + uint16_t ret; + int i, j = 0; + + trace_pci_nvme_identify_nslist_csi(min_nsid, c->csi); + + if (c->csi != NVME_CSI_NVM) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + list = g_malloc0(data_len); + for (i = 0; i < n->num_namespaces; i++) { + if (i < min_nsid) { + continue; + } + list[j++] = cpu_to_le32(i + 1); + if (j == data_len / sizeof(uint32_t)) { + break; + } + } + ret = nvme_dma_read_prp(n, (uint8_t *)list, data_len, prp1, prp2); + g_free(list); + return ret; +} + +static uint16_t nvme_list_ns_descriptors(NvmeCtrl *n, NvmeIdentify *c) +{ + NvmeNamespace *ns; + uint32_t nsid = le32_to_cpu(c->nsid); + uint64_t prp1 = le64_to_cpu(c->prp1); + uint64_t prp2 = le64_to_cpu(c->prp2); + void *buf_ptr; + NvmeNsIdDesc *desc; + static const int data_len = NVME_IDENTIFY_DATA_SIZE; + uint8_t *buf; + uint16_t status; + + trace_pci_nvme_list_ns_descriptors(); + + if (unlikely(nsid == 0 || nsid > n->num_namespaces)) { + trace_pci_nvme_err_invalid_ns(nsid, n->num_namespaces); + return NVME_INVALID_NSID | NVME_DNR; + } + + ns = &n->namespaces[nsid - 1]; + assert(nsid == ns->nsid); + + buf = g_malloc0(data_len); + buf_ptr = buf; + + desc = buf_ptr; + desc->nidt = NVME_NIDT_UUID; + desc->nidl = NVME_NIDL_UUID; + buf_ptr += sizeof(*desc); + memcpy(buf_ptr, ns->uuid.data, NVME_NIDL_UUID); + buf_ptr += NVME_NIDL_UUID; + + desc = buf_ptr; + desc->nidt = NVME_NIDT_CSI; + desc->nidl = NVME_NIDL_CSI; + buf_ptr += sizeof(*desc); + *(uint8_t *)buf_ptr = NVME_CSI_NVM; + + status = nvme_dma_read_prp(n, buf, data_len, prp1, prp2); + g_free(buf); + return status; +} + +static uint16_t nvme_identify_cmd_set(NvmeCtrl *n, NvmeIdentify *c) +{ + uint64_t prp1 = le64_to_cpu(c->prp1); + uint64_t prp2 = le64_to_cpu(c->prp2); + static const int data_len = NVME_IDENTIFY_DATA_SIZE; + uint32_t *list; + uint8_t *ptr; + uint16_t status; + + trace_pci_nvme_identify_cmd_set(); + + list = g_malloc0(data_len); + ptr = (uint8_t *)list; + NVME_SET_CSI(*ptr, NVME_CSI_NVM); + status = nvme_dma_read_prp(n, (uint8_t *)list, data_len, prp1, prp2); + g_free(list); + return status; +} + static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd) { NvmeIdentify *c = (NvmeIdentify *)cmd; @@ -740,10 +884,20 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd) switch (le32_to_cpu(c->cns)) { case NVME_ID_CNS_NS: return nvme_identify_ns(n, c); + case NVME_ID_CNS_CS_NS: + return nvme_identify_ns_csi(n, c); case NVME_ID_CNS_CTRL: return nvme_identify_ctrl(n, c); + case NVME_ID_CNS_CS_CTRL: + return nvme_identify_ctrl_csi(n, c); case NVME_ID_CNS_NS_ACTIVE_LIST: return nvme_identify_nslist(n, c); + case NVME_ID_CNS_CS_NS_ACTIVE_LIST: + return nvme_identify_nslist_csi(n, c); + case NVME_ID_CNS_NS_DESC_LIST: + return nvme_list_ns_descriptors(n, c); + case NVME_ID_CNS_IO_COMMAND_SET: + return nvme_identify_cmd_set(n, c); default: trace_pci_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns)); return NVME_INVALID_FIELD | NVME_DNR; @@ -818,6 +972,9 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) break; case NVME_TIMESTAMP: return nvme_get_feature_timestamp(n, cmd); + case NVME_COMMAND_SET_PROFILE: + result = 0; + break; default: trace_pci_nvme_err_invalid_getfeat(dw10); return NVME_INVALID_FIELD | NVME_DNR; @@ -864,6 +1021,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) break; case NVME_TIMESTAMP: return nvme_set_feature_timestamp(n, cmd); + break; + + case NVME_COMMAND_SET_PROFILE: + if (dw11 & 0x1ff) { + trace_pci_nvme_err_invalid_iocsci(dw11 & 0x1ff); + return NVME_CMD_SET_CMB_REJECTED | NVME_DNR; + } + break; + default: trace_pci_nvme_err_invalid_setfeat(dw10); return NVME_INVALID_FIELD | NVME_DNR; @@ -1149,6 +1315,29 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, break; case 0x14: /* CC */ trace_pci_nvme_mmio_cfg(data & 0xffffffff); + + if (NVME_CC_CSS(data) != NVME_CC_CSS(n->bar.cc)) { + if (NVME_CC_EN(n->bar.cc)) { + NVME_GUEST_ERR(pci_nvme_err_change_css_when_enabled, + "changing selected command set when enabled"); + break; + } + switch (NVME_CC_CSS(data)) { + case CSS_NVM_ONLY: + trace_pci_nvme_css_nvm_cset_selected_by_host(data & 0xffffffff); + break; + case CSS_ALL_NSTYPES: + NVME_SET_CC_CSS(n->bar.cc, CSS_ALL_NSTYPES); + trace_pci_nvme_css_all_csets_sel_by_host(data & 0xffffffff); + break; + case CSS_ADMIN_ONLY: + break; + default: + NVME_GUEST_ERR(pci_nvme_ub_unknown_css_value, + "unknown value in CC.CSS field"); + } + } + /* Windows first sends data, then sends enable bit */ if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) && !NVME_CC_SHN(data) && !NVME_CC_SHN(n->bar.cc)) @@ -1496,6 +1685,7 @@ static void nvme_init_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) { int64_t bs_size; NvmeIdNs *id_ns = &ns->id_ns; + int lba_index; bs_size = blk_getlength(n->conf.blk); if (bs_size < 0) { @@ -1505,7 +1695,10 @@ static void nvme_init_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) n->ns_size = bs_size; - id_ns->lbaf[0].ds = BDRV_SECTOR_BITS; + ns->csi = NVME_CSI_NVM; + qemu_uuid_generate(&ns->uuid); /* TODO make UUIDs persistent */ + lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas); + id_ns->lbaf[lba_index].ds = nvme_ilog2(n->conf.logical_block_size); id_ns->nsze = cpu_to_le64(nvme_ns_nlbas(n, ns)); /* no thin provisioning */ @@ -1616,7 +1809,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) 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", ' '); - strpadcpy((char *)id->fr, sizeof(id->fr), "1.0", ' '); + strpadcpy((char *)id->fr, sizeof(id->fr), "2.0", ' '); strpadcpy((char *)id->sn, sizeof(id->sn), n->params.serial, ' '); id->rab = 6; id->ieee[0] = 0x00; @@ -1640,7 +1833,11 @@ 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); + /* + * The driver now always supports NS Types, but all commands that + * support CSI field will only handle NVM Command Set. + */ + NVME_CAP_SET_CSS(n->bar.cap, (CAP_CSS_NVM | CAP_CSS_CSI_SUPP)); NVME_CAP_SET_MPSMAX(n->bar.cap, 4); n->bar.vs = 0x00010200; @@ -1650,6 +1847,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) static void nvme_realize(PCIDevice *pci_dev, Error **errp) { NvmeCtrl *n = NVME(pci_dev); + NvmeNamespace *ns; Error *local_err = NULL; int i; @@ -1675,8 +1873,10 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) nvme_init_ctrl(n, pci_dev); - for (i = 0; i < n->num_namespaces; i++) { - nvme_init_namespace(n, &n->namespaces[i], &local_err); + ns = n->namespaces; + for (i = 0; i < n->num_namespaces; i++, ns++) { + ns->nsid = i + 1; + nvme_init_namespace(n, ns, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 4fd155c409..0d29f75475 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -121,4 +121,15 @@ static inline uint64_t nvme_ns_nlbas(NvmeCtrl *n, NvmeNamespace *ns) return n->ns_size >> nvme_ns_lbads(ns); } +static inline int nvme_ilog2(uint64_t i) +{ + int log = -1; + + while (i) { + i >>= 1; + log++; + } + return log; +} + #endif /* HW_NVME_H */ From patchwork Wed Jun 17 21:34:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Fomichev X-Patchwork-Id: 280146 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.5 required=3.0 tests=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 7A9BAC433E0 for ; Wed, 17 Jun 2020 21:52:11 +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 4861C21548 for ; Wed, 17 Jun 2020 21:52:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="JaJezOhI" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4861C21548 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:46374 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jlfyc-0000iZ-GI for qemu-devel@archiver.kernel.org; Wed, 17 Jun 2020 17:52:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46312) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jlfiN-0004dc-2E; Wed, 17 Jun 2020 17:35:23 -0400 Received: from esa1.hgst.iphmx.com ([68.232.141.245]:29885) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jlfiJ-0005JY-Cq; Wed, 17 Jun 2020 17:35:22 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1592429719; x=1623965719; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=u2r9SyxJDxOigqOynmlVPCtDA74dVEj+5oloZa8fMbA=; b=JaJezOhIcYZT3CQeTa49kKlWKC2KtuZ4gIx3CS9iTrK868j0ELx1qkWr yCApNwxlOhzahuNx0VQwCi/IN2QTWsPv6FBWmOBiGqRAjwv9WmUIv6s8J BmbuotYxV/ZMDv9nOv0w+zcZX87S5xHf8JhNQSRvEtePAoSjsrJEyb6U4 KVHnWnJV90SNZel/Pw2ygyESWtUlIl/QHh3GxUNrzp02kdFbQfEdnuji8 11Pfe3YVu03eqUPxWHdBmB6cRr5Wyg5pAzmKWsGfC16/xiNF2dxvHIFQI UFrYg98Tryo9o7zpdQJPk+XzQh1NgGVxtG31qmQXsDoKFeOu1rX4KYb5e w==; IronPort-SDR: icK2opN1UtHgyS9ECwyjX4jbWZ0Gca5coGvXHBZij5Myt6Oso/PoRDrs/fd/cTIA/lJQQ80r2u MUUm8QyvEEHVHGLM/G2vZHDH80isDd+iwue0paqj+r0Ij2X1eGOyDAQc5aCeedMiRylLNkJSRB EPUTPXVWl+KWovKOp2/CgW5fEJwinwjwOru0/71PPI8sJEQFoawUUp+fX+mxHoSITUUbKR/LmB jxQ2dWxh4bB+K5qq3pZNwkr343E6GG79wV20PSsqOKYF3qT+JZ4VbNOHftTUN2M9NQQqRgVLW5 +Ng= X-IronPort-AV: E=Sophos;i="5.73,523,1583164800"; d="scan'208";a="249439839" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 18 Jun 2020 05:34:55 +0800 IronPort-SDR: YYeeqblnZcT9oImlo9aPC9Ob/X8Awx4AHNM4LgywaZnf7UErv220NCFDjGfsTnwBhynG5WGLPi 34BP34e8sAfC46o4cL+0gVobQLPeLbph8= Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jun 2020 14:23:36 -0700 IronPort-SDR: FWlWQaUJfrVauzI7k/WkYeEqBzPlnQEeiVOwB6bDSPLC8zrUKJS3xRThjzeTFozRsboosA+W0J yJsLOtfgnYHw== WDCIronportException: Internal Received: from unknown (HELO redsun50.ssa.fujisawa.hgst.com) ([10.149.66.24]) by uls-op-cesaip02.wdc.com with ESMTP; 17 Jun 2020 14:34:54 -0700 From: Dmitry Fomichev To: Kevin Wolf , Keith Busch , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Maxim Levitsky Subject: [PATCH v2 15/18] hw/block/nvme: Support Zone Descriptor Extensions Date: Thu, 18 Jun 2020 06:34:12 +0900 Message-Id: <20200617213415.22417-16-dmitry.fomichev@wdc.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20200617213415.22417-1-dmitry.fomichev@wdc.com> References: <20200617213415.22417-1-dmitry.fomichev@wdc.com> MIME-Version: 1.0 Received-SPF: pass client-ip=68.232.141.245; envelope-from=prvs=430b82a1d=dmitry.fomichev@wdc.com; helo=esa1.hgst.iphmx.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/06/17 17:34:28 X-ACL-Warn: Detected OS = FreeBSD 9.x or newer [fuzzy] X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN 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: Niklas Cassel , Damien Le Moal , qemu-block@nongnu.org, Dmitry Fomichev , qemu-devel@nongnu.org, Matias Bjorling Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Zone Descriptor Extension is a label that can be assigned to a zone. It can be set to an Empty zone and it stays assigned until the zone is reset. This commit adds a new optional property, "zone_descr_ext_size", to the driver. Its value must be a multiple of 64 bytes. If this value is non-zero, it becomes possible to assign extensions of that size to any Empty zones. The default value for this property is 0, therefore setting extensions is disabled by default. Signed-off-by: Hans Holmberg Signed-off-by: Dmitry Fomichev --- hw/block/nvme.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++--- hw/block/nvme.h | 8 ++++++ 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index b9135a6b1f..eb41081627 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1360,6 +1360,26 @@ static bool nvme_cond_offline_all(uint8_t state) return state == NVME_ZONE_STATE_READ_ONLY; } +static uint16_t nvme_set_zd_ext(NvmeCtrl *n, NvmeNamespace *ns, + NvmeZone *zone, uint8_t state) +{ + uint16_t status; + + if (state == NVME_ZONE_STATE_EMPTY) { + nvme_auto_transition_zone(n, ns, false, true); + status = nvme_aor_check(n, ns, 1, 0); + if (status != NVME_SUCCESS) { + return status; + } + nvme_aor_inc_active(n, ns); + zone->d.za |= NVME_ZA_ZD_EXT_VALID; + nvme_assign_zone_state(n, ns, zone, NVME_ZONE_STATE_CLOSED); + return NVME_SUCCESS; + } + + return NVME_ZONE_INVAL_TRANSITION; +} + static uint16_t name_do_zone_op(NvmeCtrl *n, NvmeNamespace *ns, NvmeZone *zone, uint8_t state, bool all, uint16_t (*op_hndlr)(NvmeCtrl *, NvmeNamespace *, NvmeZone *, @@ -1388,13 +1408,16 @@ static uint16_t name_do_zone_op(NvmeCtrl *n, NvmeNamespace *ns, static uint16_t nvme_zone_mgmt_send(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd, NvmeRequest *req) { + NvmeRwCmd *rw; uint32_t dw13 = le32_to_cpu(cmd->cdw13); + uint64_t prp1, prp2; uint64_t slba = 0; uint64_t zone_idx = 0; uint16_t status; uint8_t action, state; bool all; NvmeZone *zone; + uint8_t *zd_ext; action = dw13 & 0xff; all = dw13 & 0x100; @@ -1449,7 +1472,25 @@ static uint16_t nvme_zone_mgmt_send(NvmeCtrl *n, NvmeNamespace *ns, case NVME_ZONE_ACTION_SET_ZD_EXT: trace_pci_nvme_set_descriptor_extension(slba, zone_idx); - return NVME_INVALID_FIELD | NVME_DNR; + if (all || !n->params.zd_extension_size) { + return NVME_INVALID_FIELD | NVME_DNR; + } + zd_ext = nvme_get_zd_extension(n, ns, zone_idx); + rw = (NvmeRwCmd *)cmd; + prp1 = le64_to_cpu(rw->prp1); + prp2 = le64_to_cpu(rw->prp2); + status = nvme_dma_write_prp(n, zd_ext, n->params.zd_extension_size, + prp1, prp2); + if (status) { + trace_pci_nvme_err_zd_extension_map_error(zone_idx); + return status; + } + + status = nvme_set_zd_ext(n, ns, zone, state); + if (status == NVME_SUCCESS) { + trace_pci_nvme_zd_extension_set(zone_idx); + return status; + } break; default: @@ -1528,7 +1569,7 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeNamespace *ns, return NVME_INVALID_FIELD | NVME_DNR; } - if (zra == NVME_ZONE_REPORT_EXTENDED) { + if (zra == NVME_ZONE_REPORT_EXTENDED && !n->params.zd_extension_size) { return NVME_INVALID_FIELD | NVME_DNR; } @@ -1540,6 +1581,9 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeNamespace *ns, partial = (dw13 >> 16) & 0x01; zone_entry_sz = sizeof(NvmeZoneDescr); + if (zra == NVME_ZONE_REPORT_EXTENDED) { + zone_entry_sz += n->params.zd_extension_size; + } max_zones = (len - sizeof(NvmeZoneReportHeader)) / zone_entry_sz; buf = g_malloc0(len); @@ -1571,6 +1615,14 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeNamespace *ns, z->wp = cpu_to_le64(~0ULL); } + if (zra == NVME_ZONE_REPORT_EXTENDED) { + if (zs->d.za & NVME_ZA_ZD_EXT_VALID) { + memcpy(buf_p, nvme_get_zd_extension(n, ns, zone_index), + n->params.zd_extension_size); + } + buf_p += n->params.zd_extension_size; + } + zone_index++; } @@ -2337,7 +2389,7 @@ static uint16_t nvme_handle_changed_zone_log(NvmeCtrl *n, NvmeCmd *cmd, continue; } num_aen_zones++; - if (zone->d.za) { + if (zone->d.za & ~NVME_ZA_ZD_EXT_VALID) { trace_pci_nvme_reporting_changed_zone(zone->d.zslba, zone->d.za); *zid_ptr++ = cpu_to_le64(zone->d.zslba); nids++; @@ -2936,6 +2988,7 @@ static int nvme_init_zone_meta(NvmeCtrl *n, NvmeNamespace *ns, ns->imp_open_zones = g_malloc0(sizeof(NvmeZoneList)); ns->closed_zones = g_malloc0(sizeof(NvmeZoneList)); ns->full_zones = g_malloc0(sizeof(NvmeZoneList)); + ns->zd_extensions = g_malloc0(n->params.zd_extension_size * n->num_zones); zone = ns->zone_array; nvme_init_zone_list(ns->exp_open_zones); @@ -3010,6 +3063,17 @@ static void nvme_zoned_init_ctrl(NvmeCtrl *n, Error **errp) if (n->params.max_active_zones > nz) { n->params.max_active_zones = nz; } + if (n->params.zd_extension_size) { + if (n->params.zd_extension_size & 0x3f) { + error_setg(errp, + "zone descriptor extension size must be a multiple of 64B"); + return; + } + if ((n->params.zd_extension_size >> 6) > 0xff) { + error_setg(errp, "zone descriptor extension size is too large"); + return; + } + } if (n->params.zone_async_events) { n->ae_cfg |= NVME_AEN_CFG_ZONE_DESCR_CHNGD_NOTICES; @@ -3040,7 +3104,8 @@ static int nvme_zoned_init_ns(NvmeCtrl *n, NvmeNamespace *ns, int lba_index, ns->id_ns_zoned->ozcs = n->params.cross_zone_read ? 0x01 : 0x00; ns->id_ns_zoned->lbafe[lba_index].zsze = cpu_to_le64(n->params.zone_size); - ns->id_ns_zoned->lbafe[lba_index].zdes = 0; + ns->id_ns_zoned->lbafe[lba_index].zdes = + n->params.zd_extension_size >> 6; /* Units of 64B */ if (n->params.fill_pattern == 0) { ns->id_ns.dlfeat = 0x01; @@ -3063,6 +3128,7 @@ static void nvme_zoned_clear(NvmeCtrl *n) g_free(ns->imp_open_zones); g_free(ns->closed_zones); g_free(ns->full_zones); + g_free(ns->zd_extensions); } } @@ -3396,6 +3462,8 @@ static Property nvme_props[] = { DEFINE_PROP_UINT64("zone_size", NvmeCtrl, params.zone_size, 512), DEFINE_PROP_UINT64("zone_capacity", NvmeCtrl, params.zone_capacity, 512), DEFINE_PROP_UINT32("zone_append_max_size", NvmeCtrl, params.zamds_bs, 0), + DEFINE_PROP_UINT32("zone_descr_ext_size", NvmeCtrl, + params.zd_extension_size, 0), DEFINE_PROP_INT32("max_active", NvmeCtrl, params.max_active_zones, 0), DEFINE_PROP_INT32("max_open", NvmeCtrl, params.max_open_zones, 0), DEFINE_PROP_UINT64("reset_rcmnd_delay", NvmeCtrl, params.rzr_delay_usec, 0), diff --git a/hw/block/nvme.h b/hw/block/nvme.h index e63f7736d7..4251295917 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -24,6 +24,7 @@ typedef struct NvmeParams { uint64_t zone_capacity; int32_t max_active_zones; int32_t max_open_zones; + uint32_t zd_extension_size; uint64_t rzr_delay_usec; uint64_t rrl_usec; uint64_t fzr_delay_usec; @@ -123,6 +124,7 @@ typedef struct NvmeNamespace { NvmeZoneList *imp_open_zones; NvmeZoneList *closed_zones; NvmeZoneList *full_zones; + uint8_t *zd_extensions; int32_t nr_open_zones; int32_t nr_active_zones; bool aen_pending; @@ -221,6 +223,12 @@ static inline bool nvme_wp_is_valid(NvmeZone *zone) st != NVME_ZONE_STATE_OFFLINE; } +static inline uint8_t *nvme_get_zd_extension(NvmeCtrl *n, + NvmeNamespace *ns, uint32_t zone_idx) +{ + return &ns->zd_extensions[zone_idx * n->params.zd_extension_size]; +} + /* * Initialize a zone list head. */ From patchwork Wed Jun 17 21:34:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Fomichev X-Patchwork-Id: 280144 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.5 required=3.0 tests=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 C42E3C433E0 for ; Wed, 17 Jun 2020 21:54:14 +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 7D1E821556 for ; Wed, 17 Jun 2020 21:54:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="nr3rpzfh" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7D1E821556 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:56538 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jlg0b-0005FT-IC for qemu-devel@archiver.kernel.org; Wed, 17 Jun 2020 17:54:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46416) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jlfin-0005Bp-Fd; Wed, 17 Jun 2020 17:35:50 -0400 Received: from esa1.hgst.iphmx.com ([68.232.141.245]:29879) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jlfii-0005JL-1q; Wed, 17 Jun 2020 17:35:49 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1592429743; x=1623965743; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=lJK5bNTrhZ/q8mT/SrRbuq0TWjcwYui8AmoM1EvfL/0=; b=nr3rpzfhsnYZ0l98BNIEdstQCgAolX0cpsa0DSqDdCSGoMIWEKR/EJDo B9I06SNlr6RuA46S2e34DcwO7E0tvwZIou7n1p5B/bNqbBr9VSgFh3MfC OuLC265RtmzmuZXlAdZDXmu2rrbFmMNREjSTGkoV/N3UQcFpqUUjTnlG6 DXBQu2LkfZThsJ1eu8qAb2RIZ2zzR3Olw82aOWDyr9Pwc1EUVgCt27XSI geEfGtakoejtddNRM9mh7+o0c4IxKYSBTPT9Me5Q6Vy/OCyNs9O41DCBc dnlHdPR9GCntFsSJJE2tl1Z+8EPUsDn4Qasmjy1UQ7ShF8YS9s+6/gJc/ g==; IronPort-SDR: ICzeSI3igO7c7uXxj0ei+qzfwx/qocskFoMK/bWJ/1aM7xb93rqTJJ/z1dWVqmTWb9cZGGiN10 geRezqDvK6tZc3lefS6H9iVTd/cpHVQ08MZ7XEa4EJsdcijhpkxzT0aRfRNLoGvRaH6PobrQXF p2zGhMC9A42gB/B2ouMLLIhriFtLB3cYyTwCnfxRw2jK4FACvmt64mM2qmo1yr0WdC59pZ0EzU U63RRhf6x2D4ZMN8BGBBIDiR6Jklh8kNtyM4dwvtMTkjLul8BwLszhFsQ3KfdlaIZkW14gvvdd 9L8= X-IronPort-AV: E=Sophos;i="5.73,523,1583164800"; d="scan'208";a="249439846" Received: from uls-op-cesaip02.wdc.com (HELO uls-op-cesaep02.wdc.com) ([199.255.45.15]) by ob1.hgst.iphmx.com with ESMTP; 18 Jun 2020 05:34:58 +0800 IronPort-SDR: 1PrmnDuei/RSAcR02qBLNblCIpyOfFZMTlFSJrDEqcbAGmQlDLgCpAvCTIMmK5mMrfj5LdnMoU PmGbQh3CFBhByqZvGimFLfQfSq0f87voc= Received: from uls-op-cesaip02.wdc.com ([10.248.3.37]) by uls-op-cesaep02.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jun 2020 14:23:40 -0700 IronPort-SDR: BzKf2ZP/cRb+0V/Xg6UoLNx7wcXYGqdHOLf1shZ05ncYNm/s86HB6hEXMZkGWlC9CS6GOXBf+D xh1tm4FABzZQ== WDCIronportException: Internal Received: from unknown (HELO redsun50.ssa.fujisawa.hgst.com) ([10.149.66.24]) by uls-op-cesaip02.wdc.com with ESMTP; 17 Jun 2020 14:34:57 -0700 From: Dmitry Fomichev To: Kevin Wolf , Keith Busch , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Maxim Levitsky Subject: [PATCH v2 17/18] hw/block/nvme: Use zone metadata file for persistence Date: Thu, 18 Jun 2020 06:34:14 +0900 Message-Id: <20200617213415.22417-18-dmitry.fomichev@wdc.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20200617213415.22417-1-dmitry.fomichev@wdc.com> References: <20200617213415.22417-1-dmitry.fomichev@wdc.com> MIME-Version: 1.0 Received-SPF: pass client-ip=68.232.141.245; envelope-from=prvs=430b82a1d=dmitry.fomichev@wdc.com; helo=esa1.hgst.iphmx.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/06/17 17:34:28 X-ACL-Warn: Detected OS = FreeBSD 9.x or newer [fuzzy] X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN 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: Niklas Cassel , Damien Le Moal , qemu-block@nongnu.org, Dmitry Fomichev , qemu-devel@nongnu.org, Matias Bjorling Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" A ZNS drive that is emulated by this driver is currently initialized with all zones Empty upon startup. However, actual ZNS SSDs save the state and condition of all zones in their internal NVRAM in the event of power loss. When such a drive is powered up again, it closes or finishes all zones that were open at the moment of shutdown. Besides that, the write pointer position as well as the state and condition of all zones is preserved across power-downs. This commit adds the capability to have a persistent zone metadata to the driver. The new optional driver property, "zone_file", is introduced. If added to the command line, this property specifies the name of the file that stores the zone metadata. If "zone_file" is omitted, the driver will initialize with all zones empty, the same as before. If zone metadata is configured to be persistent, then zone descriptor extensions also persist across controller shutdowns. Signed-off-by: Dmitry Fomichev --- hw/block/nvme.c | 371 +++++++++++++++++++++++++++++++++++++++++++++--- hw/block/nvme.h | 38 +++++ 2 files changed, 388 insertions(+), 21 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 14d5f1d155..63e7a6352e 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -69,6 +69,8 @@ } while (0) static void nvme_process_sq(void *opaque); +static void nvme_sync_zone_file(NvmeCtrl *n, NvmeNamespace *ns, + NvmeZone *zone, int len); /* * Add a zone to the tail of a zone list. @@ -90,6 +92,7 @@ static void nvme_add_zone_tail(NvmeCtrl *n, NvmeNamespace *ns, NvmeZoneList *zl, zl->tail = idx; } zl->size++; + nvme_set_zone_meta_dirty(n, ns, true); } /* @@ -106,12 +109,15 @@ static void nvme_remove_zone(NvmeCtrl *n, NvmeNamespace *ns, NvmeZoneList *zl, if (zl->size == 0) { zl->head = NVME_ZONE_LIST_NIL; zl->tail = NVME_ZONE_LIST_NIL; + nvme_set_zone_meta_dirty(n, ns, true); } else if (idx == zl->head) { zl->head = zone->next; ns->zone_array[zl->head].prev = NVME_ZONE_LIST_NIL; + nvme_set_zone_meta_dirty(n, ns, true); } else if (idx == zl->tail) { zl->tail = zone->prev; ns->zone_array[zl->tail].next = NVME_ZONE_LIST_NIL; + nvme_set_zone_meta_dirty(n, ns, true); } else { ns->zone_array[zone->next].prev = zone->prev; ns->zone_array[zone->prev].next = zone->next; @@ -138,6 +144,7 @@ static NvmeZone *nvme_remove_zone_head(NvmeCtrl *n, NvmeNamespace *ns, ns->zone_array[zl->head].prev = NVME_ZONE_LIST_NIL; } zone->prev = zone->next = 0; + nvme_set_zone_meta_dirty(n, ns, true); } return zone; @@ -476,6 +483,7 @@ static void nvme_assign_zone_state(NvmeCtrl *n, NvmeNamespace *ns, case NVME_ZONE_STATE_READ_ONLY: zone->tstamp = 0; } + nvme_sync_zone_file(n, ns, zone, sizeof(NvmeZone)); } static bool nvme_addr_is_cmb(NvmeCtrl *n, hwaddr addr) @@ -2976,9 +2984,114 @@ static const MemoryRegionOps nvme_cmb_ops = { }, }; -static int nvme_init_zone_meta(NvmeCtrl *n, NvmeNamespace *ns, +static int nvme_validate_zone_file(NvmeCtrl *n, NvmeNamespace *ns, uint64_t capacity) { + NvmeZoneMeta *meta = ns->zone_meta; + NvmeZone *zone = ns->zone_array; + uint64_t start = 0, zone_size = n->params.zone_size; + int i, n_imp_open = 0, n_exp_open = 0, n_closed = 0, n_full = 0; + + if (meta->magic != NVME_ZONE_META_MAGIC) { + return 1; + } + if (meta->version != NVME_ZONE_META_VER) { + return 2; + } + if (meta->zone_size != zone_size) { + return 3; + } + if (meta->zone_capacity != n->params.zone_capacity) { + return 4; + } + if (meta->nr_offline_zones != n->params.nr_offline_zones) { + return 5; + } + if (meta->nr_rdonly_zones != n->params.nr_rdonly_zones) { + return 6; + } + if (meta->lba_size != n->conf.logical_block_size) { + return 7; + } + if (meta->zd_extension_size != n->params.zd_extension_size) { + return 8; + } + + for (i = 0; i < n->num_zones; i++, zone++) { + if (start + zone_size > capacity) { + zone_size = capacity - start; + } + if (zone->d.zt != NVME_ZONE_TYPE_SEQ_WRITE) { + return 9; + } + if (zone->d.zcap != n->params.zone_capacity) { + return 10; + } + if (zone->d.zslba != start) { + return 11; + } + switch (nvme_get_zone_state(zone)) { + case NVME_ZONE_STATE_EMPTY: + case NVME_ZONE_STATE_OFFLINE: + case NVME_ZONE_STATE_READ_ONLY: + if (zone->d.wp != start) { + return 12; + } + break; + case NVME_ZONE_STATE_IMPLICITLY_OPEN: + if (zone->d.wp < start || + zone->d.wp >= zone->d.zslba + zone->d.zcap) { + return 13; + } + n_imp_open++; + break; + case NVME_ZONE_STATE_EXPLICITLY_OPEN: + if (zone->d.wp < start || + zone->d.wp >= zone->d.zslba + zone->d.zcap) { + return 13; + } + n_exp_open++; + break; + case NVME_ZONE_STATE_CLOSED: + if (zone->d.wp < start || + zone->d.wp >= zone->d.zslba + zone->d.zcap) { + return 13; + } + n_closed++; + break; + case NVME_ZONE_STATE_FULL: + if (zone->d.wp != zone->d.zslba + zone->d.zcap) { + return 14; + } + n_full++; + break; + default: + return 15; + } + + start += zone_size; + } + + if (n_imp_open != nvme_zone_list_size(ns->exp_open_zones)) { + return 16; + } + if (n_exp_open != nvme_zone_list_size(ns->imp_open_zones)) { + return 17; + } + if (n_closed != nvme_zone_list_size(ns->closed_zones)) { + return 18; + } + if (n_full != nvme_zone_list_size(ns->full_zones)) { + return 19; + } + + return 0; +} + +static int nvme_init_zone_file(NvmeCtrl *n, NvmeNamespace *ns, + uint64_t capacity) +{ + NvmeZoneMeta *meta = ns->zone_meta; NvmeZone *zone; Error *err; uint64_t start = 0, zone_size = n->params.zone_size; @@ -2986,18 +3099,33 @@ static int nvme_init_zone_meta(NvmeCtrl *n, NvmeNamespace *ns, int i; uint16_t zs; - ns->zone_array = g_malloc0(n->zone_array_size); - ns->exp_open_zones = g_malloc0(sizeof(NvmeZoneList)); - ns->imp_open_zones = g_malloc0(sizeof(NvmeZoneList)); - ns->closed_zones = g_malloc0(sizeof(NvmeZoneList)); - ns->full_zones = g_malloc0(sizeof(NvmeZoneList)); - ns->zd_extensions = g_malloc0(n->params.zd_extension_size * n->num_zones); + if (n->params.zone_file) { + meta->magic = NVME_ZONE_META_MAGIC; + meta->version = NVME_ZONE_META_VER; + meta->zone_size = zone_size; + meta->zone_capacity = n->params.zone_capacity; + meta->lba_size = n->conf.logical_block_size; + meta->nr_offline_zones = n->params.nr_offline_zones; + meta->nr_rdonly_zones = n->params.nr_rdonly_zones; + meta->zd_extension_size = n->params.zd_extension_size; + } else { + ns->zone_array = g_malloc0(n->zone_array_size); + ns->exp_open_zones = g_malloc0(sizeof(NvmeZoneList)); + ns->imp_open_zones = g_malloc0(sizeof(NvmeZoneList)); + ns->closed_zones = g_malloc0(sizeof(NvmeZoneList)); + ns->full_zones = g_malloc0(sizeof(NvmeZoneList)); + ns->zd_extensions = + g_malloc0(n->params.zd_extension_size * n->num_zones); + } zone = ns->zone_array; nvme_init_zone_list(ns->exp_open_zones); nvme_init_zone_list(ns->imp_open_zones); nvme_init_zone_list(ns->closed_zones); nvme_init_zone_list(ns->full_zones); + if (n->params.zone_file) { + nvme_set_zone_meta_dirty(n, ns, true); + } for (i = 0; i < n->num_zones; i++, zone++) { if (start + zone_size > capacity) { @@ -3048,7 +3176,189 @@ static int nvme_init_zone_meta(NvmeCtrl *n, NvmeNamespace *ns, return 0; } -static void nvme_zoned_init_ctrl(NvmeCtrl *n, Error **errp) +static int nvme_open_zone_file(NvmeCtrl *n, bool *init_meta) +{ + struct stat statbuf; + size_t fsize; + int ret; + + ret = stat(n->params.zone_file, &statbuf); + if (ret && errno == ENOENT) { + *init_meta = true; + } else if (!S_ISREG(statbuf.st_mode)) { + fprintf(stderr, "%s is not a regular file\n", strerror(errno)); + return -1; + } + + n->zone_file_fd = open(n->params.zone_file, + O_RDWR | O_LARGEFILE | O_BINARY | O_CREAT, 644); + if (n->zone_file_fd < 0) { + fprintf(stderr, "failed to create zone file %s, err %s\n", + n->params.zone_file, strerror(errno)); + return -1; + } + + fsize = n->meta_size * n->num_namespaces; + + if (stat(n->params.zone_file, &statbuf)) { + fprintf(stderr, "can't stat zone file %s, err %s\n", + n->params.zone_file, strerror(errno)); + return -1; + } + if (statbuf.st_size != fsize) { + ret = ftruncate(n->zone_file_fd, fsize); + if (ret < 0) { + fprintf(stderr, "can't truncate zone file %s, err %s\n", + n->params.zone_file, strerror(errno)); + return -1; + } + *init_meta = true; + } + + return 0; +} + +static int nvme_map_zone_file(NvmeCtrl *n, NvmeNamespace *ns, bool *init_meta) +{ + off_t meta_ofs = n->meta_size * (ns->nsid - 1); + + ns->zone_meta = mmap(0, n->meta_size, PROT_READ | PROT_WRITE, + MAP_SHARED, n->zone_file_fd, meta_ofs); + if (ns->zone_meta == MAP_FAILED) { + fprintf(stderr, "failed to map zone file %s, ofs %lu, err %s\n", + n->params.zone_file, meta_ofs, strerror(errno)); + return -1; + } + + ns->zone_array = (NvmeZone *)(ns->zone_meta + 1); + ns->exp_open_zones = &ns->zone_meta->exp_open_zones; + ns->imp_open_zones = &ns->zone_meta->imp_open_zones; + ns->closed_zones = &ns->zone_meta->closed_zones; + ns->full_zones = &ns->zone_meta->full_zones; + + if (n->params.zd_extension_size) { + ns->zd_extensions = (uint8_t *)(ns->zone_meta + 1); + ns->zd_extensions += n->zone_array_size; + } + + return 0; +} + +static void nvme_sync_zone_file(NvmeCtrl *n, NvmeNamespace *ns, + NvmeZone *zone, int len) +{ + uintptr_t addr, zd = (uintptr_t)zone; + + addr = zd & qemu_real_host_page_mask; + len += zd - addr; + if (msync((void *)addr, len, MS_ASYNC) < 0) + fprintf(stderr, "msync: failed to sync zone descriptors, file %s\n", + strerror(errno)); + + if (nvme_zone_meta_dirty(n, ns)) { + nvme_set_zone_meta_dirty(n, ns, false); + if (msync(ns->zone_meta, sizeof(NvmeZoneMeta), MS_ASYNC) < 0) + fprintf(stderr, "msync: failed to sync zone meta, file %s\n", + strerror(errno)); + } +} + +/* + * Close or finish all the zones that might be still open after power-down. + */ +static void nvme_prepare_zones(NvmeCtrl *n, NvmeNamespace *ns) +{ + NvmeZone *zone; + uint32_t set_state; + int i; + + assert(!ns->nr_active_zones); + assert(!ns->nr_open_zones); + + zone = ns->zone_array; + for (i = 0; i < n->num_zones; i++, zone++) { + zone->flags = 0; + zone->tstamp = 0; + + switch (nvme_get_zone_state(zone)) { + case NVME_ZONE_STATE_IMPLICITLY_OPEN: + case NVME_ZONE_STATE_EXPLICITLY_OPEN: + break; + case NVME_ZONE_STATE_CLOSED: + nvme_aor_inc_active(n, ns); + /* pass through */ + default: + continue; + } + + if (zone->d.za & NVME_ZA_ZD_EXT_VALID) { + set_state = NVME_ZONE_STATE_CLOSED; + } else if (zone->d.wp == zone->d.zslba) { + set_state = NVME_ZONE_STATE_EMPTY; + } else if (n->params.max_active_zones == 0 || + ns->nr_active_zones < n->params.max_active_zones) { + set_state = NVME_ZONE_STATE_CLOSED; + } else { + set_state = NVME_ZONE_STATE_FULL; + } + + switch (set_state) { + case NVME_ZONE_STATE_CLOSED: + trace_pci_nvme_power_on_close(nvme_get_zone_state(zone), + zone->d.zslba); + nvme_aor_inc_active(n, ns); + nvme_add_zone_tail(n, ns, ns->closed_zones, zone); + break; + case NVME_ZONE_STATE_EMPTY: + trace_pci_nvme_power_on_reset(nvme_get_zone_state(zone), + zone->d.zslba); + break; + case NVME_ZONE_STATE_FULL: + trace_pci_nvme_power_on_full(nvme_get_zone_state(zone), + zone->d.zslba); + zone->d.wp = nvme_zone_wr_boundary(zone); + } + + nvme_set_zone_state(zone, set_state); + } +} + +static int nvme_load_zone_meta(NvmeCtrl *n, NvmeNamespace *ns, + uint64_t capacity, bool init_meta) +{ + int ret = 0; + + if (n->params.zone_file) { + ret = nvme_map_zone_file(n, ns, &init_meta); + trace_pci_nvme_mapped_zone_file(n->params.zone_file, ret); + if (ret < 0) { + return ret; + } + + if (!init_meta) { + ret = nvme_validate_zone_file(n, ns, capacity); + if (ret) { + trace_pci_nvme_err_zone_file_invalid(ret); + init_meta = true; + } + } + } else { + init_meta = true; + } + + if (init_meta) { + ret = nvme_init_zone_file(n, ns, capacity); + } else { + nvme_prepare_zones(n, ns); + } + if (!ret && n->params.zone_file) { + nvme_sync_zone_file(n, ns, ns->zone_array, n->zone_array_size); + } + + return ret; +} + +static void nvme_zoned_init_ctrl(NvmeCtrl *n, bool *init_meta, Error **errp) { uint64_t zone_size = 0, capacity; uint32_t nz; @@ -3084,6 +3394,9 @@ static void nvme_zoned_init_ctrl(NvmeCtrl *n, Error **errp) nz = DIV_ROUND_UP(capacity, zone_size); n->num_zones = nz; n->zone_array_size = sizeof(NvmeZone) * nz; + n->meta_size = sizeof(NvmeZoneMeta) + n->zone_array_size + + nz * n->params.zd_extension_size; + n->meta_size = ROUND_UP(n->meta_size, qemu_real_host_page_size); n->params.rzr_delay_usec *= SCALE_MS; n->params.rrl_usec *= SCALE_MS; @@ -3119,6 +3432,13 @@ static void nvme_zoned_init_ctrl(NvmeCtrl *n, Error **errp) } } + if (n->params.zone_file) { + if (nvme_open_zone_file(n, init_meta) < 0) { + error_setg(errp, "cannot open zone metadata file"); + return; + } + } + if (n->params.zone_async_events) { n->ae_cfg |= NVME_AEN_CFG_ZONE_DESCR_CHNGD_NOTICES; } @@ -3127,13 +3447,14 @@ static void nvme_zoned_init_ctrl(NvmeCtrl *n, Error **errp) } static int nvme_zoned_init_ns(NvmeCtrl *n, NvmeNamespace *ns, int lba_index, - Error **errp) + bool init_meta, Error **errp) { int ret; - ret = nvme_init_zone_meta(n, ns, n->num_zones * n->params.zone_size); + ret = nvme_load_zone_meta(n, ns, n->num_zones * n->params.zone_size, + init_meta); if (ret) { - error_setg(errp, "could not init zone metadata"); + error_setg(errp, "could not load/init zone metadata"); return -1; } @@ -3164,15 +3485,20 @@ static void nvme_zoned_clear(NvmeCtrl *n) { int i; + if (n->params.zone_file) { + close(n->zone_file_fd); + } for (i = 0; i < n->num_namespaces; i++) { NvmeNamespace *ns = &n->namespaces[i]; g_free(ns->id_ns_zoned); - g_free(ns->zone_array); - g_free(ns->exp_open_zones); - g_free(ns->imp_open_zones); - g_free(ns->closed_zones); - g_free(ns->full_zones); - g_free(ns->zd_extensions); + if (!n->params.zone_file) { + g_free(ns->zone_array); + g_free(ns->exp_open_zones); + g_free(ns->imp_open_zones); + g_free(ns->closed_zones); + g_free(ns->full_zones); + g_free(ns->zd_extensions); + } } } @@ -3258,7 +3584,8 @@ static void nvme_init_blk(NvmeCtrl *n, Error **errp) n->ns_size = bs_size; } -static void nvme_init_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) +static void nvme_init_namespace(NvmeCtrl *n, NvmeNamespace *ns, bool init_meta, + Error **errp) { NvmeIdNs *id_ns = &ns->id_ns; int lba_index; @@ -3272,7 +3599,7 @@ static void nvme_init_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) if (n->params.zoned) { ns->csi = NVME_CSI_ZONED; id_ns->ncap = cpu_to_le64(n->params.zone_capacity * n->num_zones); - if (nvme_zoned_init_ns(n, ns, lba_index, errp) != 0) { + if (nvme_zoned_init_ns(n, ns, lba_index, init_meta, errp) != 0) { return; } } else { @@ -3429,6 +3756,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) NvmeCtrl *n = NVME(pci_dev); NvmeNamespace *ns; Error *local_err = NULL; + bool init_meta = false; int i; @@ -3452,7 +3780,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) } if (n->params.zoned) { - nvme_zoned_init_ctrl(n, &local_err); + nvme_zoned_init_ctrl(n, &init_meta, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -3463,7 +3791,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) ns = n->namespaces; for (i = 0; i < n->num_namespaces; i++, ns++) { ns->nsid = i + 1; - nvme_init_namespace(n, ns, &local_err); + nvme_init_namespace(n, ns, init_meta, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -3506,6 +3834,7 @@ static Property nvme_props[] = { DEFINE_PROP_UINT64("zone_size", NvmeCtrl, params.zone_size, 512), DEFINE_PROP_UINT64("zone_capacity", NvmeCtrl, params.zone_capacity, 512), DEFINE_PROP_UINT32("zone_append_max_size", NvmeCtrl, params.zamds_bs, 0), + DEFINE_PROP_STRING("zone_file", NvmeCtrl, params.zone_file), DEFINE_PROP_UINT32("zone_descr_ext_size", NvmeCtrl, params.zd_extension_size, 0), DEFINE_PROP_INT32("max_active", NvmeCtrl, params.max_active_zones, 0), diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 900fc54809..5e9a3a62f7 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -14,6 +14,7 @@ typedef struct NvmeParams { uint16_t msix_qsize; uint32_t cmb_size_mb; + char *zone_file; bool zoned; bool cross_zone_read; bool zone_async_events; @@ -114,6 +115,27 @@ typedef struct NvmeZoneList { uint8_t rsvd12[4]; } NvmeZoneList; +#define NVME_ZONE_META_MAGIC 0x3aebaa70 +#define NVME_ZONE_META_VER 1 + +typedef struct NvmeZoneMeta { + uint32_t magic; + uint32_t version; + uint64_t zone_size; + uint64_t zone_capacity; + uint32_t nr_offline_zones; + uint32_t nr_rdonly_zones; + uint32_t lba_size; + uint32_t rsvd40; + NvmeZoneList exp_open_zones; + NvmeZoneList imp_open_zones; + NvmeZoneList closed_zones; + NvmeZoneList full_zones; + uint8_t zd_extension_size; + uint8_t dirty; + uint8_t rsvd594[3990]; +} NvmeZoneMeta; + typedef struct NvmeNamespace { NvmeIdNs id_ns; uint32_t nsid; @@ -122,6 +144,7 @@ typedef struct NvmeNamespace { NvmeIdNsZoned *id_ns_zoned; NvmeZone *zone_array; + NvmeZoneMeta *zone_meta; NvmeZoneList *exp_open_zones; NvmeZoneList *imp_open_zones; NvmeZoneList *closed_zones; @@ -174,6 +197,7 @@ typedef struct NvmeCtrl { int zone_file_fd; uint32_t num_zones; + size_t meta_size; uint64_t zone_size_bs; uint64_t zone_array_size; uint8_t zamds; @@ -282,6 +306,19 @@ static inline NvmeZone *nvme_next_zone_in_list(NvmeNamespace *ns, NvmeZone *z, return &ns->zone_array[z->next]; } +static inline bool nvme_zone_meta_dirty(NvmeCtrl *n, NvmeNamespace *ns) +{ + return n->params.zone_file ? ns->zone_meta->dirty : false; +} + +static inline void nvme_set_zone_meta_dirty(NvmeCtrl *n, NvmeNamespace *ns, + bool yesno) +{ + if (n->params.zone_file) { + ns->zone_meta->dirty = yesno; + } +} + static inline int nvme_ilog2(uint64_t i) { int log = -1; @@ -295,6 +332,7 @@ static inline int nvme_ilog2(uint64_t i) static inline void _hw_nvme_check_size(void) { + QEMU_BUILD_BUG_ON(sizeof(NvmeZoneMeta) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeZoneList) != 16); QEMU_BUILD_BUG_ON(sizeof(NvmeZone) != 88); }