From nobody Thu Apr 18 08:42:26 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.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=1593491033; cv=none; d=zohomail.com; s=zohoarc; b=bQJIvOcX47DNc7z7OVxks16k1C3B31LjvCrKLJEVBLGvuILHOX6tySieWiqPRfu54mD8yR4crcm4+vChmDeSamS+h2z1N8SuciMgjF4brl2hq5R+mB3w4vN45htFkpWaSTMmQsHRxsah4vqzLhtF19KQMB5chgp0WKouxi80LH8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1593491033; h=Content-Transfer-Encoding:Cc:Date:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:To; bh=YH6yvfSPnYpX3LQbp+KFfQlLFio/520SleadpSbLU78=; b=epr44z7LKoBLmduUPozKx5uPojTTy4eZ9YdOr4wNRr2X5Eq+uuPoMagPNgupXDcOM+BNjaY5HuL43ud2+Of3CnYKU5TRG8gBVvpNhbHHKIOOJLV9i0UKOiHMbpn7kPbBNJHKa6x7+893wQ1m1cR1dWjdanIcH4Pgy9EhTFkQMeA= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.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 (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1593491033080970.6551425391007; Mon, 29 Jun 2020 21:23:53 -0700 (PDT) Received: from localhost ([::1]:59736 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jq7oF-00046C-Rw for importer@patchew.org; Tue, 30 Jun 2020 00:23:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:43874) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jq7nb-0003bu-AO; Tue, 30 Jun 2020 00:23:11 -0400 Received: from charlie.dont.surf ([128.199.63.193]:47044) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jq7nY-00035i-QF; Tue, 30 Jun 2020 00:23:11 -0400 Received: from apples.local (80-167-98-190-cable.dk.customer.tdc.net [80.167.98.190]) by charlie.dont.surf (Postfix) with ESMTPSA id D1FD5BF670; Tue, 30 Jun 2020 04:23:06 +0000 (UTC) From: Klaus Jensen To: qemu-block@nongnu.org Subject: [PATCH] hw/block/nvme: add support for dulbe Date: Tue, 30 Jun 2020 06:23:04 +0200 Message-Id: <20200630042304.1305269-1-its@irrelevant.dk> X-Mailer: git-send-email 2.27.0 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.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; Received-SPF: pass client-ip=128.199.63.193; envelope-from=its@irrelevant.dk; helo=charlie.dont.surf X-detected-operating-system: by eggs.gnu.org: First seen = 2020/06/30 00:09:10 X-ACL-Warn: Detected OS = Linux 3.11 and newer [fuzzy] X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_NONE=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: Kevin Wolf , Klaus Jensen , qemu-devel@nongnu.org, Max Reitz , Klaus Jensen , Keith Busch Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" From: Klaus Jensen This adds support for reporting the Deallocated or Unwritten Logical Block error (DULBE). This requires tracking the allocated/deallocated status of all logical blocks. Introduce a bitmap that does this. The bitmap is persisted on the new 'state' drive that is associated with a namespace. If no such drive is attached, the controller will not indicate support for DULBE. Signed-off-by: Klaus Jensen --- Based-on: <20200630041956.1304473-1-its@irrelevant.dk> ("[PATCH] hw/block/nvme: make lba data size configurable") hw/block/nvme-ns.c | 103 +++++++++++++++++++++++++++++++++++++ hw/block/nvme-ns.h | 12 +++++ hw/block/nvme.c | 117 ++++++++++++++++++++++++++++++++++++++++-- hw/block/nvme.h | 4 +- hw/block/trace-events | 3 ++ include/block/nvme.h | 5 ++ 6 files changed, 240 insertions(+), 4 deletions(-) diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index d6ec55860a5e..7c825c38c69d 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -28,6 +28,35 @@ #include "nvme.h" #include "nvme-ns.h" =20 +static int nvme_ns_blk_resize(BlockBackend *blk, size_t len, Error **errp) +{ + Error *local_err =3D NULL; + int ret; + uint64_t perm, shared_perm; + + blk_get_perm(blk, &perm, &shared_perm); + + ret =3D blk_set_perm(blk, perm | BLK_PERM_RESIZE, shared_perm, &local_err= ); + if (ret < 0) { + error_propagate_prepend(errp, local_err, "blk_set_perm: "); + return ret; + } + + ret =3D blk_truncate(blk, len, false, PREALLOC_MODE_OFF, 0, &local_err); + if (ret < 0) { + error_propagate_prepend(errp, local_err, "blk_truncate: "); + return ret; + } + + ret =3D blk_set_perm(blk, perm, shared_perm, &local_err); + if (ret < 0) { + error_propagate_prepend(errp, local_err, "blk_set_perm: "); + return ret; + } + + return 0; +} + static void nvme_ns_init(NvmeNamespace *ns) { NvmeIdNs *id_ns =3D &ns->id_ns; @@ -41,6 +70,66 @@ static void nvme_ns_init(NvmeNamespace *ns) id_ns->nuse =3D id_ns->ncap; } =20 +static int nvme_ns_init_blk_state(NvmeNamespace *ns, Error **errp) +{ + BlockBackend *blk =3D ns->blk_state; + uint64_t perm, shared_perm; + int64_t len, state_len; + + Error *local_err =3D NULL; + int ret; + + perm =3D BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; + shared_perm =3D BLK_PERM_ALL; + + ns->utilization =3D bitmap_new(nvme_ns_nlbas(ns)); + + ret =3D blk_set_perm(blk, perm, shared_perm, &local_err); + if (ret) { + error_propagate_prepend(errp, local_err, "blk_set_perm: "); + return ret; + } + + state_len =3D nvme_ns_blk_state_len(ns); + + len =3D blk_getlength(blk); + if (len < 0) { + error_setg_errno(errp, -len, "blk_getlength: "); + return len; + } + + if (len) { + if (len !=3D state_len) { + error_setg(errp, "state size mismatch " + "(expected %"PRIu64" bytes; was %"PRIu64" bytes)", + state_len, len); + error_append_hint(errp, + "Did you change the 'lbads' parameter? " + "Or re-formatted the namespace using Format NVM?\n"); + return -1; + } + + ret =3D blk_pread(blk, 0, ns->utilization, state_len); + if (ret < 0) { + error_setg_errno(errp, -ret, "blk_pread: "); + return ret; + } else if (ret !=3D state_len) { + error_setg(errp, "blk_pread: short read"); + return -1; + } + + return 0; + } + + ret =3D nvme_ns_blk_resize(blk, state_len, &local_err); + if (ret < 0) { + error_propagate_prepend(errp, local_err, "nvme_ns_blk_resize: "); + return ret; + } + + return 0; +} + static int nvme_ns_init_blk(NvmeCtrl *n, NvmeNamespace *ns, NvmeIdCtrl *id, Error **errp) { @@ -111,6 +200,19 @@ int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Erro= r **errp) } =20 nvme_ns_init(ns); + + if (ns->blk_state) { + if (nvme_ns_init_blk_state(ns, errp)) { + return -1; + } + + /* + * With a state file in place we can enable the Deallocated or + * Unwritten Logical Block Error feature. + */ + ns->id_ns.nsfeat |=3D 0x4; + } + if (nvme_register_namespace(n, ns, errp)) { return -1; } @@ -136,6 +238,7 @@ static Property nvme_ns_props[] =3D { DEFINE_PROP_DRIVE("drive", NvmeNamespace, blk), DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0), DEFINE_PROP_UINT8("lbads", NvmeNamespace, params.lbads, BDRV_SECTOR_BI= TS), + DEFINE_PROP_DRIVE("state", NvmeNamespace, blk_state), DEFINE_PROP_END_OF_LIST(), }; =20 diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h index bee46b32efa5..eb901acc912b 100644 --- a/hw/block/nvme-ns.h +++ b/hw/block/nvme-ns.h @@ -27,11 +27,18 @@ typedef struct NvmeNamespaceParams { typedef struct NvmeNamespace { DeviceState parent_obj; BlockBackend *blk; + BlockBackend *blk_state; int32_t bootindex; int64_t size; =20 NvmeIdNs id_ns; NvmeNamespaceParams params; + + unsigned long *utilization; + + struct { + uint32_t err_rec; + } features; } NvmeNamespace; =20 static inline uint32_t nvme_nsid(NvmeNamespace *ns) @@ -60,6 +67,11 @@ static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns) return ns->size >> nvme_ns_lbads(ns); } =20 +static inline size_t nvme_ns_blk_state_len(NvmeNamespace *ns) +{ + return ROUND_UP(DIV_ROUND_UP(nvme_ns_nlbas(ns), 8), BDRV_SECTOR_SIZE); +} + typedef struct NvmeCtrl NvmeCtrl; =20 int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp); diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 9e512c88656d..8e147b667c81 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -681,6 +681,10 @@ static uint16_t nvme_dma(NvmeCtrl *n, uint8_t *ptr, ui= nt32_t len, =20 static void nvme_aio_destroy(NvmeAIO *aio) { + if (aio->flags & NVME_AIO_INTERNAL) { + qemu_iovec_destroy((QEMUIOVector *)aio->payload); + } + g_free(aio); } =20 @@ -915,6 +919,18 @@ static inline uint16_t nvme_check_bounds(NvmeCtrl *n, = NvmeNamespace *ns, return NVME_SUCCESS; } =20 +static inline uint16_t nvme_check_dulbe(NvmeCtrl *n, NvmeNamespace *ns, + uint64_t slba, uint32_t nlb) +{ + uint64_t elba =3D slba + nlb; + + if (find_next_zero_bit(ns->utilization, elba, slba) < elba) { + return NVME_DULB; + } + + return NVME_SUCCESS; +} + static uint16_t nvme_check_rw(NvmeCtrl *n, NvmeRequest *req) { NvmeNamespace *ns =3D req->ns; @@ -934,9 +950,57 @@ static uint16_t nvme_check_rw(NvmeCtrl *n, NvmeRequest= *req) return status; } =20 + if (!nvme_req_is_write(req) && NVME_ERR_REC_DULBE(ns->features.err_rec= )) { + status =3D nvme_check_dulbe(n, ns, req->slba, req->nlb); + if (status) { + return status; + } + } + return NVME_SUCCESS; } =20 +static void nvme_ns_update_util(NvmeNamespace *ns, uint64_t slba, + uint32_t nlb, NvmeRequest *req) +{ + int64_t offset =3D slba >> 3; + size_t len =3D DIV_ROUND_UP(nlb, 8); + + QEMUIOVector *iov =3D g_new0(QEMUIOVector, 1); + NvmeAIO *aio =3D g_new0(NvmeAIO, 1); + + *aio =3D (NvmeAIO) { + .opc =3D NVME_AIO_OPC_WRITE, + .blk =3D ns->blk_state, + .offset =3D offset, + .len =3D len, + .payload =3D iov, + .req =3D req, + .flags =3D NVME_AIO_INTERNAL, + }; + + qemu_iovec_init(iov, 1); + qemu_iovec_add(iov, ((uint8_t *) ns->utilization) + offset, len); + + trace_pci_nvme_ns_update_util(nvme_cid(req), nvme_nsid(ns)); + + nvme_req_add_aio(req, aio); +} + +static void nvme_aio_write_cb(NvmeAIO *aio, void *opaque, int ret) +{ + NvmeRequest *req =3D aio->req; + NvmeNamespace *ns =3D req->ns; + + trace_pci_nvme_aio_write_cb(nvme_cid(req), nvme_nsid(ns), req->slba, + req->nlb); + + if (!ret && ns->blk_state) { + bitmap_set(ns->utilization, req->slba, req->nlb); + nvme_ns_update_util(ns, req->slba, req->nlb, req); + } +} + static void nvme_rw_cb(NvmeRequest *req, void *opaque) { NvmeNamespace *ns =3D req->ns; @@ -1025,7 +1089,8 @@ static void nvme_aio_cb(void *opaque, int ret) nvme_aio_destroy(aio); } =20 -static void nvme_aio_rw(NvmeNamespace *ns, NvmeAIOOp opc, NvmeRequest *req) +static void nvme_aio_rw(NvmeNamespace *ns, NvmeAIOOp opc, + NvmeAIOCompletionFunc *cb, NvmeRequest *req) { NvmeAIO *aio =3D g_new(NvmeAIO, 1); =20 @@ -1034,6 +1099,7 @@ static void nvme_aio_rw(NvmeNamespace *ns, NvmeAIOOp = opc, NvmeRequest *req) .blk =3D ns->blk, .offset =3D req->slba << nvme_ns_lbads(ns), .req =3D req, + .cb =3D cb, }; =20 if (req->qsg.sg) { @@ -1098,6 +1164,7 @@ static uint16_t nvme_write_zeroes(NvmeCtrl *n, NvmeRe= quest *req) .offset =3D offset, .len =3D count, .req =3D req, + .cb =3D nvme_aio_write_cb, }; =20 nvme_req_add_aio(req, aio); @@ -1115,10 +1182,12 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeRequest *r= eq) =20 enum BlockAcctType acct =3D BLOCK_ACCT_READ; NvmeAIOOp opc =3D NVME_AIO_OPC_READ; + NvmeAIOCompletionFunc *cb =3D NULL; =20 if (nvme_req_is_write(req)) { acct =3D BLOCK_ACCT_WRITE; opc =3D NVME_AIO_OPC_WRITE; + cb =3D nvme_aio_write_cb; } =20 req->nlb =3D le16_to_cpu(rw->nlb) + 1; @@ -1138,7 +1207,7 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeRequest *req) goto invalid; } =20 - nvme_aio_rw(ns, opc, req); + nvme_aio_rw(ns, opc, cb, req); nvme_req_set_cb(req, nvme_rw_cb, NULL); =20 return NVME_NO_COMPLETE; @@ -1737,6 +1806,8 @@ static uint16_t nvme_get_feature_timestamp(NvmeCtrl *= n, NvmeRequest *req) =20 static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req) { + NvmeNamespace *ns; + NvmeCmd *cmd =3D &req->cmd; uint32_t dw10 =3D le32_to_cpu(cmd->cdw10); uint32_t dw11 =3D le32_to_cpu(cmd->cdw11); @@ -1802,6 +1873,18 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRe= quest *req) break; } =20 + break; + case NVME_ERROR_RECOVERY: + if (!nvme_nsid_valid(n, nsid)) { + return NVME_INVALID_NSID | NVME_DNR; + } + + ns =3D nvme_ns(n, nsid); + if (unlikely(!ns)) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + result =3D cpu_to_le32(ns->features.err_rec); break; case NVME_VOLATILE_WRITE_CACHE: result =3D cpu_to_le32(n->features.vwc); @@ -1876,7 +1959,7 @@ static uint16_t nvme_set_feature_timestamp(NvmeCtrl *= n, NvmeRequest *req) =20 static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) { - NvmeNamespace *ns; + NvmeNamespace *ns =3D NULL; =20 NvmeCmd *cmd =3D &req->cmd; uint32_t dw10 =3D le32_to_cpu(cmd->cdw10); @@ -1943,6 +2026,26 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRe= quest *req) NVME_LOG_SMART_INFO); } =20 + break; + case NVME_ERROR_RECOVERY: + if (nsid =3D=3D NVME_NSID_BROADCAST) { + for (int i =3D 1; i <=3D n->num_namespaces; i++) { + ns =3D nvme_ns(n, i); + + if (!ns) { + continue; + } + + if (NVME_ID_NS_NSFEAT_DULBE(ns->id_ns.nsfeat)) { + ns->features.err_rec =3D dw11; + } + } + + break; + } + + assert(ns); + ns->features.err_rec =3D dw11; break; case NVME_VOLATILE_WRITE_CACHE: n->features.vwc =3D dw11 & 0x1; @@ -2091,6 +2194,10 @@ static void nvme_clear_ctrl(NvmeCtrl *n) } =20 blk_drain(ns->blk); + + if (ns->blk_state) { + blk_drain(ns->blk_state); + } } =20 for (i =3D 0; i < n->params.max_ioqpairs + 1; i++) { @@ -2121,6 +2228,10 @@ static void nvme_clear_ctrl(NvmeCtrl *n) } =20 blk_flush(ns->blk); + + if (ns->blk_state) { + blk_flush(ns->blk_state); + } } =20 n->bar.cc =3D 0; diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 8bf1a050497e..66187902b7cf 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -93,7 +93,8 @@ typedef enum NvmeAIOOp { } NvmeAIOOp; =20 typedef enum NvmeAIOFlags { - NVME_AIO_DMA =3D 1 << 0, + NVME_AIO_DMA =3D 1 << 0, + NVME_AIO_INTERNAL =3D 1 << 1, } NvmeAIOFlags; =20 typedef struct NvmeAIO NvmeAIO; @@ -171,6 +172,7 @@ typedef struct NvmeFeatureVal { =20 static const uint32_t nvme_feature_cap[0x100] =3D { [NVME_TEMPERATURE_THRESHOLD] =3D NVME_FEAT_CAP_CHANGE, + [NVME_ERROR_RECOVERY] =3D NVME_FEAT_CAP_CHANGE | NVME_FEAT_C= AP_NS, [NVME_VOLATILE_WRITE_CACHE] =3D NVME_FEAT_CAP_CHANGE, [NVME_NUMBER_OF_QUEUES] =3D NVME_FEAT_CAP_CHANGE, [NVME_ASYNCHRONOUS_EVENT_CONF] =3D NVME_FEAT_CAP_CHANGE, diff --git a/hw/block/trace-events b/hw/block/trace-events index cbcfbfdfbafc..c570c7d0e2a5 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -40,6 +40,8 @@ pci_nvme_map_prp(uint16_t cid, uint64_t trans_len, uint32= _t len, uint64_t prp1, pci_nvme_map_sgl(uint16_t cid, uint8_t typ, uint32_t nlb, uint64_t len) "c= id %"PRIu16" type 0x%"PRIx8" nlb %"PRIu32" len %"PRIu64"" pci_nvme_req_add_aio(uint16_t cid, void *aio, const char *blkname, uint64_= t offset, uint64_t count, const char *opc, void *req) "cid %"PRIu16" aio %p= blk \"%s\" offset %"PRIu64" count %"PRIu64" opc \"%s\" req %p" pci_nvme_aio_cb(uint16_t cid, void *aio, const char *blkname, uint64_t off= set, const char *opc, void *req) "cid %"PRIu16" aio %p blk \"%s\" offset %"= PRIu64" opc \"%s\" req %p" +pci_nvme_aio_discard_cb(uint16_t cid, uint32_t nsid, uint64_t slba, uint32= _t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" +pci_nvme_aio_write_cb(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t= nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode= ) "cid %"PRIu16" nsid %"PRIu32" sqid %"PRIu16" opc 0x%"PRIx8"" pci_nvme_admin_cmd(uint16_t cid, uint16_t sqid, uint8_t opcode) "cid %"PRI= u16" sqid %"PRIu16" opc 0x%"PRIx8"" pci_nvme_rw(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, u= int64_t count, uint64_t lba) "cid %"PRIu16" %s nsid %"PRIu32" nlb %"PRIu32"= count %"PRIu64" lba 0x%"PRIx64"" @@ -75,6 +77,7 @@ pci_nvme_mmio_read(uint64_t addr) "addr 0x%"PRIx64"" pci_nvme_mmio_write(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0= x%"PRIx64"" pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16= " new_head %"PRIu16"" pci_nvme_mmio_doorbell_sq(uint16_t sqid, uint16_t new_tail) "cqid %"PRIu16= " new_tail %"PRIu16"" +pci_nvme_ns_update_util(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %= "PRIu32"" pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, inte= rrupt mask set, data=3D0x%"PRIx64", new_mask=3D0x%"PRIx64"" pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, inte= rrupt mask clr, data=3D0x%"PRIx64", new_mask=3D0x%"PRIx64"" pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=3D0= x%"PRIx64"" diff --git a/include/block/nvme.h b/include/block/nvme.h index 6e133469cf28..2a9c5e95bfd2 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -675,6 +675,7 @@ enum NvmeStatusCodes { NVME_E2E_REF_ERROR =3D 0x0284, NVME_CMP_FAILURE =3D 0x0285, NVME_ACCESS_DENIED =3D 0x0286, + NVME_DULB =3D 0x0287, NVME_MORE =3D 0x2000, NVME_DNR =3D 0x4000, NVME_NO_COMPLETE =3D 0xffff, @@ -890,6 +891,9 @@ enum NvmeIdCtrlLpa { #define NVME_AEC_NS_ATTR(aec) ((aec >> 8) & 0x1) #define NVME_AEC_FW_ACTIVATION(aec) ((aec >> 9) & 0x1) =20 +#define NVME_ERR_REC_TLER(err_rec) (err_rec & 0xffff) +#define NVME_ERR_REC_DULBE(err_rec) (err_rec & 0x10000) + enum NvmeFeatureIds { NVME_ARBITRATION =3D 0x1, NVME_POWER_MANAGEMENT =3D 0x2, @@ -1007,6 +1011,7 @@ enum { =20 =20 #define NVME_ID_NS_NSFEAT_THIN(nsfeat) ((nsfeat & 0x1)) +#define NVME_ID_NS_NSFEAT_DULBE(nsfeat) ((nsfeat >> 2) & 0x1) #define NVME_ID_NS_FLBAS_EXTENDED(flbas) ((flbas >> 4) & 0x1) #define NVME_ID_NS_FLBAS_INDEX(flbas) ((flbas & 0xf)) #define NVME_ID_NS_MC_SEPARATE(mc) ((mc >> 1) & 0x1) --=20 2.27.0