summaryrefslogtreecommitdiffstats
path: root/hw/block/nvme-ns.c
diff options
context:
space:
mode:
authorMinwoo Im2021-02-12 12:25:08 +0100
committerKlaus Jensen2021-03-18 12:34:52 +0100
commit6a674bc295527c9acb1404b85be8d225b5bbac9d (patch)
tree4e8755b0ee7385993ae00f7c0c0e0714a6f9e9df /hw/block/nvme-ns.c
parenthw/block/nvme: add non-mdts command size limit for verify (diff)
downloadqemu-6a674bc295527c9acb1404b85be8d225b5bbac9d.tar.gz
qemu-6a674bc295527c9acb1404b85be8d225b5bbac9d.tar.xz
qemu-6a674bc295527c9acb1404b85be8d225b5bbac9d.zip
hw/block/nvme: support multiple lba formats
This patch introduces multiple LBA formats supported with the typical logical block sizes of 512 bytes and 4096 bytes as well as metadata sizes of 0, 8, 16 and 64 bytes. The format will be chosed based on the lbads and ms parameters of the nvme-ns device. Signed-off-by: Minwoo Im <minwoo.im@samsung.com> [k.jensen: resurrected and rebased] Signed-off-by: Klaus Jensen <k.jensen@samsung.com> Reviewed-by: Keith Busch <kbusch@kernel.org>
Diffstat (limited to 'hw/block/nvme-ns.c')
-rw-r--r--hw/block/nvme-ns.c60
1 files changed, 52 insertions, 8 deletions
diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c
index a082a7004d..00e8f6af21 100644
--- a/hw/block/nvme-ns.c
+++ b/hw/block/nvme-ns.c
@@ -36,13 +36,15 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
{
BlockDriverInfo bdi;
NvmeIdNs *id_ns = &ns->id_ns;
- int lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas);
int npdg, nlbas;
+ uint8_t ds;
+ uint16_t ms;
+ int i;
ns->id_ns.dlfeat = 0x1;
- id_ns->lbaf[lba_index].ds = 31 - clz32(ns->blkconf.logical_block_size);
- id_ns->lbaf[lba_index].ms = ns->params.ms;
+ ds = 31 - clz32(ns->blkconf.logical_block_size);
+ ms = ns->params.ms;
if (ns->params.ms) {
id_ns->mc = 0x3;
@@ -53,8 +55,47 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
id_ns->dpc = 0x1f;
id_ns->dps = ((ns->params.pil & 0x1) << 3) | ns->params.pi;
+
+ NvmeLBAF lbaf[16] = {
+ [0] = { .ds = 9 },
+ [1] = { .ds = 9, .ms = 8 },
+ [2] = { .ds = 9, .ms = 16 },
+ [3] = { .ds = 9, .ms = 64 },
+ [4] = { .ds = 12 },
+ [5] = { .ds = 12, .ms = 8 },
+ [6] = { .ds = 12, .ms = 16 },
+ [7] = { .ds = 12, .ms = 64 },
+ };
+
+ memcpy(&id_ns->lbaf, &lbaf, sizeof(lbaf));
+ id_ns->nlbaf = 7;
+ } else {
+ NvmeLBAF lbaf[16] = {
+ [0] = { .ds = 9 },
+ [1] = { .ds = 12 },
+ };
+
+ memcpy(&id_ns->lbaf, &lbaf, sizeof(lbaf));
+ id_ns->nlbaf = 1;
+ }
+
+ for (i = 0; i <= id_ns->nlbaf; i++) {
+ NvmeLBAF *lbaf = &id_ns->lbaf[i];
+ if (lbaf->ds == ds) {
+ if (lbaf->ms == ms) {
+ id_ns->flbas |= i;
+ goto lbaf_found;
+ }
+ }
}
+ /* add non-standard lba format */
+ id_ns->nlbaf++;
+ id_ns->lbaf[id_ns->nlbaf].ds = ds;
+ id_ns->lbaf[id_ns->nlbaf].ms = ms;
+ id_ns->flbas |= id_ns->nlbaf;
+
+lbaf_found:
nlbas = nvme_ns_nlbas(ns);
id_ns->nsze = cpu_to_le64(nlbas);
@@ -244,9 +285,10 @@ static void nvme_ns_zoned_init_state(NvmeNamespace *ns)
}
}
-static void nvme_ns_init_zoned(NvmeNamespace *ns, int lba_index)
+static void nvme_ns_init_zoned(NvmeNamespace *ns)
{
NvmeIdNsZoned *id_ns_z;
+ int i;
nvme_ns_zoned_init_state(ns);
@@ -258,9 +300,11 @@ static void nvme_ns_init_zoned(NvmeNamespace *ns, int lba_index)
id_ns_z->zoc = 0;
id_ns_z->ozcs = ns->params.cross_zone_read ? 0x01 : 0x00;
- id_ns_z->lbafe[lba_index].zsze = cpu_to_le64(ns->zone_size);
- id_ns_z->lbafe[lba_index].zdes =
- ns->params.zd_extension_size >> 6; /* Units of 64B */
+ for (i = 0; i <= ns->id_ns.nlbaf; i++) {
+ id_ns_z->lbafe[i].zsze = cpu_to_le64(ns->zone_size);
+ id_ns_z->lbafe[i].zdes =
+ ns->params.zd_extension_size >> 6; /* Units of 64B */
+ }
ns->csi = NVME_CSI_ZONED;
ns->id_ns.nsze = cpu_to_le64(ns->num_zones * ns->zone_size);
@@ -367,7 +411,7 @@ int nvme_ns_setup(NvmeNamespace *ns, Error **errp)
if (nvme_ns_zoned_check_calc_geometry(ns, errp) != 0) {
return -1;
}
- nvme_ns_init_zoned(ns, 0);
+ nvme_ns_init_zoned(ns);
}
return 0;