From nobody Sun May 19 10:01:27 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1562094042; cv=none; d=zoho.com; s=zohoarc; b=hQkEmDa8QMFe6MQONg7kYjx2d6vOjajel7DaSszAtZ5TK8iWAM4rxSH9UMR6rqgibHPg1tOtlEt7UZL5NV5bUtwFTdMPCsumF2VLsUwHkjX71+clbkMEZrppG2CBjN44a69SUpsbEPG2mUNv0oipvhuwyhA0q1WSokvxzbm6L0Y= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562094042; h=Content-Type:Content-Transfer-Encoding:Date:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:To:ARC-Authentication-Results; bh=C/AQ7mJlOuHFzMCRRLCkaOlDinRa2Ver9nxAqBoSfPk=; b=a8ydvwxwFGOycVJYy9c02so4sHTsBiVsc1P4MQ8BKXYsUmIE6tt0yB+oDWzz4q44kvLwyNyHhyreYicbsmBjpFQ2mElX5bF4NSYzhjWMsE/Qn7umQeMeuZLP3Fff5mTNSMlMJpbik5SodBJPHimimcYsRHFq5W6jfZWvTHPC6HE= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1562094042781815.6381632852588; Tue, 2 Jul 2019 12:00:42 -0700 (PDT) Received: from localhost ([::1]:56340 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hiO14-0004P5-2l for importer@patchew.org; Tue, 02 Jul 2019 15:00:34 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40105) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hiMlj-0006Z0-2C for qemu-devel@nongnu.org; Tue, 02 Jul 2019 13:40:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hiMle-0004hL-KT for qemu-devel@nongnu.org; Tue, 02 Jul 2019 13:40:38 -0400 Received: from p3plmtsmtp01.prod.phx3.secureserver.net ([184.168.131.12]:37338) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hiMle-0004SQ-7f for qemu-devel@nongnu.org; Tue, 02 Jul 2019 13:40:34 -0400 Received: from n06.mail01.mtsvc.net ([216.70.64.26]) by :MT-SMTP: with ESMTP id iMknhLHnJywc7iMknh6z0s; Tue, 02 Jul 2019 10:39:41 -0700 Received: from 76-14-151-140.rk.wavecable.com ([76.14.151.140]:59125 helo=[10.10.0.62]) by n06.mail01.mtsvc.net with esmtpsa (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.92) (envelope-from ) id 1hiMkj-000CHD-9x; Tue, 02 Jul 2019 13:39:41 -0400 X-SID: iMknhLHnJywc7 From: Matt Fitzpatrick To: keith.busch@intel.com, kwolf@redhat.com, mreitz@redhat.com, qemu-block@nongnu.org, qemu-devel@nongnu.org Message-ID: <8115eb18-38c0-2bd9-b7d7-2d0c96a106e7@oakgatetech.com> Date: Tue, 2 Jul 2019 10:39:36 -0700 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8"; format="flowed" Content-Transfer-Encoding: quoted-printable Content-Language: en-US X-Authenticated-User: 1274755 matt.fitzpatrick@oakgatetech.com X-MT-ID: 4030CEC58F673A93EB94C0FECA0E49165788AD9E X-CMAE-Envelope: MS4wfLNmkmzEVozXPSlTFbm3zpHx4BXjMVW1u7Ncu31BS4njNRAqk0vrVF3XtDTtewnAq7xYzsRwKCnZs3LxF1Ajuv1k4MOyGGy8dMi6m0Eyl+qZdT2KxV8l 9SE7Ov1pjWc4w+zcj2EskGd0bjfhh9GBczQ0EUPj7ouubjJ7JLduv6HJZ3zoqwiAe5b8wbGIY0cZozi2YFgdSHSg+dLgifFxhrLn2FSSbVQ0AfkONqAk1OD7 9mE+xKrcy9b92sBR11c2obPkTBaE+7jMBVPMIp9KBGXAIZhnLYpDNt3egvBiN7q8zTy/DgKwi68G4YJ/ript1w== X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 184.168.131.12 X-Mailman-Approved-At: Tue, 02 Jul 2019 14:11:03 -0400 Subject: [Qemu-devel] [RFC,v1] Namespace Management Support 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: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Adding namespace management support to the nvme device. Namespace=20 creation requires contiguous block space for a simple method of allocation. I wrote this a few years ago based on Keith's fork and nvmeqemu fork and=20 have recently re-synced with the latest trunk.=C2=A0 Some data structures i= n=20 nvme.h are a bit more filled out that strictly necessary as this is also=20 the base for sr-iov and IOD patched to be submitted later. Signed-off-by: fitzpat --- =C2=A0hw/block/nvme.c=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 | 506 ++++++++++++++++= +++++++++++++++++++++------ =C2=A0hw/block/nvme.h=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0 57 ++++- =C2=A0include/block/nvme.h | 128 ++++++++++- =C2=A03 files changed, 610 insertions(+), 81 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 107a719b95..11d7da26f3 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -42,6 +44,9 @@ =C2=A0#include "trace.h" =C2=A0#include "nvme.h" +#define NVME_CTRL_LIST_MAX_ENTRIES=C2=A0 2047 +#define NVME_MAX_NUM_NAMESPACES=C2=A0=C2=A0=C2=A0=C2=A0 256 + =C2=A0#define NVME_GUEST_ERR(trace, fmt, ...) \ =C2=A0=C2=A0=C2=A0=C2=A0 do { \ =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (trace_##trace)(__VA_ARGS= __); \ @@ -50,6 +55,8 @@ =C2=A0=C2=A0=C2=A0=C2=A0 } while (0) =C2=A0static void nvme_process_sq(void *opaque); +static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, +=C2=A0=C2=A0=C2=A0 unsigned size); =C2=A0static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int = size) =C2=A0{ @@ -377,7 +384,7 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace=20 *ns, NvmeCmd *cmd, =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t lba_index=C2=A0 =3D NVME_ID_NS_FLBAS_INDE= X(ns->id_ns.flbas); =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t data_shift =3D ns->id_ns.lbaf[lba_index].= ds; =C2=A0=C2=A0=C2=A0=C2=A0 uint64_t data_size =3D (uint64_t)nlb << data_shif= t; -=C2=A0=C2=A0=C2=A0 uint64_t data_offset =3D slba << data_shift; +=C2=A0=C2=A0=C2=A0 uint64_t data_offset =3D (slba << data_shift) + ns->sta= rt_byte_index; =C2=A0=C2=A0=C2=A0=C2=A0 int is_write =3D rw->opcode =3D=3D NVME_CMD_WRITE= ? 1 : 0; =C2=A0=C2=A0=C2=A0=C2=A0 enum BlockAcctType acct =3D is_write ? BLOCK_ACCT= _WRITE :=20 BLOCK_ACCT_READ; @@ -425,6 +432,11 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd=20 *cmd, NvmeRequest *req) =C2=A0=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 ns =3D &n->namespaces[nsid - 1]; + +=C2=A0=C2=A0=C2=A0 if (unlikely(!ns->ctrl)) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_INVALID_NSID | NVME= _DNR; +=C2=A0=C2=A0=C2=A0 } + =C2=A0=C2=A0=C2=A0=C2=A0 switch (cmd->opcode) { =C2=A0=C2=A0=C2=A0=C2=A0 case NVME_CMD_FLUSH: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return nvme_flush(n, ns, = cmd, req); @@ -676,6 +688,49 @@ static uint16_t nvme_identify_ns(NvmeCtrl *n,=20 NvmeIdentify *c) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 prp1, prp2); =C2=A0} +/** + * Identify Allocated Namespace List + * @param n + * @param c + * @return + */ +static uint16_t nvme_identify_ns_allocated(NvmeCtrl *n, NvmeIdentify *c) +{ +=C2=A0=C2=A0=C2=A0 static const int data_len =3D 4 * KiB; +=C2=A0=C2=A0=C2=A0 uint32_t min_nsid =3D le32_to_cpu(c->nsid); +=C2=A0=C2=A0=C2=A0 uint64_t prp1 =3D le64_to_cpu(c->prp1); +=C2=A0=C2=A0=C2=A0 uint64_t prp2 =3D le64_to_cpu(c->prp2); +=C2=A0=C2=A0=C2=A0 uint32_t *list; +=C2=A0=C2=A0=C2=A0 uint16_t ret; +=C2=A0=C2=A0=C2=A0 int i, j =3D 0; + +=C2=A0=C2=A0=C2=A0 trace_nvme_identify_nslist(min_nsid); + +=C2=A0=C2=A0=C2=A0 list =3D g_malloc0(data_len); +=C2=A0=C2=A0=C2=A0 for (i =3D 0; i < NVME_MAX_NUM_NAMESPACES; i++) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (i < min_nsid) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 continu= e; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (n->namespaces[i].created) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 list[j+= +] =3D cpu_to_le32(i + 1); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (j = =3D=3D data_len / sizeof(uint32_t)) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 break; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 ret =3D nvme_dma_read_prp(n, (uint8_t *)list, data_len,= prp1, prp2); +=C2=A0=C2=A0=C2=A0 g_free(list); +=C2=A0=C2=A0=C2=A0 return ret; +} + +/** + * Identify Active Namespace List + * Active is defined as created and attached. + * + * @param n + * @param c + * @return + */ =C2=A0static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c) =C2=A0{ =C2=A0=C2=A0=C2=A0=C2=A0 static const int data_len =3D 4 * KiB; @@ -689,13 +744,15 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n,=20 NvmeIdentify *c) =C2=A0=C2=A0=C2=A0=C2=A0 trace_nvme_identify_nslist(min_nsid); =C2=A0=C2=A0=C2=A0=C2=A0 list =3D g_malloc0(data_len); -=C2=A0=C2=A0=C2=A0 for (i =3D 0; i < n->num_namespaces; i++) { +=C2=A0=C2=A0=C2=A0 for (i =3D 0; i < NVME_MAX_NUM_NAMESPACES; i++) { =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (i < min_nsid) { =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 c= ontinue; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 list[j++] =3D cpu_to_le32(i + 1= ); -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (j =3D=3D data_len / sizeof(= uint32_t)) { -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 break; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (n->namespaces[i].created &&= n->namespaces[i].ctrl) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 list[j+= +] =3D cpu_to_le32(i + 1); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (j = =3D=3D data_len / sizeof(uint32_t)) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 break; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 ret =3D nvme_dma_read_prp(n, (uint8_t *)list, dat= a_len, prp1, prp2); @@ -708,18 +765,271 @@ static uint16_t nvme_identify(NvmeCtrl *n,=20 NvmeCmd *cmd) =C2=A0=C2=A0=C2=A0=C2=A0 NvmeIdentify *c =3D (NvmeIdentify *)cmd; =C2=A0=C2=A0=C2=A0=C2=A0 switch (le32_to_cpu(c->cns)) { -=C2=A0=C2=A0=C2=A0 case 0x00: +=C2=A0=C2=A0=C2=A0 case NVME_ADM_CNS_ID_NS: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return nvme_identify_ns(n= , c); -=C2=A0=C2=A0=C2=A0 case 0x01: +=C2=A0=C2=A0=C2=A0 case NVME_ADM_CNS_ID_CTRL: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return nvme_identify_ctrl= (n, c); -=C2=A0=C2=A0=C2=A0 case 0x02: +=C2=A0=C2=A0=C2=A0 case NVME_ADM_CNS_ID_NS_LIST: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return nvme_identify_nsli= st(n, c); +=C2=A0=C2=A0=C2=A0 case NVME_ADM_CNS_ID_NS_LIST_ALLOC: +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return nvme_identify_ns_allocat= ed(n, c); +=C2=A0=C2=A0=C2=A0 case NVME_ADM_CNS_ID_NS_ALLOC: +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return nvme_identify_ns(n, c); =C2=A0=C2=A0=C2=A0=C2=A0 default: trace_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns)); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_INVALID_FIELD= | NVME_DNR; =C2=A0=C2=A0=C2=A0=C2=A0 } =C2=A0} +static uint16_t nvme_namespace_controller_attach(NvmeCtrl *n, NvmeCmd *cmd) +{ +=C2=A0=C2=A0=C2=A0 int i; +=C2=A0=C2=A0=C2=A0 uint64_t prp1 =3D le64_to_cpu(cmd->prp1); +=C2=A0=C2=A0=C2=A0 uint64_t prp2 =3D le64_to_cpu(cmd->prp2); +=C2=A0=C2=A0=C2=A0 NvmeNamespace *ns =3D &n->namespaces[cmd->nsid - 1]; + +=C2=A0=C2=A0=C2=A0 uint16_t ctrl_list[2048]; +=C2=A0=C2=A0=C2=A0 uint16_t ctrl_list_size; + +=C2=A0=C2=A0=C2=A0 if (nvme_dma_write_prp(n, (uint8_t *)ctrl_list, sizeof(= ctrl_list),=20 prp1, prp2)) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_INVALID_FIELD; +=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 ctrl_list_size =3D ctrl_list[0]; + +=C2=A0=C2=A0=C2=A0 if (!ctrl_list_size || ctrl_list_size > NVME_CTRL_LIST_= MAX_ENTRIES) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_CTRL_LIST_INVALID; +=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 if (ns->ctrl =3D=3D n) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_NS_ALREADY_ATTACHED; +=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 if (!ns->created) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_INVALID_NSID; +=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 /*=C2=A0 TODO: Update NvmeNamespace to link multiple co= ntrollers */ +=C2=A0=C2=A0=C2=A0 for ( i =3D 1; i <=3D ctrl_list_size; i++) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (n->id_ctrl.cntlid =3D=3D ct= rl_list[i]) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ns->ctr= l =3D n; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return = NVME_SUCCESS; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 return NVME_CTRL_LIST_INVALID; +} + +static uint16_t nvme_namespace_controller_detach(NvmeCtrl *n, NvmeCmd *cmd) +{ +=C2=A0=C2=A0=C2=A0 int i; +=C2=A0=C2=A0=C2=A0 uint64_t prp1 =3D le64_to_cpu(cmd->prp1); +=C2=A0=C2=A0=C2=A0 uint64_t prp2 =3D le64_to_cpu(cmd->prp2); +=C2=A0=C2=A0=C2=A0 NvmeNamespace *ns =3D &n->namespaces[cmd->nsid - 1]; + +=C2=A0=C2=A0=C2=A0 uint16_t ctrl_list[2048]; +=C2=A0=C2=A0=C2=A0 uint16_t ctrl_list_size; + +=C2=A0=C2=A0=C2=A0 if (nvme_dma_write_prp(n, (uint8_t *)ctrl_list, sizeof(= ctrl_list),=20 prp1, prp2)) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_INVALID_FIELD; +=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 ctrl_list_size =3D ctrl_list[0]; + +=C2=A0=C2=A0=C2=A0 if (!ctrl_list_size || ctrl_list_size > NVME_CTRL_LIST_= MAX_ENTRIES) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_CTRL_LIST_INVALID; +=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 /* TODO: semaphore to lock NS on detach for scenario wi= th detach=20 during IO */ +=C2=A0=C2=A0=C2=A0 if (!ns->ctrl || (ns->ctrl !=3D n) ) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_NS_NOT_ATTACHED; +=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 if (!ns->created) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_INVALID_NSID; +=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 /*=C2=A0 TODO: Update NvmeNamespace to link multiple co= ntrollers */ +=C2=A0=C2=A0=C2=A0 for ( i =3D 1; i <=3D ctrl_list_size; i++) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (n->id_ctrl.cntlid =3D=3D ct= rl_list[i]) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ns->ctr= l =3D NULL; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return = NVME_SUCCESS; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 return NVME_CTRL_LIST_INVALID; +} + +static uint16_t nvme_namespace_attachment(NvmeCtrl *n, NvmeCmd *cmd) +{ +=C2=A0=C2=A0=C2=A0 uint32_t dw10 =3D le32_to_cpu(cmd->cdw10); + +=C2=A0=C2=A0=C2=A0 if ( (!cmd->nsid || cmd->nsid > NVME_MAX_NUM_NAMESPACES) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 && (cmd= ->nsid !=3D 0xFFFFFFFF)) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_INVALID_FIELD; +=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 switch (dw10) { +=C2=A0=C2=A0=C2=A0 case NVME_NS_CONTROLLER_ATTACH: +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return nvme_namespace_controlle= r_attach(n, cmd); +=C2=A0=C2=A0=C2=A0 case NVME_NS_CONTROLLER_DETACH: +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return nvme_namespace_controlle= r_detach(n, cmd); +=C2=A0=C2=A0=C2=A0 default: +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_INVALID_FIELD | NVM= E_DNR; +=C2=A0=C2=A0=C2=A0 } +} + +static int nvme_set_start_index(NvmeCtrl *n, uint64_t *ns_start_index,=20 uint64_t requested_ns_size) +{ +=C2=A0=C2=A0=C2=A0 int i; +=C2=A0=C2=A0=C2=A0 int lba_index; +=C2=A0=C2=A0=C2=A0 uint64_t start_index =3D 0; +=C2=A0=C2=A0=C2=A0 uint64_t end_index, ns_bytes; +=C2=A0=C2=A0=C2=A0 bool adjusted; + +=C2=A0=C2=A0=C2=A0 if (requested_ns_size > n->nvm_capacity) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return -1; +=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 do { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 adjusted =3D false; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 end_index =3D start_index + req= uested_ns_size; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (end_index > n->nvm_capacity= ) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return = -1; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 for (i =3D 0; i < NVME_MAX_NUM_= NAMESPACES; i++) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 NvmeNam= espace *ns =3D &n->namespaces[i]; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 NvmeIdN= s *id_ns =3D &ns->id_ns; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (ns-= >created) { + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 lba_index =3D NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 ns_bytes =3D id_ns->nsze * ((1 <<=20 id_ns->lbaf[lba_index].ds)); + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 if ((start_index >=3D ns->start_byte_index && +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 start_index < = (ns->start_byte_index + ns_bytes)) || +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (end_index >= =3D ns->start_byte_index && +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 end_inde= x < (ns->start_byte_index + ns_bytes))) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 start_index =3D ns->start_byte_index += ns_bytes; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 adjusted =3D true; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 } while (adjusted); + +=C2=A0=C2=A0=C2=A0 *ns_start_index =3D start_index; +=C2=A0=C2=A0=C2=A0 return 0; +} + +/** + * Attempts to create a namespace in a free contiguous space within the=20 block layer + * + * @param n + * @param cmd + * @param req + * @return NVME_SUCCESS is successfuly created + */ +static uint16_t nvme_namespace_create(NvmeCtrl *n, NvmeCmd *cmd,=20 NvmeRequest *req) +{ +=C2=A0=C2=A0=C2=A0 int i; +=C2=A0=C2=A0=C2=A0 uint64_t prp1 =3D le64_to_cpu(cmd->prp1); +=C2=A0=C2=A0=C2=A0 uint64_t prp2 =3D le64_to_cpu(cmd->prp2); +=C2=A0=C2=A0=C2=A0 NvmeIdNs id_ns_host; + + +=C2=A0=C2=A0=C2=A0 if (nvme_dma_write_prp(n, (uint8_t*)&id_ns_host,=20 sizeof(id_ns_host), prp1, prp2)) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return = NVME_INVALID_FIELD; +=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 for (i =3D 0; i < NVME_MAX_NUM_NAMESPACES; i++) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 uint64_t ns_size; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int lba_index; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 NvmeNamespace *ns =3D &n->names= paces[i]; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 NvmeIdNs *id_ns =3D &ns->id_ns; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (id_ns_host.flbas || id_ns_h= ost.mc || id_ns_host.dps) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return = NVME_INVALID_FIELD | NVME_DNR; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (!ns->created) { /* take the= first available NS */ + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->= flbas =3D id_ns_host.flbas; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->= mc =3D id_ns_host.mc; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->= dps =3D id_ns_host.dps; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->= nuse =3D id_ns_host.nsze; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->= ncap =3D id_ns_host.ncap; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->= nsze =3D id_ns_host.nsze; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 lba_ind= ex =3D NVME_ID_NS_FLBAS_INDEX(id_ns->flbas); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->= lbaf[lba_index].ds =3D BDRV_SECTOR_BITS; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ns_size= =3D id_ns->nsze * (1 << id_ns->lbaf[lba_index].ds); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->= nvmcap =3D ns_size; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ns->id = =3D i + 1; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->= nguid =3D ns->id; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (nvm= e_set_start_index(n, &ns->start_byte_index, ns_size)) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 return NVME_NS_INSUFF_CAP; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ns->cre= ated =3D true; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n->id_c= trl.unvmcap -=3D id_ns->nvmcap; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ns->ctr= l =3D NULL; /* not attached */ + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n->num_= namespaces++; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n->id_c= trl.nn++; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 req->cq= e.result =3D ns->id; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return = NVME_SUCCESS; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 return NVME_NS_INSUFF_CAP; +} + +static uint16_t nvme_namespace_delete(NvmeCtrl *n, NvmeCmd *cmd,=20 NvmeRequest *req) +{ +=C2=A0=C2=A0=C2=A0 NvmeNamespace *ns =3D &n->namespaces[cmd->nsid - 1]; +=C2=A0=C2=A0=C2=A0 if (ns->created) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ns->created =3D false; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ns->ctrl =3D NULL; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n->num_namespaces--; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n->id_ctrl.nn--; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n->id_ctrl.unvmcap +=3D ns->id_= ns.nvmcap; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_SUCCESS; +=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 return NVME_INVALID_NSID; +} + +static uint16_t nvme_namespace_management(NvmeCtrl *n, NvmeCmd *cmd,=20 NvmeRequest *req) +{ +=C2=A0=C2=A0=C2=A0 uint32_t dw10 =3D le32_to_cpu(cmd->cdw10); + +=C2=A0=C2=A0=C2=A0 if ( (cmd->nsid > NVME_MAX_NUM_NAMESPACES) +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 && (cmd= ->nsid !=3D 0xFFFFFFFF)) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_INVALID_FIELD; +=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 switch (dw10) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 case NVME_NS_CREATE: +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return = nvme_namespace_create(n, cmd, req); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 case NVME_NS_DELETE: +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if ( cm= d->nsid =3D=3D 0xFFFFFFFF ) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 uint32_t i; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 uint16_t ret =3D NVME_SUCCESS; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 for (i =3D 1; i < NVME_MAX_NUM_NAMESPACES; i++) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 cmd->nsid =3D i; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if ( &n->namespaces[cmd->nsid - = 1].created) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ret =3D = nvme_namespace_delete(n, cmd, req); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (ret !=3D NVME_SUCCESS) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return r= et; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 return ret; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return = nvme_namespace_delete(n, cmd, req); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 default: +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return = NVME_INVALID_FIELD; +=C2=A0=C2=A0=C2=A0 } +} + =C2=A0static inline void nvme_set_timestamp(NvmeCtrl *n, uint64_t ts) =C2=A0{ =C2=A0=C2=A0=C2=A0=C2=A0 trace_nvme_setfeat_timestamp(ts); @@ -860,6 +1170,10 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n,=20 NvmeCmd *cmd, NvmeRequest *req) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return nvme_set_feature(n= , cmd, req); =C2=A0=C2=A0=C2=A0=C2=A0 case NVME_ADM_CMD_GET_FEATURES: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return nvme_get_feature(n= , cmd, req); +=C2=A0=C2=A0=C2=A0 case NVME_ADM_CMD_NS_MANAGEMENT: +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return nvme_namespace_managemen= t(n, cmd, req); +=C2=A0=C2=A0=C2=A0 case NVME_ADM_CMD_NS_ATTACH: +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return nvme_namespace_attachmen= t(n, cmd); =C2=A0=C2=A0=C2=A0=C2=A0 default: =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 trace_nvme_err_invalid_ad= min_opc(cmd->opcode); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NVME_INVALID_OPCOD= E | NVME_DNR; @@ -915,6 +1229,7 @@ static void nvme_clear_ctrl(NvmeCtrl *n) =C2=A0=C2=A0=C2=A0=C2=A0 } =C2=A0=C2=A0=C2=A0=C2=A0 blk_flush(n->conf.blk); + =C2=A0=C2=A0=C2=A0=C2=A0 n->bar.cc =3D 0; =C2=A0} @@ -1302,61 +1617,10 @@ static const MemoryRegionOps nvme_cmb_ops =3D { =C2=A0=C2=A0=C2=A0=C2=A0 }, =C2=A0}; -static void nvme_realize(PCIDevice *pci_dev, Error **errp) +static void nvme_init_ctrl(NvmeCtrl *n) =C2=A0{ -=C2=A0=C2=A0=C2=A0 NvmeCtrl *n =3D NVME(pci_dev); =C2=A0=C2=A0=C2=A0=C2=A0 NvmeIdCtrl *id =3D &n->id_ctrl; - -=C2=A0=C2=A0=C2=A0 int i; -=C2=A0=C2=A0=C2=A0 int64_t bs_size; -=C2=A0=C2=A0=C2=A0 uint8_t *pci_conf; - -=C2=A0=C2=A0=C2=A0 if (!n->num_queues) { -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 error_setg(errp, "num_queues ca= n't be zero"); -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return; -=C2=A0=C2=A0=C2=A0 } - -=C2=A0=C2=A0=C2=A0 if (!n->conf.blk) { -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 error_setg(errp, "drive propert= y not set"); -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return; -=C2=A0=C2=A0=C2=A0 } - -=C2=A0=C2=A0=C2=A0 bs_size =3D blk_getlength(n->conf.blk); -=C2=A0=C2=A0=C2=A0 if (bs_size < 0) { -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 error_setg(errp, "could not get= backing file size"); -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return; -=C2=A0=C2=A0=C2=A0 } - -=C2=A0=C2=A0=C2=A0 if (!n->serial) { -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 error_setg(errp, "serial proper= ty not set"); -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return; -=C2=A0=C2=A0=C2=A0 } -=C2=A0=C2=A0=C2=A0 blkconf_blocksizes(&n->conf); -=C2=A0=C2=A0=C2=A0 if (!blkconf_apply_backend_options(&n->conf,=20 blk_is_read_only(n->conf.blk), -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 false, errp)) { -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return; -=C2=A0=C2=A0=C2=A0 } - -=C2=A0=C2=A0=C2=A0 pci_conf =3D pci_dev->config; -=C2=A0=C2=A0=C2=A0 pci_conf[PCI_INTERRUPT_PIN] =3D 1; -=C2=A0=C2=A0=C2=A0 pci_config_set_prog_interface(pci_dev->config, 0x2); -=C2=A0=C2=A0=C2=A0 pci_config_set_class(pci_dev->config, PCI_CLASS_STORAGE= _EXPRESS); -=C2=A0=C2=A0=C2=A0 pcie_endpoint_cap_init(pci_dev, 0x80); - -=C2=A0=C2=A0=C2=A0 n->num_namespaces =3D 1; -=C2=A0=C2=A0=C2=A0 n->reg_size =3D pow2ceil(0x1004 + 2 * (n->num_queues + = 1) * 4); -=C2=A0=C2=A0=C2=A0 n->ns_size =3D bs_size / (uint64_t)n->num_namespaces; - -=C2=A0=C2=A0=C2=A0 n->namespaces =3D g_new0(NvmeNamespace, n->num_namespac= es); -=C2=A0=C2=A0=C2=A0 n->sq =3D g_new0(NvmeSQueue *, n->num_queues); -=C2=A0=C2=A0=C2=A0 n->cq =3D g_new0(NvmeCQueue *, n->num_queues); - -=C2=A0=C2=A0=C2=A0 memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_= ops, n, -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 "nvme", n->reg_size); -=C2=A0=C2=A0=C2=A0 pci_register_bar(pci_dev, 0, -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 PCI_BASE_ADDRESS_SPACE_MEMORY |= PCI_BASE_ADDRESS_MEM_TYPE_64, -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 &n->iomem); -=C2=A0=C2=A0=C2=A0 msix_init_exclusive_bar(pci_dev, n->num_queues, 4, NULL= ); +=C2=A0=C2=A0=C2=A0 uint8_t *pci_conf =3D n->parent_obj.config; =C2=A0=C2=A0=C2=A0=C2=A0 id->vid =3D cpu_to_le16(pci_get_word(pci_conf + P= CI_VENDOR_ID)); =C2=A0=C2=A0=C2=A0=C2=A0 id->ssvid =3D cpu_to_le16(pci_get_word(pci_conf +=20 PCI_SUBSYSTEM_VENDOR_ID)); @@ -1367,16 +1631,25 @@ static void nvme_realize(PCIDevice *pci_dev,=20 Error **errp) =C2=A0=C2=A0=C2=A0=C2=A0 id->ieee[0] =3D 0x00; =C2=A0=C2=A0=C2=A0=C2=A0 id->ieee[1] =3D 0x02; =C2=A0=C2=A0=C2=A0=C2=A0 id->ieee[2] =3D 0xb3; -=C2=A0=C2=A0=C2=A0 id->oacs =3D cpu_to_le16(0); +=C2=A0=C2=A0=C2=A0 id->oacs =3D cpu_to_le16(0x8); // Namespace Management = Supported + =C2=A0=C2=A0=C2=A0=C2=A0 id->frmw =3D 7 << 1; =C2=A0=C2=A0=C2=A0=C2=A0 id->lpa =3D 1 << 0; =C2=A0=C2=A0=C2=A0=C2=A0 id->sqes =3D (0x6 << 4) | 0x6; =C2=A0=C2=A0=C2=A0=C2=A0 id->cqes =3D (0x4 << 4) | 0x4; -=C2=A0=C2=A0=C2=A0 id->nn =3D cpu_to_le32(n->num_namespaces); +=C2=A0=C2=A0=C2=A0 id->mnan =3D 0; +=C2=A0=C2=A0=C2=A0 id->nn =3D NVME_MAX_NUM_NAMESPACES; =C2=A0=C2=A0=C2=A0=C2=A0 id->oncs =3D cpu_to_le16(NVME_ONCS_WRITE_ZEROS | = NVME_ONCS_TIMESTAMP); =C2=A0=C2=A0=C2=A0=C2=A0 id->psd[0].mp =3D cpu_to_le16(0x9c4); =C2=A0=C2=A0=C2=A0=C2=A0 id->psd[0].enlat =3D cpu_to_le32(0x10); =C2=A0=C2=A0=C2=A0=C2=A0 id->psd[0].exlat =3D cpu_to_le32(0x4); +=C2=A0=C2=A0=C2=A0 id->tnvmcap =3D n->nvm_capacity; +=C2=A0=C2=A0=C2=A0 id->unvmcap =3D 0; +=C2=A0=C2=A0=C2=A0 id->hmpre =3D n->hmpre; +=C2=A0=C2=A0=C2=A0 id->hmmin =3D n->hmmin; + +=C2=A0=C2=A0=C2=A0 snprintf ((char*)id->subnqn, sizeof(id->subnqn), "QEMU = NVMe=20 Subsystem 1.2 Compatible"); + =C2=A0=C2=A0=C2=A0=C2=A0 if (blk_enable_write_cache(n->conf.blk)) { =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id->vwc =3D 1; =C2=A0=C2=A0=C2=A0=C2=A0 } @@ -1387,10 +1660,34 @@ static void nvme_realize(PCIDevice *pci_dev,=20 Error **errp) =C2=A0=C2=A0=C2=A0=C2=A0 NVME_CAP_SET_AMS(n->bar.cap, 1); =C2=A0=C2=A0=C2=A0=C2=A0 NVME_CAP_SET_TO(n->bar.cap, 0xf); =C2=A0=C2=A0=C2=A0=C2=A0 NVME_CAP_SET_CSS(n->bar.cap, 1); +=C2=A0=C2=A0=C2=A0 NVME_CAP_SET_MPSMIN(n->bar.cap, 0); =C2=A0=C2=A0=C2=A0=C2=A0 NVME_CAP_SET_MPSMAX(n->bar.cap, 4); =C2=A0=C2=A0=C2=A0=C2=A0 n->bar.vs =3D 0x00010200; =C2=A0=C2=A0=C2=A0=C2=A0 n->bar.intmc =3D n->bar.intms =3D 0; +} + +static void nvme_init_pci(NvmeCtrl *n) { +=C2=A0=C2=A0=C2=A0 uint8_t *pci_conf =3D n->parent_obj.config; + +=C2=A0=C2=A0=C2=A0 pci_conf[PCI_INTERRUPT_PIN] =3D 1; +=C2=A0=C2=A0=C2=A0 pci_config_set_prog_interface(pci_conf, 0x2); +=C2=A0=C2=A0=C2=A0 pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_EXPRES= S); + + +=C2=A0=C2=A0=C2=A0 pci_config_set_device_id(pci_conf, 0x5845); +=C2=A0=C2=A0=C2=A0 pcie_endpoint_cap_init(&n->parent_obj, 0x80); + +=C2=A0=C2=A0=C2=A0 memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_= ops, n, "nvme", +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 n->reg_size); + + +=C2=A0=C2=A0=C2=A0 pci_register_bar(&n->parent_obj, 0, +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 PCI_BASE_ADDRESS_SPACE_MEM= ORY |=20 PCI_BASE_ADDRESS_MEM_TYPE_64, +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 &n->iomem); + + +=C2=A0=C2=A0=C2=A0 msix_init_exclusive_bar(&n->parent_obj, n->num_queues, = 4, NULL); =C2=A0=C2=A0=C2=A0=C2=A0 if (n->cmb_size_mb) { @@ -1406,20 +1703,31 @@ static void nvme_realize(PCIDevice *pci_dev,=20 Error **errp) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 NVME_CMBSZ_SET_SZ(n->bar.= cmbsz, n->cmb_size_mb); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n->cmbloc =3D n->bar.cmbl= oc; -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n->cmbsz =3D n->bar.cmbsz; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n->cmbsz=C2=A0 =3D n->bar.cmbsz; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n->cmbuf =3D g_malloc0(NV= ME_CMBSZ_GETSIZE(n->bar.cmbsz)); =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 memory_region_init_io(&n-= >ctrl_mem, OBJECT(n), &nvme_cmb_ops, n, =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "nvme-cmb",=20 NVME_CMBSZ_GETSIZE(n->bar.cmbsz)); -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 pci_register_bar(pci_dev, NVME_= CMBLOC_BIR(n->bar.cmbloc), -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 PCI_BAS= E_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 | -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 PCI_BAS= E_ADDRESS_MEM_PREFETCH, &n->ctrl_mem); - +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 pci_register_bar(&n->parent_obj= , NVME_CMBLOC_BIR(n->bar.cmbloc), +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 PC= I_BASE_ADDRESS_SPACE_MEMORY |=20 PCI_BASE_ADDRESS_MEM_TYPE_64 | +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 PC= I_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem); =C2=A0=C2=A0=C2=A0=C2=A0 } +} + +/** + * Divides up the total block space between all requested namespaces. + * @param n + */ +static void nvme_init_namespaces(NvmeCtrl *n) +{ +=C2=A0=C2=A0=C2=A0 uint8_t i; =C2=A0=C2=A0=C2=A0=C2=A0 for (i =3D 0; i < n->num_namespaces; i++) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 uint64_t blks; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int lba_index; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 NvmeNamespace *ns =3D &n-= >namespaces[i]; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 NvmeIdNs *id_ns =3D &ns->= id_ns; + =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->nsfeat =3D 0; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->nlbaf =3D 0; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->flbas =3D 0; @@ -1427,12 +1735,65 @@ static void nvme_realize(PCIDevice *pci_dev,=20 Error **errp) =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->dpc =3D 0; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->dps =3D 0; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->lbaf[0].ds =3D BDR= V_SECTOR_BITS; -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->ncap=C2=A0 =3D id_ns->nu= se =3D id_ns->nsze =3D -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 cpu_to_= le64(n->ns_size >> - id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas)].ds); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->nsze =3D n->nvm_capacity= / (uint64_t)n->num_namespaces; + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 lba_index =3D NVME_ID_NS_FLBAS_= INDEX(ns->id_ns.flbas); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 blks =3D id_ns->nsze / (1 << id= _ns->lbaf[lba_index].ds); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->nuse =3D id_ns->ncap =3D= id_ns->nsze =3D cpu_to_le64(blks); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id_ns->nvmcap =3D id_ns->nsze *= (1 << id_ns->lbaf[lba_index].ds); + +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ns->id =3D i + 1; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ns->start_byte_index =3D (i * i= d_ns->nsze) >> BDRV_SECTOR_BITS; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ns->created =3D true; +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ns->ctrl =3D n; /* attached */ + =C2=A0=C2=A0=C2=A0=C2=A0 } =C2=A0} +static void nvme_realize(PCIDevice *pci_dev, Error **errp) +{ +=C2=A0=C2=A0=C2=A0 NvmeCtrl *n =3D NVME(pci_dev); + +=C2=A0=C2=A0=C2=A0 int64_t bs_size; +=C2=A0=C2=A0=C2=A0 Error *local_err =3D NULL; + +=C2=A0=C2=A0=C2=A0 if (!n->conf.blk) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 error_setg(errp, "drive propert= y not set"); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return; +=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 bs_size =3D blk_getlength(n->conf.blk); +=C2=A0=C2=A0=C2=A0 if (bs_size < 0) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 error_setg(errp, "could not get= backing file size"); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return; +=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 if (!n->serial) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 error_setg(errp, "serial proper= ty not set"); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return; +=C2=A0=C2=A0=C2=A0 } +=C2=A0=C2=A0=C2=A0 blkconf_blocksizes(&n->conf); +=C2=A0=C2=A0=C2=A0 blkconf_apply_backend_options(&n->conf, blk_is_read_onl= y(n->conf.blk), +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 false, &local_err); +=C2=A0=C2=A0=C2=A0 if (local_err) { +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 error_report_err(local_err); +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return; +=C2=A0=C2=A0=C2=A0 } + +=C2=A0=C2=A0=C2=A0 n->reg_size =3D pow2ceil(0x1004 + 2 * (n->num_queues + = 1) * 4); +=C2=A0=C2=A0=C2=A0 n->nvm_capacity =3D bs_size; +=C2=A0=C2=A0=C2=A0 n->sq =3D g_new0(NvmeSQueue *, n->num_queues); +=C2=A0=C2=A0=C2=A0 n->cq =3D g_new0(NvmeCQueue *, n->num_queues); +=C2=A0=C2=A0=C2=A0 n->namespaces =3D g_new0(NvmeNamespace, NVME_MAX_NUM_NA= MESPACES); + +=C2=A0=C2=A0=C2=A0 nvme_init_pci(n); +=C2=A0=C2=A0=C2=A0 nvme_init_ctrl(n); +=C2=A0=C2=A0=C2=A0 nvme_init_namespaces(n); + +} + =C2=A0static void nvme_exit(PCIDevice *pci_dev) =C2=A0{ =C2=A0=C2=A0=C2=A0=C2=A0 NvmeCtrl *n =3D NVME(pci_dev); @@ -1451,6 +1812,7 @@ static void nvme_exit(PCIDevice *pci_dev) =C2=A0static Property nvme_props[] =3D { =C2=A0=C2=A0=C2=A0=C2=A0 DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf), =C2=A0=C2=A0=C2=A0=C2=A0 DEFINE_PROP_STRING("serial", NvmeCtrl, serial), +=C2=A0=C2=A0=C2=A0 DEFINE_PROP_UINT32("namespaces", NvmeCtrl, num_namespac= es, 1), =C2=A0=C2=A0=C2=A0=C2=A0 DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_s= ize_mb, 0), =C2=A0=C2=A0=C2=A0=C2=A0 DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_qu= eues, 64), =C2=A0=C2=A0=C2=A0=C2=A0 DEFINE_PROP_END_OF_LIST(), diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 557194ee19..c182dcb10a 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -9,6 +9,7 @@ typedef struct NvmeAsyncEvent { =C2=A0typedef struct NvmeRequest { =C2=A0=C2=A0=C2=A0=C2=A0 struct NvmeSQueue=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 *sq; +=C2=A0=C2=A0=C2=A0 struct NvmeNamespace=C2=A0=C2=A0=C2=A0 *ns; =C2=A0=C2=A0=C2=A0=C2=A0 BlockAIOCB=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 *aiocb; =C2=A0=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 status; =C2=A0=C2=A0=C2=A0=C2=A0 bool=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 has_s= g; @@ -50,7 +51,16 @@ typedef struct NvmeCQueue { =C2=A0} NvmeCQueue; =C2=A0typedef struct NvmeNamespace { +=C2=A0=C2=A0=C2=A0 struct NvmeCtrl *ctrl; +=C2=A0=C2=A0=C2=A0 bool=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 created; =C2=A0=C2=A0=C2=A0=C2=A0 NvmeIdNs=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 id_ns; +=C2=A0=C2=A0=C2=A0 NvmeRangeType=C2=A0=C2=A0 lba_range[64]; +=C2=A0=C2=A0=C2=A0 unsigned long=C2=A0=C2=A0 *util; +=C2=A0=C2=A0=C2=A0 unsigned long=C2=A0=C2=A0 *uncorrectable; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 id; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 star= t_byte_index; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 meta= _start_offset; +=C2=A0=C2=A0=C2=A0 BlockConf=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 conf; =C2=A0} NvmeNamespace; =C2=A0#define TYPE_NVME "nvme" @@ -64,23 +74,66 @@ typedef struct NvmeCtrl { =C2=A0=C2=A0=C2=A0=C2=A0 NvmeBar=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 bar; =C2=A0=C2=A0=C2=A0=C2=A0 BlockConf=C2=A0=C2=A0=C2=A0 conf; -=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 page_size; +=C2=A0=C2=A0=C2=A0 time_t=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 start_time; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 temperature; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 page_size; =C2=A0=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 page_bits; =C2=A0=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 max_prp_ents; =C2=A0=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 cqe_size; =C2=A0=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 sqe_size; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 oacs; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 oncs; =C2=A0=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 reg_size; =C2=A0=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 num_namespaces; =C2=A0=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 num_queues; =C2=A0=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 max_q_ents; -=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 ns_size; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 nvm_capacity; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 db_stride; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 aerl; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 acl; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 elpe; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 elp_index; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 error_count; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 mdts; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 cqr; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 max_sqes; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 max_cqes; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 meta; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 vwc; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 mc; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 dpc; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 dps; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 nlbaf; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 extended; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 lba_index; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 mpsmin; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 mpsmax; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 intc; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 intc_thresh; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 intc_time; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 outstanding_aers; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 temp_warn_issued; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 num_errors; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 cqes_pending; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 vid; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 did; =C2=A0=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 cmb_size_mb; =C2=A0=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 cmbsz; =C2=A0=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 cmbloc; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 sriov_total_vfs; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 *cmbuf; =C2=A0=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 irq_status; =C2=A0=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 host_timestamp;=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 /* Timestamp sent by=20 the host */ =C2=A0=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 timestamp_set_qemu_clo= ck_ms;=C2=A0=C2=A0=C2=A0 /* QEMU clock time */ +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 ehm; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 hsize; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 hmdlal; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 hmdlua; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 hmdlec; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 *hmbuf; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 hmmin; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 hmpre; + =C2=A0=C2=A0=C2=A0=C2=A0 char=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 *serial; =C2=A0=C2=A0=C2=A0=C2=A0 NvmeNamespace=C2=A0=C2=A0 *namespaces; diff --git a/include/block/nvme.h b/include/block/nvme.h index 3ec8efcc43..8c1e8c6cdc 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -17,6 +17,16 @@ typedef struct NvmeBar { =C2=A0=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 cmbsz; =C2=A0} NvmeBar; +enum NvmeNsSelect { +=C2=A0=C2=A0=C2=A0 NVME_NS_CONTROLLER_ATTACH =3D 0, +=C2=A0=C2=A0=C2=A0 NVME_NS_CONTROLLER_DETACH =3D 1, +}; + +enum NvmeNsManagement { +=C2=A0=C2=A0=C2=A0 NVME_NS_CREATE =3D 0, +=C2=A0=C2=A0=C2=A0 NVME_NS_DELETE =3D 1, +}; + =C2=A0enum NvmeCapShift { =C2=A0=C2=A0=C2=A0=C2=A0 CAP_MQES_SHIFT=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0, =C2=A0=C2=A0=C2=A0=C2=A0 CAP_CQR_SHIFT=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D 1= 6, @@ -233,13 +243,31 @@ enum NvmeAdminCommands { =C2=A0=C2=A0=C2=A0=C2=A0 NVME_ADM_CMD_SET_FEATURES=C2=A0=C2=A0 =3D 0x09, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_ADM_CMD_GET_FEATURES=C2=A0=C2=A0 =3D 0x0a, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_ADM_CMD_ASYNC_EV_REQ=C2=A0=C2=A0 =3D 0x0c, +=C2=A0=C2=A0=C2=A0 NVME_ADM_CMD_NS_MANAGEMENT=C2=A0 =3D 0x0d, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_ADM_CMD_ACTIVATE_FW=C2=A0=C2=A0=C2=A0 =3D 0x= 10, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_ADM_CMD_DOWNLOAD_FW=C2=A0=C2=A0=C2=A0 =3D 0x= 11, +=C2=A0=C2=A0=C2=A0 NVME_ADM_CMD_NS_ATTACH=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = =3D 0x15, +=C2=A0=C2=A0=C2=A0 NVME_ADM_VIRT_MANAGEMENT=C2=A0=C2=A0=C2=A0 =3D 0x1C, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_ADM_CMD_FORMAT_NVM=C2=A0=C2=A0=C2=A0=C2=A0 = =3D 0x80, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_ADM_CMD_SECURITY_SEND=C2=A0 =3D 0x81, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_ADM_CMD_SECURITY_RECV=C2=A0 =3D 0x82, =C2=A0}; + +enum NvmeAdminCns { +=C2=A0=C2=A0=C2=A0 NVME_ADM_CNS_ID_NS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0x00, +=C2=A0=C2=A0=C2=A0 NVME_ADM_CNS_ID_CTRL=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 =3D 0x01, +=C2=A0=C2=A0=C2=A0 NVME_ADM_CNS_ID_NS_LIST=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 =3D 0x02, +=C2=A0=C2=A0=C2=A0 NVME_ADM_CNS_NS_DESC_LIST=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0= x03, +=C2=A0=C2=A0=C2=A0 NVME_ADM_CNS_NVM_SET_LIST=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0= x04, +=C2=A0=C2=A0=C2=A0 NVME_ADM_CNS_ID_NS_LIST_ALLOC =3D 0x10, +=C2=A0=C2=A0=C2=A0 NVME_ADM_CNS_ID_NS_ALLOC=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = =3D 0x11, +=C2=A0=C2=A0=C2=A0 NVME_ADM_CNS_CTRL_LIST_NS_ATT =3D 0x12, +=C2=A0=C2=A0=C2=A0 NVME_ADM_CNS_CTRL_LIST=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 =3D 0x13, +=C2=A0=C2=A0=C2=A0 NVME_ADM_CNS_PRIM_CTRL_CAP=C2=A0=C2=A0=C2=A0 =3D 0x14, +=C2=A0=C2=A0=C2=A0 NVME_ADM_CNS_SEC_CTRL_LIST=C2=A0=C2=A0=C2=A0 =3D 0x15, +}; + =C2=A0enum NvmeIoCommands { =C2=A0=C2=A0=C2=A0=C2=A0 NVME_CMD_FLUSH=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0x00, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_CMD_WRITE=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0x01, @@ -427,6 +455,17 @@ enum NvmeStatusCodes { =C2=A0=C2=A0=C2=A0=C2=A0 NVME_CMD_ABORT_MISSING_FUSE =3D 0x000a, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_INVALID_NSID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0x000b, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_CMD_SEQ_ERROR=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 =3D 0x000c, +=C2=A0=C2=A0=C2=A0 NVME_NS_INSUFF_CAP=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =3D 0x0015, +=C2=A0=C2=A0=C2=A0 NVME_NS_ID_UNAVAILABLE=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = =3D 0x0016, +=C2=A0=C2=A0=C2=A0 NVME_NS_ALREADY_ATTACHED=C2=A0=C2=A0=C2=A0 =3D 0x0018, +=C2=A0=C2=A0=C2=A0 NVME_NS_PRIVATE=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0x0019, +=C2=A0=C2=A0=C2=A0 NVME_NS_NOT_ATTACHED=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 =3D 0x001A, +=C2=A0=C2=A0=C2=A0 NVME_THIN_PROV_NOT_SUP=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = =3D 0x001B, +=C2=A0=C2=A0=C2=A0 NVME_CTRL_LIST_INVALID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = =3D 0x001C, +=C2=A0=C2=A0=C2=A0 NVME_INVALID_CTRL_ID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 =3D 0x001F, +=C2=A0=C2=A0=C2=A0 NVME_INVALID_SEC_CTRL_ST=C2=A0=C2=A0=C2=A0 =3D 0x0020, +=C2=A0=C2=A0=C2=A0 NVME_INVALID_NUM_CTRL_RES=C2=A0=C2=A0 =3D 0x0021, +=C2=A0=C2=A0=C2=A0 NVME_INVALID_RES_ID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 =3D 0x0022, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_LBA_RANGE=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0x0080, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_CAP_EXCEEDED=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0x0081, =C2=A0=C2=A0=C2=A0=C2=A0 NVME_NS_NOT_READY=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0x0082, @@ -543,7 +582,20 @@ typedef struct NvmeIdCtrl { =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 ieee[3]; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 cmic; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 mdts; -=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd255[178]; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 cntlid; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 ver; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd_95[8]; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 oaes; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 ctratt; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 rrls; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd110[9]; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 cntrltype; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 fguid; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 fguid_u; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 crdt1; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 crdt2; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 crdt3; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd255[122]; =C2=A0=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 oacs; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 acl; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 aerl; @@ -551,10 +603,39 @@ typedef struct NvmeIdCtrl { =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 lpa; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 elpe; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 npss; -=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd511[248]; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 avscc; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 apsta; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 wctemp; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 cctemp; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 mtfa; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 hmpre; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 hmmin; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 tnvmcap; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 tnvmcap_u; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 unvmcap; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 unvmcap_u; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 rpmbs; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 edstt; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 dsto; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 fwug; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 kas; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 hctma; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 mntmt; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 mxtmt; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 sanicap; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 hmminds; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 hmmaxd; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 nsetidmax; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 endgidmax; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 anatt; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 anacap; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 anagrpmax; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 nanagrpid; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 pels; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd511[156]; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 sqes; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 cqes; -=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 rsvd515; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 maxcmd; =C2=A0=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 nn; =C2=A0=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 oncs; =C2=A0=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 fuses; @@ -562,8 +643,15 @@ typedef struct NvmeIdCtrl { =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 vwc; =C2=A0=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 awun; =C2=A0=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 awupf; -=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd703[174]; -=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd2047[1344]; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 nvscc; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 nwpc; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 acwu; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd535[2]; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 sgls; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 mnan; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd767[224]; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 subnqn[256]; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd2047[1024]; =C2=A0=C2=A0=C2=A0=C2=A0 NvmePSD=C2=A0=C2=A0=C2=A0=C2=A0 psd[32]; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 vs[1024]; =C2=A0} NvmeIdCtrl; @@ -653,9 +741,35 @@ typedef struct NvmeIdNs { =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 mc; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 dpc; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 dps; -=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 res30[98]; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 nmic; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rescap; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 fpi; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 dlfeat; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 nawun; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 nawupf; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 nacwu; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 nabsn; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 nabo; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 nabspf; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 noiob; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 nvmcap; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 nvmcap_u; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 npwg; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 npwa; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 npdg; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 npda; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 nows; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd91[18]; +=C2=A0=C2=A0=C2=A0 uint32_t=C2=A0=C2=A0=C2=A0 anagrpid; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd98[3]; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 nsattr; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 nvmsetid; +=C2=A0=C2=A0=C2=A0 uint16_t=C2=A0=C2=A0=C2=A0 endgid; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 nguid; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 nguid_u; +=C2=A0=C2=A0=C2=A0 uint64_t=C2=A0=C2=A0=C2=A0 eui64; =C2=A0=C2=A0=C2=A0=C2=A0 NvmeLBAF=C2=A0=C2=A0=C2=A0 lbaf[16]; -=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 res192[192]; +=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 rsvd383[192]; =C2=A0=C2=A0=C2=A0=C2=A0 uint8_t=C2=A0=C2=A0=C2=A0=C2=A0 vs[3712]; =C2=A0} NvmeIdNs; --=20 2.17.1