diff --git a/CHANGELOG.md b/CHANGELOG.md index 00d82cf33..b127db99f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,11 @@ New function `spdk_env_get_main_core` was added. New `spdk_nvmf_request_copy_to/from_buf()` APIs have been added, which support iovecs, unlike the deprecated `spdk_nvmf_request_get_data()`. +### nvme + +New API `spdk_nvme_ns_get_format_index` was added to calculate the exact format index, that +was used to format the namespace. + ## v23.01 ### accel diff --git a/examples/nvme/identify/identify.c b/examples/nvme/identify/identify.c index 6f2e4bf36..5c2ed4349 100644 --- a/examples/nvme/identify/identify.c +++ b/examples/nvme/identify/identify.c @@ -791,7 +791,7 @@ get_and_print_zns_zone_report(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *q uint64_t handled_zones = 0; uint64_t slba = 0; size_t zdes = 0; - uint32_t zds, zrs; + uint32_t zds, zrs, format_index; int rc = 0; outstanding_commands = 0; @@ -801,7 +801,9 @@ get_and_print_zns_zone_report(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *q zrs = sizeof(struct spdk_nvme_zns_zone_report); zds = sizeof(struct spdk_nvme_zns_zone_desc); - zdes = nsdata_zns->lbafe[nsdata->flbas.format].zdes * 64; + + format_index = spdk_nvme_ns_get_format_index(nsdata); + zdes = nsdata_zns->lbafe[format_index].zdes * 64; report_bufsize = spdk_nvme_ns_get_max_io_xfer_size(ns); report_buf = calloc(1, report_bufsize); @@ -964,7 +966,7 @@ print_namespace(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns) uint32_t i; uint32_t flags; char uuid_str[SPDK_UUID_STRING_LEN]; - uint32_t blocksize; + uint32_t blocksize, format_index; enum spdk_nvme_dealloc_logical_block_read_value dlfeat_read_value; cdata = spdk_nvme_ctrlr_get_data(ctrlr); @@ -1017,13 +1019,14 @@ print_namespace(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns) printf("Protection Information Transferred as: %s\n", nsdata->dps.md_start ? "First 8 Bytes" : "Last 8 Bytes"); } - if (nsdata->lbaf[nsdata->flbas.format].ms > 0) { + format_index = spdk_nvme_ns_get_format_index(nsdata); + if (nsdata->lbaf[format_index].ms > 0) { printf("Metadata Transferred as: %s\n", nsdata->flbas.extended ? "Extended Data LBA" : "Separate Metadata Buffer"); } printf("Namespace Sharing Capabilities: %s\n", nsdata->nmic.can_share ? "Multiple Controllers" : "Private"); - blocksize = 1 << nsdata->lbaf[nsdata->flbas.format].lbads; + blocksize = 1 << nsdata->lbaf[format_index].lbads; printf("Size (in LBAs): %lld (%lldGiB)\n", (long long)nsdata->nsze, (long long)nsdata->nsze * blocksize / 1024 / 1024 / 1024); @@ -1103,7 +1106,7 @@ print_namespace(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns) printf("Number of LBA Formats: %d\n", nsdata->nlbaf + 1); printf("Current LBA Format: LBA Format #%02d\n", - nsdata->flbas.format); + format_index); for (i = 0; i <= nsdata->nlbaf; i++) { printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n", i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms); diff --git a/examples/nvme/nvme_manage/nvme_manage.c b/examples/nvme/nvme_manage/nvme_manage.c index 196e72ed8..7de09fd9d 100644 --- a/examples/nvme/nvme_manage/nvme_manage.c +++ b/examples/nvme/nvme_manage/nvme_manage.c @@ -161,8 +161,10 @@ display_namespace(struct spdk_nvme_ns *ns) { const struct spdk_nvme_ns_data *nsdata; uint32_t i; + uint32_t format_index; nsdata = spdk_nvme_ns_get_data(ns); + format_index = spdk_nvme_ns_get_format_index(nsdata); printf("Namespace ID:%d\n", spdk_nvme_ns_get_id(ns)); @@ -182,7 +184,7 @@ display_namespace(struct spdk_nvme_ns *ns) } printf("Number of LBA Formats: %d\n", nsdata->nlbaf + 1); printf("Current LBA Format: LBA Format #%02d\n", - nsdata->flbas.format); + format_index); for (i = 0; i <= nsdata->nlbaf; i++) printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n", i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms); @@ -467,7 +469,8 @@ ns_manage_add(struct dev *device, uint64_t ns_size, uint64_t ns_capacity, int ns ndata->nsze = ns_size; ndata->ncap = ns_capacity; - ndata->flbas.format = ns_lbasize; + ndata->flbas.format = ns_lbasize & 0xF; + ndata->flbas.msb_format = (ns_lbasize >> 4) & 0x3; if (SPDK_NVME_FMT_NVM_PROTECTION_DISABLE != ns_dps_type) { ndata->dps.pit = ns_dps_type; ndata->dps.md_start = ns_dps_location; @@ -501,11 +504,12 @@ nvme_manage_format(struct dev *device, int ns_id, int ses, int pi, int pil, int int ret = 0; struct spdk_nvme_format format = {}; - format.lbaf = lbaf; + format.lbaf = lbaf & 0xF; format.ms = ms; format.pi = pi; format.pil = pil; format.ses = ses; + format.lbafu = (lbaf >> 4) & 0x3; ret = spdk_nvme_ctrlr_format(device->ctrlr, ns_id, &format); if (ret) { fprintf(stdout, "nvme format: Failed\n"); diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index dd0410307..83eff5779 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -2851,6 +2851,18 @@ enum spdk_nvme_pi_type spdk_nvme_ns_get_pi_type(struct spdk_nvme_ns *ns); */ uint32_t spdk_nvme_ns_get_md_size(struct spdk_nvme_ns *ns); +/** + * Get the format index of the given namespace. + * + * This function is thread safe and can be called at any point while the controller + * is attached to the SPDK NVMe driver. + * + * \param nsdata pointer to the NVMe namespace data. + * + * \return the format index of the given namespace. + */ +uint32_t spdk_nvme_ns_get_format_index(const struct spdk_nvme_ns_data *nsdata); + /** * Check whether if the namespace can support extended LBA when end-to-end data * protection enabled. diff --git a/include/spdk/nvme_spec.h b/include/spdk/nvme_spec.h index 62694946a..759bf7de1 100644 --- a/include/spdk/nvme_spec.h +++ b/include/spdk/nvme_spec.h @@ -2569,9 +2569,12 @@ struct spdk_nvme_ns_data { /** formatted lba size */ struct { - uint8_t format : 4; - uint8_t extended : 1; - uint8_t reserved2 : 3; + /** LSB for Format index */ + uint8_t format : 4; + uint8_t extended : 1; + /** MSB for Format index, to be ignored if nlbaf <= 16 */ + uint8_t msb_format : 2; + uint8_t reserved2 : 1; } flbas; /** metadata capabilities */ @@ -2772,9 +2775,7 @@ struct spdk_nvme_ns_data { uint32_t rp : 2; uint32_t reserved6 : 6; - } lbaf[16]; - - uint8_t reserved6[192]; + } lbaf[64]; uint8_t vendor_specific[3712]; }; @@ -2835,9 +2836,7 @@ struct spdk_nvme_zns_ns_data { uint64_t zdes : 8; uint64_t reserved15 : 56; - } lbafe[16]; - - uint8_t reserved3072[768]; + } lbafe[64]; uint8_t vendor_specific[256]; }; @@ -3545,13 +3544,21 @@ enum spdk_nvme_metadata_setting { SPDK_NVME_FMT_NVM_METADATA_TRANSFER_AS_LBA = 0x1, }; +/* Format - Command Dword 10 */ struct spdk_nvme_format { + /* LBA format lower (LSB 4 bits of format index), also called lbafl in 2.0 spec */ uint32_t lbaf : 4; + /* Metadata settings, also called mset in 2.0 spec */ uint32_t ms : 1; + /* Protection information */ uint32_t pi : 3; + /* Protection information location */ uint32_t pil : 1; + /* Secure erase settings */ uint32_t ses : 3; - uint32_t reserved : 20; + /* LBA format upper (MSB 2 bits of format index) */ + uint32_t lbafu : 2; + uint32_t reserved : 18; }; SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_format) == 4, "Incorrect size"); diff --git a/lib/nvme/nvme_ns.c b/lib/nvme/nvme_ns.c index 6fe3e6793..03f7a0253 100644 --- a/lib/nvme/nvme_ns.c +++ b/lib/nvme/nvme_ns.c @@ -21,15 +21,17 @@ void nvme_ns_set_identify_data(struct spdk_nvme_ns *ns) { struct spdk_nvme_ns_data *nsdata; + uint32_t format_index; nsdata = _nvme_ns_get_data(ns); ns->flags = 0x0000; + format_index = spdk_nvme_ns_get_format_index(nsdata); - ns->sector_size = 1 << nsdata->lbaf[nsdata->flbas.format].lbads; + ns->sector_size = 1 << nsdata->lbaf[format_index].lbads; ns->extended_lba_size = ns->sector_size; - ns->md_size = nsdata->lbaf[nsdata->flbas.format].ms; + ns->md_size = nsdata->lbaf[format_index].ms; if (nsdata->flbas.extended) { ns->flags |= SPDK_NVME_NS_EXTENDED_LBA_SUPPORTED; ns->extended_lba_size += ns->md_size; @@ -80,7 +82,7 @@ nvme_ns_set_identify_data(struct spdk_nvme_ns *ns) } ns->pi_type = SPDK_NVME_FMT_NVM_PROTECTION_DISABLE; - if (nsdata->lbaf[nsdata->flbas.format].ms && nsdata->dps.pit) { + if (nsdata->lbaf[format_index].ms && nsdata->dps.pit) { ns->flags |= SPDK_NVME_NS_DPS_PI_SUPPORTED; ns->pi_type = nsdata->dps.pit; } @@ -318,6 +320,16 @@ spdk_nvme_ns_get_md_size(struct spdk_nvme_ns *ns) return ns->md_size; } +uint32_t +spdk_nvme_ns_get_format_index(const struct spdk_nvme_ns_data *nsdata) +{ + if (nsdata->nlbaf < 16) { + return nsdata->flbas.format; + } else { + return ((nsdata->flbas.msb_format << 4) + nsdata->flbas.format); + } +} + const struct spdk_nvme_ns_data * spdk_nvme_ns_get_data(struct spdk_nvme_ns *ns) { diff --git a/lib/nvme/nvme_zns.c b/lib/nvme/nvme_zns.c index cec85e18d..fcff2d7ff 100644 --- a/lib/nvme/nvme_zns.c +++ b/lib/nvme/nvme_zns.c @@ -17,8 +17,11 @@ spdk_nvme_zns_ns_get_zone_size_sectors(struct spdk_nvme_ns *ns) { const struct spdk_nvme_zns_ns_data *nsdata_zns = spdk_nvme_zns_ns_get_data(ns); const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns); + uint32_t format_index; - return nsdata_zns->lbafe[nsdata->flbas.format].zsze; + format_index = spdk_nvme_ns_get_format_index(nsdata); + + return nsdata_zns->lbafe[format_index].zsze; } uint64_t diff --git a/lib/nvme/spdk_nvme.map b/lib/nvme/spdk_nvme.map index b14de0537..5e46d8fa3 100644 --- a/lib/nvme/spdk_nvme.map +++ b/lib/nvme/spdk_nvme.map @@ -136,6 +136,7 @@ spdk_nvme_ns_get_size; spdk_nvme_ns_get_pi_type; spdk_nvme_ns_get_md_size; + spdk_nvme_ns_get_format_index; spdk_nvme_ns_supports_extended_lba; spdk_nvme_ns_supports_compare; spdk_nvme_ns_get_dealloc_logical_block_read_value; diff --git a/lib/nvmf/ctrlr.c b/lib/nvmf/ctrlr.c index 8bb7d88c5..ce20b60f0 100644 --- a/lib/nvmf/ctrlr.c +++ b/lib/nvmf/ctrlr.c @@ -2618,7 +2618,7 @@ spdk_nvmf_ctrlr_identify_ns(struct spdk_nvmf_ctrlr *ctrlr, { struct spdk_nvmf_subsystem *subsystem = ctrlr->subsys; struct spdk_nvmf_ns *ns; - uint32_t max_num_blocks; + uint32_t max_num_blocks, format_index; enum spdk_nvme_ana_state ana_state; ns = _nvmf_subsystem_get_ns_safe(subsystem, cmd->nsid, rsp); @@ -2629,9 +2629,12 @@ spdk_nvmf_ctrlr_identify_ns(struct spdk_nvmf_ctrlr *ctrlr, nvmf_bdev_ctrlr_identify_ns(ns, nsdata, ctrlr->dif_insert_or_strip); assert(ctrlr->admin_qpair); + + format_index = spdk_nvme_ns_get_format_index(nsdata); + /* Due to bug in the Linux kernel NVMe driver we have to set noiob no larger than mdts */ max_num_blocks = ctrlr->admin_qpair->transport->opts.max_io_size / - (1U << nsdata->lbaf[nsdata->flbas.format].lbads); + (1U << nsdata->lbaf[format_index].lbads); if (nsdata->noiob > max_num_blocks) { nsdata->noiob = max_num_blocks; } diff --git a/lib/nvmf/ctrlr_bdev.c b/lib/nvmf/ctrlr_bdev.c index 27cb28d7d..d9bc1fbc5 100644 --- a/lib/nvmf/ctrlr_bdev.c +++ b/lib/nvmf/ctrlr_bdev.c @@ -129,6 +129,7 @@ nvmf_bdev_ctrlr_identify_ns(struct spdk_nvmf_ns *ns, struct spdk_nvme_ns_data *n nsdata->nuse = num_blocks; nsdata->nlbaf = 0; nsdata->flbas.format = 0; + nsdata->flbas.msb_format = 0; nsdata->nacwu = spdk_bdev_get_acwu(bdev) - 1; /* nacwu is 0-based */ if (!dif_insert_or_strip) { nsdata->lbaf[0].ms = spdk_bdev_get_md_size(bdev); diff --git a/test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c b/test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c index e83a87526..543e0d0a1 100644 --- a/test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c +++ b/test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c @@ -253,6 +253,7 @@ test_nvme_ns_set_identify_data(void) ns.nsdata.nsrescap.raw = 1; ns.nsdata.dps.pit = SPDK_NVME_FMT_NVM_PROTECTION_TYPE1; ns.nsdata.flbas.format = 0; + ns.nsdata.flbas.msb_format = 0; ns.nsdata.lbaf[0].lbads = 9; ns.nsdata.lbaf[0].ms = 8; diff --git a/test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c b/test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c index bc06d3ade..4807f9bfb 100644 --- a/test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c +++ b/test/unit/lib/nvmf/ctrlr.c/ctrlr_ut.c @@ -210,6 +210,9 @@ DEFINE_STUB(spdk_bdev_get_max_open_zones, uint32_t, (const struct spdk_bdev *bde DEFINE_STUB(spdk_bdev_get_zone_size, uint64_t, (const struct spdk_bdev *bdev), ZONE_SIZE); DEFINE_STUB(spdk_bdev_is_zoned, bool, (const struct spdk_bdev *bdev), false); +DEFINE_STUB(spdk_nvme_ns_get_format_index, uint32_t, + (const struct spdk_nvme_ns_data *nsdata), 0); + int spdk_nvmf_qpair_disconnect(struct spdk_nvmf_qpair *qpair, nvmf_qpair_disconnect_cb cb_fn, void *ctx) { @@ -229,6 +232,7 @@ nvmf_bdev_ctrlr_identify_ns(struct spdk_nvmf_ns *ns, struct spdk_nvme_ns_data *n nsdata->nuse = num_blocks; nsdata->nlbaf = 0; nsdata->flbas.format = 0; + nsdata->flbas.msb_format = 0; nsdata->lbaf[0].lbads = spdk_u32log2(512); } diff --git a/test/unit/lib/nvmf/ctrlr_bdev.c/ctrlr_bdev_ut.c b/test/unit/lib/nvmf/ctrlr_bdev.c/ctrlr_bdev_ut.c index b157e58c4..6ef64226c 100644 --- a/test/unit/lib/nvmf/ctrlr_bdev.c/ctrlr_bdev_ut.c +++ b/test/unit/lib/nvmf/ctrlr_bdev.c/ctrlr_bdev_ut.c @@ -488,6 +488,7 @@ test_nvmf_bdev_ctrlr_identify_ns(void) CU_ASSERT(nsdata.nuse == 10); CU_ASSERT(nsdata.nlbaf == 0); CU_ASSERT(nsdata.flbas.format == 0); + CU_ASSERT(nsdata.flbas.msb_format == 0); CU_ASSERT(nsdata.nacwu == 0); CU_ASSERT(nsdata.lbaf[0].lbads == spdk_u32log2(4096)); CU_ASSERT(nsdata.lbaf[0].ms == 512); @@ -516,6 +517,7 @@ test_nvmf_bdev_ctrlr_identify_ns(void) CU_ASSERT(nsdata.nuse == 10); CU_ASSERT(nsdata.nlbaf == 0); CU_ASSERT(nsdata.flbas.format == 0); + CU_ASSERT(nsdata.flbas.msb_format == 0); CU_ASSERT(nsdata.nacwu == 0); CU_ASSERT(nsdata.lbaf[0].lbads == spdk_u32log2(4096)); CU_ASSERT(nsdata.noiob == SPDK_BDEV_IO_NUM_CHILD_IOV); diff --git a/test/unit/lib/nvmf/tcp.c/tcp_ut.c b/test/unit/lib/nvmf/tcp.c/tcp_ut.c index 7253dc4b0..ce17400f1 100644 --- a/test/unit/lib/nvmf/tcp.c/tcp_ut.c +++ b/test/unit/lib/nvmf/tcp.c/tcp_ut.c @@ -235,6 +235,9 @@ DEFINE_STUB(spdk_bdev_get_max_open_zones, uint32_t, DEFINE_STUB(spdk_bdev_is_zoned, bool, (const struct spdk_bdev *bdev), false); DEFINE_STUB(spdk_bdev_get_zone_size, uint64_t, (const struct spdk_bdev *bdev), 0); +DEFINE_STUB(spdk_nvme_ns_get_format_index, uint32_t, + (const struct spdk_nvme_ns_data *nsdata), 0); + struct spdk_io_channel * spdk_accel_get_io_channel(void) { @@ -339,6 +342,7 @@ nvmf_bdev_ctrlr_identify_ns(struct spdk_nvmf_ns *ns, struct spdk_nvme_ns_data *n nsdata->nuse = num_blocks; nsdata->nlbaf = 0; nsdata->flbas.format = 0; + nsdata->flbas.msb_format = 0; nsdata->lbaf[0].lbads = spdk_u32log2(512); }