diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dd1841a4..55f965e82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,10 @@ with new `spdk_bdev_module_fini_start_done` API. Deprecated `spdk_bdev_module_finish_done()` API, which will be removed in SPDK 22.01. Bdev modules should use `spdk_bdev_module_fini_done()` instead. +The `ocssd` bdev has been removed. The Open Channel specification has been largely superceded by +zoned namespaces, few if any devices have been brough to market, and there is little reason to +continue to support this. OCSSD support in the nvme driver will remain for now. + ### dma A new library, lib/dma, has been added. This library provides the necessary infrastructure for diff --git a/doc/ftl.md b/doc/ftl.md index 95b2ae11d..0e2985176 100644 --- a/doc/ftl.md +++ b/doc/ftl.md @@ -150,62 +150,6 @@ Both interfaces require the same arguments which are described by the `--help` o - base bdev's name (base bdev must implement bdev_zone API) - UUID of the FTL device (if the FTL is to be restored from the SSD) -### FTL usage with OCSSD nvme bdev {#ftl_ocssd} - -This option requires an Open Channel SSD, which can be emulated using QEMU. - -The QEMU with the patches providing Open Channel support can be found on the SPDK's QEMU fork -on [spdk-3.0.0](https://github.com/spdk/qemu/tree/spdk-3.0.0) branch. - -## Configuring QEMU {#ftl_qemu_config} - -To emulate an Open Channel device, QEMU expects parameters describing the characteristics and -geometry of the SSD: - -- `serial` - serial number, -- `lver` - version of the OCSSD standard (0 - disabled, 1 - "1.2", 2 - "2.0"), libftl only supports - 2.0, -- `lba_index` - default LBA format. Possible values can be found in the table below (libftl only supports lba_index >= 3): -- `lnum_ch` - number of groups, -- `lnum_lun` - number of parallel units -- `lnum_pln` - number of planes (logical blocks from all planes constitute a chunk) -- `lpgs_per_blk` - number of pages (smallest programmable unit) per chunk -- `lsecs_per_pg` - number of sectors in a page -- `lblks_per_pln` - number of chunks in a parallel unit -- `laer_thread_sleep` - timeout in ms between asynchronous events requesting the host to relocate - the data based on media feedback -- `lmetadata` - metadata file - - |lba_index| data| metadata| - |---------|-----|---------| - | 0 | 512B| 0B | - | 1 | 512B| 8B | - | 2 | 512B| 16B | - | 3 |4096B| 0B | - | 4 |4096B| 64B | - | 5 |4096B| 128B | - | 6 |4096B| 16B | - -For more detailed description of the available options, consult the `hw/block/nvme.c` file in -the QEMU repository. - -Example: - -``` -$ /path/to/qemu [OTHER PARAMETERS] -drive format=raw,file=/path/to/data/file,if=none,id=myocssd0 - -device nvme,drive=myocssd0,serial=deadbeef,lver=2,lba_index=3,lnum_ch=1,lnum_lun=8,lnum_pln=4, - lpgs_per_blk=1536,lsecs_per_pg=4,lblks_per_pln=512,lmetadata=/path/to/md/file -``` - -In the above example, a device is created with 1 channel, 8 parallel units, 512 chunks per parallel -unit, 24576 (`lnum_pln` * `lpgs_per_blk` * `lsecs_per_pg`) logical blocks in each chunk with logical -block being 4096B. Therefore the data file needs to be at least 384G `(8 * 512 * 24576 * 4096B)` -of size and can be created with the following command: - -``` -fallocate -l 384G /path/to/data/file -``` - ## Configuring SPDK {#ftl_spdk_config} To verify that the drive is emulated correctly, one can check the output of the NVMe identify app @@ -226,40 +170,6 @@ Model Number: QEMU NVMe Ctrl ... other info ... -Namespace OCSSD Geometry -======================= -OC version: maj:2 min:0 - -... other info ... - -Groups (channels): 1 -PUs (LUNs) per group: 8 -Chunks per LUN: 512 -Logical blks per chunk: 24576 - -... other info ... - -``` - -In order to create FTL on top Open Channel SSD, the following steps are required: - -1) Attach OCSSD NVMe controller -2) Create OCSSD bdev on the controller attached in step 1 (user could specify parallel unit range -and create multiple OCSSD bdevs on single OCSSD NVMe controller) -3) Create FTL bdev on top of bdev created in step 2 - -Example: -``` -$ scripts/rpc.py bdev_nvme_attach_controller -b nvme0 -a 00:0a.0 -t pcie - -$ scripts/rpc.py bdev_ocssd_create -c nvme0 -b nvme0n1 - nvme0n1 - -$ scripts/rpc.py bdev_ftl_create -b ftl0 -d nvme0n1 -{ - "name": "ftl0", - "uuid": "3b469565-1fa5-4bfb-8341-747ec9fca9b9" -} ``` ## FTL usage with zone block bdev {#ftl_zone_block} diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 90f7bbc49..d41812dc6 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -4137,79 +4137,6 @@ Example response: } ~~~ -### bdev_ocssd_create {#rpc_bdev_ocssd_create} - -Create Open Channel zoned bdev on specified Open Channel controller. - -#### Parameters - -Name | Optional | Type | Description ------------------------ | -------- | ----------- | ----------- -ctrlr_name | Required | string | OC NVMe controller -name | Required | string | Bdev name to create -nsid | Optional | string | namespace ID - -#### Example - -Example request: - -~~~ -{ - "jsonrpc": "2.0", - "method": "bdev_ocssd_create", - "id": 1, - "params": { - "ctrlr_name": "nvme0", - "bdev_name": "nvme0n1" - } -} -~~~ - -Example response: - -~~~ -{ - "jsonrpc": "2.0", - "id": 1, - "result": true -} -~~~ - -### bdev_ocssd_delete {#rpc_bdev_ocssd_delete} - -Delete Open Channel zoned bdev. - -#### Parameters - -Name | Optional | Type | Description ------------------------ | -------- | ----------- | ----------- -name | Required | string | Bdev name to delete - -#### Example - -Example request: - -~~~ -{ - "jsonrpc": "2.0", - "method": "bdev_ocssd_delete", - "id": 1, - "params": { - "name": "nvme0n1" - } -} -~~~ - -Example response: - -~~~ -{ - "jsonrpc": "2.0", - "id": 1, - "result": true -} -~~~ - ### bdev_pmem_create_pool {#rpc_bdev_pmem_create_pool} Create a @ref bdev_config_pmem blk pool file. It is equivalent of following `pmempool create` command: diff --git a/module/bdev/nvme/Makefile b/module/bdev/nvme/Makefile index 85145d9f1..9198b49b8 100644 --- a/module/bdev/nvme/Makefile +++ b/module/bdev/nvme/Makefile @@ -37,7 +37,7 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk SO_VER := 4 SO_MINOR := 0 -C_SRCS = bdev_nvme.c bdev_nvme_rpc.c nvme_rpc.c common.c bdev_ocssd.c bdev_ocssd_rpc.c +C_SRCS = bdev_nvme.c bdev_nvme_rpc.c nvme_rpc.c common.c C_SRCS-$(CONFIG_NVME_CUSE) += bdev_nvme_cuse_rpc.c ifeq ($(OS),Linux) diff --git a/module/bdev/nvme/bdev_nvme.c b/module/bdev/nvme/bdev_nvme.c index 667dc873f..749525ce7 100644 --- a/module/bdev/nvme/bdev_nvme.c +++ b/module/bdev/nvme/bdev_nvme.c @@ -35,7 +35,6 @@ #include "spdk/stdinc.h" #include "bdev_nvme.h" -#include "bdev_ocssd.h" #include "spdk/accel_engine.h" #include "spdk/config.h" @@ -203,7 +202,6 @@ static void nvme_ctrlr_populate_standard_namespace(struct nvme_ctrlr *nvme_ctrlr static populate_namespace_fn g_populate_namespace_fn[] = { NULL, nvme_ctrlr_populate_standard_namespace, - bdev_ocssd_populate_namespace, }; typedef void (*depopulate_namespace_fn)(struct nvme_ns *nvme_ns); @@ -212,7 +210,6 @@ static void nvme_ctrlr_depopulate_standard_namespace(struct nvme_ns *nvme_ns); static depopulate_namespace_fn g_depopulate_namespace_fn[] = { NULL, nvme_ctrlr_depopulate_standard_namespace, - bdev_ocssd_depopulate_namespace, }; typedef void (*config_json_namespace_fn)(struct spdk_json_write_ctx *w, @@ -223,7 +220,6 @@ static void nvme_ctrlr_config_json_standard_namespace(struct spdk_json_write_ctx static config_json_namespace_fn g_config_json_namespace_fn[] = { NULL, nvme_ctrlr_config_json_standard_namespace, - bdev_ocssd_namespace_config_json, }; struct spdk_nvme_qpair * @@ -1083,13 +1079,6 @@ bdev_nvme_create_ctrlr_channel_cb(void *io_device, void *ctx_buf) TAILQ_INIT(&ctrlr_ch->pending_resets); - if (spdk_nvme_ctrlr_is_ocssd_supported(nvme_ctrlr->ctrlr)) { - rc = bdev_ocssd_create_io_channel(ctrlr_ch); - if (rc != 0) { - goto err_ocssd_ch; - } - } - ctrlr_ch->ctrlr = nvme_ctrlr; rc = bdev_nvme_create_qpair(ctrlr_ch); @@ -1100,10 +1089,6 @@ bdev_nvme_create_ctrlr_channel_cb(void *io_device, void *ctx_buf) return 0; err_qpair: - if (ctrlr_ch->ocssd_ch) { - bdev_ocssd_destroy_io_channel(ctrlr_ch); - } -err_ocssd_ch: spdk_put_io_channel(pg_ch); return rc; @@ -1116,10 +1101,6 @@ bdev_nvme_destroy_ctrlr_channel_cb(void *io_device, void *ctx_buf) assert(ctrlr_ch->group != NULL); - if (ctrlr_ch->ocssd_ch != NULL) { - bdev_ocssd_destroy_io_channel(ctrlr_ch); - } - bdev_nvme_destroy_qpair(ctrlr_ch); spdk_put_io_channel(spdk_io_channel_from_ctx(ctrlr_ch->group)); @@ -1852,11 +1833,7 @@ nvme_ctrlr_populate_namespaces(struct nvme_ctrlr *nvme_ctrlr, if (!nvme_ns->populated && ns_is_active) { nvme_ns->id = nsid; nvme_ns->ctrlr = nvme_ctrlr; - if (spdk_nvme_ctrlr_is_ocssd_supported(ctrlr)) { - nvme_ns->type = NVME_NS_OCSSD; - } else { - nvme_ns->type = NVME_NS_STANDARD; - } + nvme_ns->type = NVME_NS_STANDARD; nvme_ns->bdev = NULL; @@ -1996,10 +1973,6 @@ aer_cb(void *arg, const struct spdk_nvme_cpl *cpl) if ((event.bits.async_event_type == SPDK_NVME_ASYNC_EVENT_TYPE_NOTICE) && (event.bits.async_event_info == SPDK_NVME_ASYNC_EVENT_NS_ATTR_CHANGED)) { nvme_ctrlr_populate_namespaces(nvme_ctrlr, NULL); - } else if ((event.bits.async_event_type == SPDK_NVME_ASYNC_EVENT_TYPE_VENDOR) && - (event.bits.log_page_identifier == SPDK_OCSSD_LOG_CHUNK_NOTIFICATION) && - spdk_nvme_ctrlr_is_ocssd_supported(nvme_ctrlr->ctrlr)) { - bdev_ocssd_handle_chunk_notification(nvme_ctrlr); } else if ((event.bits.async_event_type == SPDK_NVME_ASYNC_EVENT_TYPE_NOTICE) && (event.bits.async_event_info == SPDK_NVME_ASYNC_EVENT_ANA_CHANGE)) { nvme_ctrlr_read_ana_log_page(nvme_ctrlr); @@ -2172,11 +2145,9 @@ nvme_ctrlr_create(struct spdk_nvme_ctrlr *ctrlr, } if (spdk_nvme_ctrlr_is_ocssd_supported(ctrlr)) { - rc = bdev_ocssd_init_ctrlr(nvme_ctrlr); - if (spdk_unlikely(rc != 0)) { - SPDK_ERRLOG("Unable to initialize OCSSD controller\n"); - goto err; - } + SPDK_ERRLOG("OCSSDs are not supported"); + rc = -ENOTSUP; + goto err; } nvme_ctrlr->prchk_flags = prchk_flags; diff --git a/module/bdev/nvme/bdev_ocssd.c b/module/bdev/nvme/bdev_ocssd.c deleted file mode 100644 index 59debc8ae..000000000 --- a/module/bdev/nvme/bdev_ocssd.c +++ /dev/null @@ -1,1596 +0,0 @@ -/*- - * BSD LICENSE - * - * Copyright (c) Intel Corporation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "spdk/stdinc.h" -#include "spdk/bdev_module.h" -#include "spdk/bdev_zone.h" -#include "spdk/log.h" -#include "spdk/string.h" -#include "spdk/util.h" -#include "spdk/nvme_ocssd.h" -#include "spdk/nvme_ocssd_spec.h" -#include "spdk/nvme.h" -#include "common.h" -#include "bdev_ocssd.h" - -struct bdev_ocssd_lba_offsets { - uint32_t grp; - uint32_t pu; - uint32_t chk; - uint32_t lbk; -}; - -struct bdev_ocssd_zone { - uint64_t slba; - uint64_t write_pointer; - uint64_t capacity; - bool busy; -}; - -struct bdev_ocssd_io { - union { - struct { - struct bdev_ocssd_zone *zone; - struct iovec *iovs; - int iovcnt; - int iovpos; - uint32_t iov_offset; - uint64_t lba[SPDK_NVME_OCSSD_MAX_LBAL_ENTRIES]; - } io; - struct { - size_t chunk_offset; - struct spdk_ocssd_chunk_information_entry chunk_info; - } zone_info; - }; -}; - -struct ocssd_io_channel { - struct spdk_poller *pending_poller; - TAILQ_HEAD(, spdk_bdev_io) pending_requests; -}; - -struct ocssd_bdev { - struct nvme_bdev nvme_bdev; - struct bdev_ocssd_zone *zones; -}; - -struct bdev_ocssd_ns { - struct spdk_ocssd_geometry_data geometry; - struct bdev_ocssd_lba_offsets lba_offsets; - bool chunk_notify_pending; - bool depopulate_pending; - uint64_t chunk_notify_count; - uint64_t num_outstanding; -#define CHUNK_NOTIFICATION_ENTRY_COUNT 64 - struct spdk_ocssd_chunk_notification_entry chunk[CHUNK_NOTIFICATION_ENTRY_COUNT]; -}; - -struct ocssd_bdev_ctrlr { - struct spdk_poller *mm_poller; -}; - -static struct bdev_ocssd_ns * -bdev_ocssd_get_ns_from_nvme(struct nvme_ns *nvme_ns) -{ - return nvme_ns->type_ctx; -} - -static inline bool -bdev_ocssd_find_io_path(struct nvme_bdev_channel *nbdev_ch, - struct bdev_ocssd_ns **_ocssd_ns, - struct spdk_nvme_ns **_ns, struct spdk_nvme_qpair **_qpair) -{ - if (spdk_unlikely(nbdev_ch->ctrlr_ch->qpair == NULL)) { - /* The device is currently resetting. */ - return false; - } - - *_ocssd_ns = bdev_ocssd_get_ns_from_nvme(nbdev_ch->nvme_ns); - *_ns = nbdev_ch->nvme_ns->ns; - *_qpair = nbdev_ch->ctrlr_ch->qpair; - return true; -} - -static int -bdev_ocssd_library_init(void) -{ - return 0; -} - -static void -bdev_ocssd_library_fini(void) -{ -} - -static int -bdev_ocssd_config_json(struct spdk_json_write_ctx *w) -{ - return 0; -} - -void -bdev_ocssd_namespace_config_json(struct spdk_json_write_ctx *w, struct nvme_ns *nvme_ns) -{ - struct nvme_bdev *nvme_bdev; - - nvme_bdev = nvme_ns->bdev; - assert(nvme_bdev != NULL); - - spdk_json_write_object_begin(w); - spdk_json_write_named_string(w, "method", "bdev_ocssd_create"); - - spdk_json_write_named_object_begin(w, "params"); - spdk_json_write_named_string(w, "ctrlr_name", nvme_ns->ctrlr->name); - spdk_json_write_named_string(w, "bdev_name", nvme_bdev->disk.name); - spdk_json_write_named_uint32(w, "nsid", nvme_ns->id); - spdk_json_write_object_end(w); - - spdk_json_write_object_end(w); -} - -static int -bdev_ocssd_get_ctx_size(void) -{ - return sizeof(struct bdev_ocssd_io); -} - -static struct spdk_bdev_module ocssd_if = { - .name = "ocssd", - .module_init = bdev_ocssd_library_init, - .module_fini = bdev_ocssd_library_fini, - .config_json = bdev_ocssd_config_json, - .get_ctx_size = bdev_ocssd_get_ctx_size, -}; - -SPDK_BDEV_MODULE_REGISTER(ocssd, &ocssd_if); - -static inline uint64_t -bdev_ocssd_get_zone_size(const struct ocssd_bdev *ocssd_bdev) -{ - return ocssd_bdev->nvme_bdev.disk.zone_size; -} - -static uint64_t -bdev_ocssd_num_zones(const struct ocssd_bdev *ocssd_bdev) -{ - const struct spdk_bdev *bdev = &ocssd_bdev->nvme_bdev.disk; - - return bdev->blockcnt / bdev->zone_size; -} - -static struct bdev_ocssd_zone * -bdev_ocssd_get_zone_by_lba(const struct ocssd_bdev *ocssd_bdev, uint64_t lba) -{ - const struct spdk_bdev *bdev = &ocssd_bdev->nvme_bdev.disk; - - if (lba >= bdev->blockcnt) { - return NULL; - } - - return &ocssd_bdev->zones[lba / bdev->zone_size]; -} - -static struct bdev_ocssd_zone * -bdev_ocssd_get_zone_by_slba(struct ocssd_bdev *ocssd_bdev, uint64_t slba) -{ - const struct spdk_bdev *bdev = &ocssd_bdev->nvme_bdev.disk; - - if (slba % bdev->zone_size != 0 || slba >= bdev->blockcnt) { - return NULL; - } - - return &ocssd_bdev->zones[slba / bdev->zone_size]; -} - -static void -bdev_ocssd_free_bdev(struct ocssd_bdev *ocssd_bdev) -{ - if (!ocssd_bdev) { - return; - } - - free(ocssd_bdev->zones); - free(ocssd_bdev->nvme_bdev.disk.name); - free(ocssd_bdev); -} - -static void -_bdev_ocssd_unregister_dev_cb(void *io_device) -{ - struct nvme_bdev *nvme_bdev = io_device; - struct ocssd_bdev *ocssd_bdev = nvme_bdev->disk.ctxt; - - bdev_ocssd_free_bdev(ocssd_bdev); -} - -static int -bdev_ocssd_destruct(void *ctx) -{ - struct ocssd_bdev *ocssd_bdev = ctx; - struct nvme_bdev *nvme_bdev = &ocssd_bdev->nvme_bdev; - struct nvme_ns *nvme_ns = nvme_bdev->nvme_ns; - - pthread_mutex_lock(&nvme_ns->ctrlr->mutex); - - nvme_ns->bdev = NULL; - - if (!nvme_ns->populated) { - pthread_mutex_unlock(&nvme_ns->ctrlr->mutex); - - nvme_ctrlr_release(nvme_ns->ctrlr); - } else { - pthread_mutex_unlock(&nvme_ns->ctrlr->mutex); - } - - spdk_io_device_unregister(nvme_bdev, _bdev_ocssd_unregister_dev_cb); - - return 0; -} - -static void -bdev_ocssd_translate_lba(const struct spdk_ocssd_geometry_data *geo, uint64_t lba, - uint64_t *grp, uint64_t *pu, uint64_t *chk, uint64_t *lbk) -{ - uint64_t addr_shift, num_punits, punit; - - /* To achieve best performance, we need to make sure that adjacent zones can be accessed - * in parallel. We accomplish this by having the following addressing scheme: - * - * [ zone id ][ zone offset ] User's LBA - * [ chunk ][ group ][ parallel unit ][ logical block ] Open Channel's LBA - * - * which means that neighbouring zones are placed in a different group and parallel unit. - */ - addr_shift = geo->clba; - num_punits = geo->num_grp * geo->num_pu; - *lbk = lba % addr_shift; - - punit = (lba / addr_shift) % num_punits; - - *pu = punit % geo->num_pu; - *grp = punit / geo->num_pu; - - addr_shift *= num_punits; - - *chk = (lba / addr_shift) % geo->num_chk; -} - -static uint64_t -bdev_ocssd_to_parallel_unit(const struct spdk_ocssd_geometry_data *geometry, - const struct bdev_ocssd_lba_offsets *offsets, - uint64_t lba) -{ - uint64_t pu, grp; - - pu = (lba >> offsets->pu) & ((1 << geometry->lbaf.pu_len) - 1); - grp = (lba >> offsets->grp) & ((1 << geometry->lbaf.grp_len) - 1); - - return grp * geometry->num_pu + pu; -} - -static uint64_t -bdev_ocssd_from_disk_lba(struct bdev_ocssd_ns *ocssd_ns, uint64_t lba) -{ - const struct spdk_ocssd_geometry_data *geometry = &ocssd_ns->geometry; - const struct bdev_ocssd_lba_offsets *offsets = &ocssd_ns->lba_offsets; - uint64_t lbk, chk, punit; - - lbk = (lba >> offsets->lbk) & ((1 << geometry->lbaf.lbk_len) - 1); - chk = (lba >> offsets->chk) & ((1 << geometry->lbaf.chk_len) - 1); - - punit = bdev_ocssd_to_parallel_unit(geometry, offsets, lba); - - return lbk + punit * geometry->clba + chk * geometry->clba * - (geometry->num_grp * geometry->num_pu); -} - -static uint64_t -bdev_ocssd_to_disk_lba(struct bdev_ocssd_ns *ocssd_ns, uint64_t lba) -{ - const struct bdev_ocssd_lba_offsets *offsets = &ocssd_ns->lba_offsets; - uint64_t lbk, chk, pu, grp; - - bdev_ocssd_translate_lba(&ocssd_ns->geometry, lba, &grp, &pu, &chk, &lbk); - - return (lbk << offsets->lbk) | - (chk << offsets->chk) | - (pu << offsets->pu) | - (grp << offsets->grp); -} - -static uint64_t -bdev_ocssd_to_chunk_info_offset(struct bdev_ocssd_ns *ocssd_ns, uint64_t lba) -{ - const struct spdk_ocssd_geometry_data *geo = &ocssd_ns->geometry; - uint64_t grp, pu, chk, lbk; - - bdev_ocssd_translate_lba(geo, lba, &grp, &pu, &chk, &lbk); - - return grp * geo->num_pu * geo->num_chk + pu * geo->num_chk + chk; -} - -static void -bdev_ocssd_reset_sgl(void *ref, uint32_t sgl_offset) -{ - struct bdev_ocssd_io *ocdev_io = ref; - struct iovec *iov; - - ocdev_io->io.iov_offset = sgl_offset; - for (ocdev_io->io.iovpos = 0; ocdev_io->io.iovpos < ocdev_io->io.iovcnt; - ocdev_io->io.iovpos++) { - iov = &ocdev_io->io.iovs[ocdev_io->io.iovpos]; - if (ocdev_io->io.iov_offset < iov->iov_len) { - break; - } - - ocdev_io->io.iov_offset -= iov->iov_len; - } -} - -static int -bdev_ocssd_next_sge(void *ref, void **address, uint32_t *length) -{ - struct bdev_ocssd_io *ocdev_io = ref; - struct iovec *iov; - - assert(ocdev_io->io.iovpos < ocdev_io->io.iovcnt); - - iov = &ocdev_io->io.iovs[ocdev_io->io.iovpos]; - - *address = iov->iov_base; - *length = iov->iov_len; - - if (ocdev_io->io.iov_offset) { - assert(ocdev_io->io.iov_offset <= iov->iov_len); - *address += ocdev_io->io.iov_offset; - *length -= ocdev_io->io.iov_offset; - } - - ocdev_io->io.iov_offset += *length; - if (ocdev_io->io.iov_offset == iov->iov_len) { - ocdev_io->io.iovpos++; - ocdev_io->io.iov_offset = 0; - } - - return 0; -} - -static void -bdev_ocssd_read_cb(void *ctx, const struct spdk_nvme_cpl *cpl) -{ - struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(ctx); - - spdk_bdev_io_complete_nvme_status(bdev_io, 0, cpl->status.sct, cpl->status.sc); -} - -static int -bdev_ocssd_read(struct ocssd_bdev *ocssd_bdev, struct bdev_ocssd_ns *ocssd_ns, - struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, - struct bdev_ocssd_io *ocdev_io, struct iovec *iov, int iovcnt, - void *md, uint64_t lba_count, uint64_t lba) -{ - const size_t zone_size = bdev_ocssd_get_zone_size(ocssd_bdev); - - if ((lba % zone_size) + lba_count > zone_size) { - SPDK_ERRLOG("Tried to cross zone boundary during read command\n"); - return -EINVAL; - } - - ocdev_io->io.iovs = iov; - ocdev_io->io.iovcnt = iovcnt; - ocdev_io->io.iovpos = 0; - ocdev_io->io.iov_offset = 0; - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, lba); - - return spdk_nvme_ns_cmd_readv_with_md(ns, qpair, lba, - lba_count, bdev_ocssd_read_cb, - ocdev_io, 0, bdev_ocssd_reset_sgl, - bdev_ocssd_next_sge, md, 0, 0); -} - -static void -bdev_ocssd_write_cb(void *ctx, const struct spdk_nvme_cpl *cpl) -{ - struct bdev_ocssd_io *ocdev_io = ctx; - struct bdev_ocssd_zone *zone = ocdev_io->io.zone; - struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(ctx); - - zone->write_pointer = bdev_io->u.bdev.offset_blocks + bdev_io->u.bdev.num_blocks; - assert(zone->write_pointer <= zone->slba + zone->capacity); - - __atomic_store_n(&zone->busy, false, __ATOMIC_SEQ_CST); - spdk_bdev_io_complete_nvme_status(bdev_io, 0, cpl->status.sct, cpl->status.sc); -} - -static int -bdev_ocssd_write(struct ocssd_bdev *ocssd_bdev, struct bdev_ocssd_ns *ocssd_ns, - struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, - struct bdev_ocssd_io *ocdev_io, struct iovec *iov, int iovcnt, - void *md, uint64_t lba_count, uint64_t lba) -{ - const size_t zone_size = bdev_ocssd_get_zone_size(ocssd_bdev); - struct bdev_ocssd_zone *zone; - int rc; - - if ((lba % zone_size) + lba_count > zone_size) { - SPDK_ERRLOG("Tried to cross zone boundary during write command\n"); - return -EINVAL; - } - - zone = bdev_ocssd_get_zone_by_lba(ocssd_bdev, lba); - if (__atomic_exchange_n(&zone->busy, true, __ATOMIC_SEQ_CST)) { - return -EINVAL; - } - - ocdev_io->io.zone = zone; - ocdev_io->io.iovs = iov; - ocdev_io->io.iovcnt = iovcnt; - ocdev_io->io.iovpos = 0; - ocdev_io->io.iov_offset = 0; - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, lba); - - rc = spdk_nvme_ns_cmd_writev_with_md(ns, qpair, lba, - lba_count, bdev_ocssd_write_cb, - ocdev_io, 0, bdev_ocssd_reset_sgl, - bdev_ocssd_next_sge, md, 0, 0); - if (spdk_unlikely(rc != 0)) { - __atomic_store_n(&zone->busy, false, __ATOMIC_SEQ_CST); - } - - return rc; -} - -static void -bdev_ocssd_append_cb(void *ctx, const struct spdk_nvme_cpl *cpl) -{ - struct bdev_ocssd_io *ocdev_io = ctx; - struct bdev_ocssd_zone *zone = ocdev_io->io.zone; - struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(ctx); - - bdev_io->u.bdev.offset_blocks = zone->write_pointer; - zone->write_pointer += bdev_io->u.bdev.num_blocks; - assert(zone->write_pointer <= zone->slba + zone->capacity); - - __atomic_store_n(&zone->busy, false, __ATOMIC_SEQ_CST); - spdk_bdev_io_complete_nvme_status(bdev_io, 0, cpl->status.sct, cpl->status.sc); -} - -static int -bdev_ocssd_zone_append(struct ocssd_bdev *ocssd_bdev, struct bdev_ocssd_ns *ocssd_ns, - struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, - struct bdev_ocssd_io *ocdev_io, struct iovec *iov, int iovcnt, - void *md, uint64_t lba_count, uint64_t lba) -{ - struct bdev_ocssd_zone *zone; - int rc = 0; - - zone = bdev_ocssd_get_zone_by_slba(ocssd_bdev, lba); - if (!zone) { - SPDK_ERRLOG("Invalid zone SLBA: %"PRIu64"\n", lba); - return -EINVAL; - } - - if (__atomic_exchange_n(&zone->busy, true, __ATOMIC_SEQ_CST)) { - return -EAGAIN; - } - - if (zone->slba + zone->capacity - zone->write_pointer < lba_count) { - SPDK_ERRLOG("Insufficient number of blocks remaining\n"); - rc = -ENOSPC; - goto out; - } - - ocdev_io->io.zone = zone; - ocdev_io->io.iovs = iov; - ocdev_io->io.iovcnt = iovcnt; - ocdev_io->io.iovpos = 0; - ocdev_io->io.iov_offset = 0; - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, zone->write_pointer); - - rc = spdk_nvme_ns_cmd_writev_with_md(ns, qpair, lba, - lba_count, bdev_ocssd_append_cb, - ocdev_io, 0, bdev_ocssd_reset_sgl, - bdev_ocssd_next_sge, md, 0, 0); -out: - if (spdk_unlikely(rc != 0)) { - __atomic_store_n(&zone->busy, false, __ATOMIC_SEQ_CST); - } - - return rc; -} - -static void -bdev_ocssd_io_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, bool success) -{ - struct ocssd_bdev *ocssd_bdev = (struct ocssd_bdev *)bdev_io->bdev->ctxt; - struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(ch); - struct bdev_ocssd_ns *ocssd_ns; - struct spdk_nvme_ns *ns; - struct spdk_nvme_qpair *qpair; - int rc; - - if (!success) { - spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM); - return; - } - - if (spdk_unlikely(!bdev_ocssd_find_io_path(nbdev_ch, &ocssd_ns, &ns, &qpair))) { - spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); - return; - } - - rc = bdev_ocssd_read(ocssd_bdev, - ocssd_ns, - ns, - qpair, - (struct bdev_ocssd_io *)bdev_io->driver_ctx, - bdev_io->u.bdev.iovs, - bdev_io->u.bdev.iovcnt, - bdev_io->u.bdev.md_buf, - bdev_io->u.bdev.num_blocks, - bdev_io->u.bdev.offset_blocks); - if (spdk_likely(rc != 0)) { - if (rc == -ENOMEM) { - spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM); - } else { - spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); - } - } -} - -static void -bdev_ocssd_reset_zone_cb(void *ctx, const struct spdk_nvme_cpl *cpl) -{ - struct bdev_ocssd_io *ocdev_io = ctx; - struct bdev_ocssd_zone *zone = ocdev_io->io.zone; - struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(ctx); - - zone->write_pointer = zone->slba; - __atomic_store_n(&zone->busy, false, __ATOMIC_SEQ_CST); - spdk_bdev_io_complete_nvme_status(bdev_io, 0, cpl->status.sct, cpl->status.sc); -} - -static int -bdev_ocssd_reset_zone(struct ocssd_bdev *ocssd_bdev, struct bdev_ocssd_ns *ocssd_ns, - struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, - struct bdev_ocssd_io *ocdev_io, uint64_t slba, size_t num_zones) -{ - uint64_t offset, zone_size = bdev_ocssd_get_zone_size(ocssd_bdev); - struct bdev_ocssd_zone *zone; - int rc; - - if (num_zones > 1) { - SPDK_ERRLOG("Exceeded maximum number of zones per single reset: 1\n"); - return -EINVAL; - } - - zone = bdev_ocssd_get_zone_by_slba(ocssd_bdev, slba); - if (__atomic_exchange_n(&zone->busy, true, __ATOMIC_SEQ_CST)) { - return -EINVAL; - } - - for (offset = 0; offset < num_zones; ++offset) { - ocdev_io->io.lba[offset] = bdev_ocssd_to_disk_lba(ocssd_ns, - slba + offset * zone_size); - } - - ocdev_io->io.zone = zone; - - rc = spdk_nvme_ocssd_ns_cmd_vector_reset(ns, qpair, - ocdev_io->io.lba, num_zones, NULL, - bdev_ocssd_reset_zone_cb, ocdev_io); - if (spdk_unlikely(rc != 0)) { - __atomic_store_n(&zone->busy, false, __ATOMIC_SEQ_CST); - } - - return rc; -} - -static int _bdev_ocssd_get_zone_info(struct ocssd_bdev *ocssd_bdev, struct bdev_ocssd_ns *ocssd_ns, - struct spdk_nvme_ns *ns, - struct bdev_ocssd_io *ocdev_io, uint64_t zone_id); - -static void -bdev_ocssd_fill_zone_info(struct ocssd_bdev *ocssd_bdev, struct bdev_ocssd_ns *ocssd_ns, - struct spdk_bdev_zone_info *zone_info, - const struct spdk_ocssd_chunk_information_entry *chunk_info) -{ - uint64_t zone_size = bdev_ocssd_get_zone_size(ocssd_bdev); - - zone_info->zone_id = bdev_ocssd_from_disk_lba(ocssd_ns, chunk_info->slba); - zone_info->write_pointer = zone_info->zone_id; - - if (chunk_info->cs.free) { - zone_info->state = SPDK_BDEV_ZONE_STATE_EMPTY; - } else if (chunk_info->cs.closed) { - zone_info->state = SPDK_BDEV_ZONE_STATE_FULL; - } else if (chunk_info->cs.open) { - zone_info->state = SPDK_BDEV_ZONE_STATE_OPEN; - zone_info->write_pointer += chunk_info->wp % zone_size; - } else if (chunk_info->cs.offline) { - zone_info->state = SPDK_BDEV_ZONE_STATE_OFFLINE; - } else { - SPDK_ERRLOG("Unknown chunk state, assuming offline\n"); - zone_info->state = SPDK_BDEV_ZONE_STATE_OFFLINE; - } - - if (chunk_info->ct.size_deviate) { - zone_info->capacity = chunk_info->cnlb; - } else { - zone_info->capacity = zone_size; - } -} - -static void -bdev_ocssd_zone_info_cb(void *ctx, const struct spdk_nvme_cpl *cpl) -{ - struct bdev_ocssd_io *ocdev_io = ctx; - struct spdk_ocssd_chunk_information_entry *chunk_info = &ocdev_io->zone_info.chunk_info; - struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(ctx); - struct ocssd_bdev *ocssd_bdev = bdev_io->bdev->ctxt; - struct nvme_bdev_channel *nbdev_ch; - struct spdk_nvme_ns *ns; - struct spdk_nvme_qpair *qpair; - struct bdev_ocssd_ns *ocssd_ns; - struct spdk_bdev_zone_info *zone_info; - int rc; - - if (spdk_unlikely(spdk_nvme_cpl_is_error(cpl))) { - spdk_bdev_io_complete_nvme_status(bdev_io, 0, cpl->status.sct, cpl->status.sc); - return; - } - - nbdev_ch = spdk_io_channel_get_ctx(spdk_bdev_io_get_io_channel(bdev_io)); - - if (spdk_unlikely(!bdev_ocssd_find_io_path(nbdev_ch, &ocssd_ns, &ns, &qpair))) { - spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); - return; - } - - zone_info = ((struct spdk_bdev_zone_info *)bdev_io->u.zone_mgmt.buf) + - ocdev_io->zone_info.chunk_offset; - bdev_ocssd_fill_zone_info(ocssd_bdev, ocssd_ns, zone_info, chunk_info); - - if (++ocdev_io->zone_info.chunk_offset == bdev_io->u.zone_mgmt.num_zones) { - spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); - } else { - rc = _bdev_ocssd_get_zone_info(ocssd_bdev, ocssd_ns, ns, ocdev_io, - bdev_io->u.zone_mgmt.zone_id); - if (spdk_unlikely(rc != 0)) { - if (rc == -ENOMEM) { - spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM); - } else { - spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); - } - } - } -} - -static int -_bdev_ocssd_get_zone_info(struct ocssd_bdev *ocssd_bdev, struct bdev_ocssd_ns *ocssd_ns, - struct spdk_nvme_ns *ns, - struct bdev_ocssd_io *ocdev_io, uint64_t zone_id) -{ - uint64_t lba, offset, zone_size = bdev_ocssd_get_zone_size(ocssd_bdev); - - lba = zone_id + ocdev_io->zone_info.chunk_offset * zone_size; - offset = bdev_ocssd_to_chunk_info_offset(ocssd_ns, lba); - - return spdk_nvme_ctrlr_cmd_get_log_page(spdk_nvme_ns_get_ctrlr(ns), - SPDK_OCSSD_LOG_CHUNK_INFO, - spdk_nvme_ns_get_id(ns), - &ocdev_io->zone_info.chunk_info, - sizeof(ocdev_io->zone_info.chunk_info), - offset * sizeof(ocdev_io->zone_info.chunk_info), - bdev_ocssd_zone_info_cb, (void *)ocdev_io); -} - -static int -bdev_ocssd_get_zone_info(struct ocssd_bdev *ocssd_bdev, struct bdev_ocssd_ns *ocssd_ns, - struct spdk_nvme_ns *ns, - struct bdev_ocssd_io *ocdev_io, uint64_t zone_id, uint32_t num_zones) -{ - uint64_t zone_size = bdev_ocssd_get_zone_size(ocssd_bdev); - - if (num_zones < 1) { - SPDK_ERRLOG("Invalid number of zones: %"PRIu32"\n", num_zones); - return -EINVAL; - } - - if (zone_id % zone_size != 0) { - SPDK_ERRLOG("Unaligned zone LBA: %"PRIu64"\n", zone_id); - return -EINVAL; - } - - ocdev_io->zone_info.chunk_offset = 0; - - return _bdev_ocssd_get_zone_info(ocssd_bdev, ocssd_ns, ns, ocdev_io, zone_id); -} - -static int -bdev_ocssd_zone_management(struct ocssd_bdev *ocssd_bdev, struct bdev_ocssd_ns *ocssd_ns, - struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, - struct spdk_bdev_io *bdev_io) -{ - switch (bdev_io->u.zone_mgmt.zone_action) { - case SPDK_BDEV_ZONE_RESET: - return bdev_ocssd_reset_zone(ocssd_bdev, - ocssd_ns, - ns, - qpair, - (struct bdev_ocssd_io *)bdev_io->driver_ctx, - bdev_io->u.zone_mgmt.zone_id, - bdev_io->u.zone_mgmt.num_zones); - default: - return -EINVAL; - } -} - -static void bdev_ocssd_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io); - -static int -bdev_ocssd_poll_pending(void *ctx) -{ - struct nvme_ctrlr_channel *ctrlr_ch = ctx; - struct ocssd_io_channel *ocssd_ch; - struct spdk_bdev_io *bdev_io; - struct spdk_io_channel *ch; - TAILQ_HEAD(, spdk_bdev_io) pending_requests; - int num_requests = 0; - - ocssd_ch = ctrlr_ch->ocssd_ch; - - TAILQ_INIT(&pending_requests); - TAILQ_SWAP(&ocssd_ch->pending_requests, &pending_requests, spdk_bdev_io, module_link); - - while ((bdev_io = TAILQ_FIRST(&pending_requests))) { - TAILQ_REMOVE(&pending_requests, bdev_io, module_link); - ch = spdk_bdev_io_get_io_channel(bdev_io); - bdev_ocssd_submit_request(ch, bdev_io); - num_requests++; - } - - if (TAILQ_EMPTY(&ocssd_ch->pending_requests)) { - spdk_poller_pause(ocssd_ch->pending_poller); - } - - return num_requests; -} - -static void -bdev_ocssd_delay_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) -{ - struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(ch); - struct nvme_ctrlr_channel *ctrlr_ch = nbdev_ch->ctrlr_ch; - struct ocssd_io_channel *ocssd_ch = ctrlr_ch->ocssd_ch; - - TAILQ_INSERT_TAIL(&ocssd_ch->pending_requests, bdev_io, module_link); - spdk_poller_resume(ocssd_ch->pending_poller); -} - -static int -_bdev_ocssd_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) -{ - struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(ch); - struct ocssd_bdev *ocssd_bdev = (struct ocssd_bdev *)bdev_io->bdev->ctxt; - struct bdev_ocssd_io *ocdev_io = (struct bdev_ocssd_io *)bdev_io->driver_ctx; - struct bdev_ocssd_ns *ocssd_ns; - struct spdk_nvme_ns *ns; - struct spdk_nvme_qpair *qpair; - - if (spdk_unlikely(!bdev_ocssd_find_io_path(nbdev_ch, &ocssd_ns, &ns, &qpair))) { - return -1; - } - - switch (bdev_io->type) { - case SPDK_BDEV_IO_TYPE_READ: - if (bdev_io->u.bdev.iovs && bdev_io->u.bdev.iovs[0].iov_base) { - return bdev_ocssd_read(ocssd_bdev, - ocssd_ns, - ns, - qpair, - ocdev_io, - bdev_io->u.bdev.iovs, - bdev_io->u.bdev.iovcnt, - bdev_io->u.bdev.md_buf, - bdev_io->u.bdev.num_blocks, - bdev_io->u.bdev.offset_blocks); - } else { - spdk_bdev_io_get_buf(bdev_io, bdev_ocssd_io_get_buf_cb, - bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen); - return 0; - } - - case SPDK_BDEV_IO_TYPE_WRITE: - return bdev_ocssd_write(ocssd_bdev, - ocssd_ns, - ns, - qpair, - ocdev_io, - bdev_io->u.bdev.iovs, - bdev_io->u.bdev.iovcnt, - bdev_io->u.bdev.md_buf, - bdev_io->u.bdev.num_blocks, - bdev_io->u.bdev.offset_blocks); - - case SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT: - return bdev_ocssd_zone_management(ocssd_bdev, ocssd_ns, ns, qpair, bdev_io); - - case SPDK_BDEV_IO_TYPE_GET_ZONE_INFO: - return bdev_ocssd_get_zone_info(ocssd_bdev, - ocssd_ns, - ns, - ocdev_io, - bdev_io->u.zone_mgmt.zone_id, - bdev_io->u.zone_mgmt.num_zones); - - case SPDK_BDEV_IO_TYPE_ZONE_APPEND: - return bdev_ocssd_zone_append(ocssd_bdev, - ocssd_ns, - ns, - qpair, - ocdev_io, - bdev_io->u.bdev.iovs, - bdev_io->u.bdev.iovcnt, - bdev_io->u.bdev.md_buf, - bdev_io->u.bdev.num_blocks, - bdev_io->u.bdev.offset_blocks); - - default: - return -EINVAL; - } - - return 0; -} - -static void -bdev_ocssd_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) -{ - int rc = _bdev_ocssd_submit_request(ch, bdev_io); - - if (spdk_unlikely(rc != 0)) { - switch (rc) { - case -ENOMEM: - spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM); - break; - case -EAGAIN: - bdev_ocssd_delay_request(ch, bdev_io); - break; - default: - spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); - break; - } - } -} - -static bool -bdev_ocssd_io_type_supported(void *ctx, enum spdk_bdev_io_type type) -{ - switch (type) { - case SPDK_BDEV_IO_TYPE_READ: - case SPDK_BDEV_IO_TYPE_WRITE: - case SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT: - case SPDK_BDEV_IO_TYPE_ZONE_APPEND: - return true; - - default: - return false; - } -} - -static struct spdk_io_channel * -bdev_ocssd_get_io_channel(void *ctx) -{ - struct ocssd_bdev *ocssd_bdev = ctx; - - return spdk_get_io_channel(&ocssd_bdev->nvme_bdev); -} - -static void -bdev_ocssd_free_namespace(struct nvme_ns *nvme_ns) -{ - struct nvme_bdev *bdev; - - bdev = nvme_ns->bdev; - if (bdev != NULL) { - spdk_bdev_unregister(&bdev->disk, NULL, NULL); - } - - free(nvme_ns->type_ctx); - nvme_ns->type_ctx = NULL; - - nvme_ctrlr_depopulate_namespace_done(nvme_ns); -} - -static void -bdev_ocssd_push_media_events(struct nvme_ns *nvme_ns, - struct spdk_ocssd_chunk_notification_entry *chunk_entry) -{ - struct bdev_ocssd_ns *ocssd_ns = bdev_ocssd_get_ns_from_nvme(nvme_ns); - const struct spdk_ocssd_geometry_data *geometry = &ocssd_ns->geometry; - struct spdk_bdev_media_event event; - struct nvme_bdev *nvme_bdev; - size_t num_blocks, lba; - int rc; - - if (chunk_entry->mask.lblk) { - num_blocks = chunk_entry->nlb; - } else if (chunk_entry->mask.chunk) { - num_blocks = geometry->clba; - } else if (chunk_entry->mask.pu) { - num_blocks = geometry->clba * geometry->num_chk; - } else { - SPDK_WARNLOG("Invalid chunk notification mask\n"); - return; - } - - nvme_bdev = nvme_ns->bdev; - if (nvme_bdev == NULL) { - SPDK_INFOLOG(bdev_ocssd, "Dropping media management event\n"); - return; - } - - lba = bdev_ocssd_from_disk_lba(ocssd_ns, chunk_entry->lba); - while (num_blocks > 0 && lba < nvme_bdev->disk.blockcnt) { - event.offset = lba; - event.num_blocks = spdk_min(num_blocks, geometry->clba); - - rc = spdk_bdev_push_media_events(&nvme_bdev->disk, &event, 1); - if (spdk_unlikely(rc < 0)) { - SPDK_DEBUGLOG(bdev_ocssd, "Failed to push media event: %s\n", - spdk_strerror(-rc)); - break; - } - - /* Jump to the next chunk on the same parallel unit */ - lba += geometry->clba * geometry->num_grp * geometry->num_pu; - num_blocks -= event.num_blocks; - } -} - -static void -bdev_ocssd_notify_media_management(struct nvme_ns *nvme_ns) -{ - struct nvme_bdev *nvme_bdev; - - nvme_bdev = nvme_ns->bdev; - if (nvme_bdev != NULL) { - spdk_bdev_notify_media_management(&nvme_bdev->disk); - } -} - -static void -bdev_ocssd_chunk_notification_cb(void *ctx, const struct spdk_nvme_cpl *cpl) -{ - struct nvme_ns *nvme_ns = ctx; - struct bdev_ocssd_ns *ocssd_ns = bdev_ocssd_get_ns_from_nvme(nvme_ns); - struct spdk_ocssd_chunk_notification_entry *chunk_entry; - size_t chunk_id; - - ocssd_ns->num_outstanding--; - - /* The namespace was being depopulated in the meantime. */ - if (ocssd_ns->depopulate_pending) { - if (ocssd_ns->num_outstanding == 0) { - ocssd_ns->depopulate_pending = false; - bdev_ocssd_free_namespace(nvme_ns); - } - - return; - } - - if (spdk_nvme_cpl_is_error(cpl)) { - SPDK_ERRLOG("Failed to retrieve chunk notification log\n"); - return; - } - - for (chunk_id = 0; chunk_id < CHUNK_NOTIFICATION_ENTRY_COUNT; ++chunk_id) { - chunk_entry = &ocssd_ns->chunk[chunk_id]; - if (chunk_entry->nc <= ocssd_ns->chunk_notify_count) { - break; - } - - ocssd_ns->chunk_notify_count = chunk_entry->nc; - - bdev_ocssd_push_media_events(nvme_ns, chunk_entry); - } - - /* If at least one notification has been processed send out media event */ - if (chunk_id > 0) { - bdev_ocssd_notify_media_management(nvme_ns); - } - - /* If we filled the full array of events, there may be more still pending. Set the pending - * flag back to true so that we try to get more events again next time the poller runs. - */ - if (chunk_id == CHUNK_NOTIFICATION_ENTRY_COUNT) { - ocssd_ns->chunk_notify_pending = true; - } -} - -static int -bdev_ocssd_poll_mm(void *ctx) -{ - struct nvme_ctrlr *nvme_ctrlr = ctx; - struct nvme_ns *nvme_ns; - struct bdev_ocssd_ns *ocssd_ns; - uint32_t nsid; - int rc; - - for (nsid = 0; nsid < nvme_ctrlr->num_ns; ++nsid) { - nvme_ns = nvme_ctrlr->namespaces[nsid]; - if (nvme_ns == NULL || !nvme_ns->populated) { - continue; - } - - ocssd_ns = bdev_ocssd_get_ns_from_nvme(nvme_ns); - if (ocssd_ns->chunk_notify_pending) { - ocssd_ns->chunk_notify_pending = false; - ocssd_ns->num_outstanding++; - - rc = spdk_nvme_ctrlr_cmd_get_log_page(nvme_ctrlr->ctrlr, - SPDK_OCSSD_LOG_CHUNK_NOTIFICATION, - nsid + 1, ocssd_ns->chunk, - sizeof(ocssd_ns->chunk[0]) * - CHUNK_NOTIFICATION_ENTRY_COUNT, - 0, bdev_ocssd_chunk_notification_cb, - nvme_ns); - if (spdk_unlikely(rc != 0)) { - SPDK_ERRLOG("Failed to get chunk notification log page: %s\n", - spdk_strerror(-rc)); - ocssd_ns->num_outstanding--; - } - } - } - - return SPDK_POLLER_BUSY; -} - -void -bdev_ocssd_handle_chunk_notification(struct nvme_ctrlr *nvme_ctrlr) -{ - struct bdev_ocssd_ns *ocssd_ns; - struct nvme_ns *nvme_ns; - uint32_t nsid; - - for (nsid = 0; nsid < nvme_ctrlr->num_ns; ++nsid) { - nvme_ns = nvme_ctrlr->namespaces[nsid]; - if (nvme_ns == NULL || !nvme_ns->populated) { - continue; - } - - ocssd_ns = bdev_ocssd_get_ns_from_nvme(nvme_ns); - ocssd_ns->chunk_notify_pending = true; - } -} - -static struct spdk_bdev_fn_table ocssdlib_fn_table = { - .destruct = bdev_ocssd_destruct, - .submit_request = bdev_ocssd_submit_request, - .io_type_supported = bdev_ocssd_io_type_supported, - .get_io_channel = bdev_ocssd_get_io_channel, -}; - -struct bdev_ocssd_create_ctx { - struct ocssd_bdev *ocssd_bdev; - struct nvme_ns *nvme_ns; - bdev_ocssd_create_cb cb_fn; - void *cb_arg; - uint64_t chunk_offset; - uint64_t end_chunk_offset; - uint64_t num_chunks; -#define OCSSD_BDEV_CHUNK_INFO_COUNT 128 - struct spdk_ocssd_chunk_information_entry chunk_info[OCSSD_BDEV_CHUNK_INFO_COUNT]; -}; - -static void -bdev_ocssd_create_complete(struct bdev_ocssd_create_ctx *create_ctx, int status) -{ - const char *bdev_name = create_ctx->ocssd_bdev->nvme_bdev.disk.name; - - if (spdk_unlikely(status != 0)) { - bdev_ocssd_free_bdev(create_ctx->ocssd_bdev); - } - - create_ctx->cb_fn(bdev_name, status, create_ctx->cb_arg); - free(create_ctx); -} - -static int bdev_ocssd_init_zone(struct bdev_ocssd_create_ctx *create_ctx); - -static void -bdev_ocssd_register_bdev(void *ctx) -{ - struct bdev_ocssd_create_ctx *create_ctx = ctx; - struct nvme_bdev *nvme_bdev = &create_ctx->ocssd_bdev->nvme_bdev; - struct nvme_ns *nvme_ns = create_ctx->nvme_ns; - int rc; - - spdk_io_device_register(nvme_bdev, - bdev_nvme_create_bdev_channel_cb, - bdev_nvme_destroy_bdev_channel_cb, - sizeof(struct nvme_bdev_channel), - nvme_bdev->disk.name); - - rc = spdk_bdev_register(&nvme_bdev->disk); - if (spdk_likely(rc == 0)) { - nvme_ns->bdev = nvme_bdev; - } else { - SPDK_ERRLOG("Failed to register bdev %s\n", nvme_bdev->disk.name); - spdk_io_device_unregister(nvme_bdev, NULL); - } - - bdev_ocssd_create_complete(create_ctx, rc); -} - -static void -bdev_occsd_init_zone_cb(void *ctx, const struct spdk_nvme_cpl *cpl) -{ - struct bdev_ocssd_create_ctx *create_ctx = ctx; - struct bdev_ocssd_zone *ocssd_zone; - struct ocssd_bdev *ocssd_bdev = create_ctx->ocssd_bdev; - struct bdev_ocssd_ns *ocssd_ns = bdev_ocssd_get_ns_from_nvme(create_ctx->nvme_ns); - struct spdk_bdev_zone_info zone_info = {}; - uint64_t offset; - int rc = 0; - - if (spdk_nvme_cpl_is_error(cpl)) { - SPDK_ERRLOG("Chunk information log page failed\n"); - bdev_ocssd_create_complete(create_ctx, -EIO); - return; - } - - for (offset = 0; offset < create_ctx->num_chunks; ++offset) { - bdev_ocssd_fill_zone_info(ocssd_bdev, ocssd_ns, &zone_info, - &create_ctx->chunk_info[offset]); - - ocssd_zone = bdev_ocssd_get_zone_by_slba(ocssd_bdev, zone_info.zone_id); - if (!ocssd_zone) { - SPDK_ERRLOG("Received invalid zone starting LBA: %"PRIu64"\n", - zone_info.zone_id); - bdev_ocssd_create_complete(create_ctx, -EINVAL); - return; - } - - /* Make sure we're not filling the same zone twice */ - assert(ocssd_zone->busy); - - ocssd_zone->busy = false; - ocssd_zone->slba = zone_info.zone_id; - ocssd_zone->capacity = zone_info.capacity; - ocssd_zone->write_pointer = zone_info.write_pointer; - } - - create_ctx->chunk_offset += create_ctx->num_chunks; - if (create_ctx->chunk_offset < create_ctx->end_chunk_offset) { - rc = bdev_ocssd_init_zone(create_ctx); - if (spdk_unlikely(rc != 0)) { - SPDK_ERRLOG("Failed to send chunk info log page\n"); - bdev_ocssd_create_complete(create_ctx, rc); - } - } else { - /* Make sure all zones have been processed */ - for (offset = 0; offset < bdev_ocssd_num_zones(ocssd_bdev); ++offset) { - assert(!ocssd_bdev->zones[offset].busy); - } - - /* Schedule the last bit of work (io_device, bdev registration) to be done in a - * context that is not tied to admin command's completion callback. - */ - spdk_thread_send_msg(spdk_get_thread(), bdev_ocssd_register_bdev, create_ctx); - } -} - -static int -bdev_ocssd_init_zone(struct bdev_ocssd_create_ctx *create_ctx) -{ - struct spdk_nvme_ns *ns = create_ctx->nvme_ns->ns; - - create_ctx->num_chunks = spdk_min(create_ctx->end_chunk_offset - create_ctx->chunk_offset, - OCSSD_BDEV_CHUNK_INFO_COUNT); - assert(create_ctx->num_chunks > 0); - - return spdk_nvme_ctrlr_cmd_get_log_page(spdk_nvme_ns_get_ctrlr(ns), - SPDK_OCSSD_LOG_CHUNK_INFO, - spdk_nvme_ns_get_id(ns), - &create_ctx->chunk_info, - sizeof(create_ctx->chunk_info[0]) * - create_ctx->num_chunks, - sizeof(create_ctx->chunk_info[0]) * - create_ctx->chunk_offset, - bdev_occsd_init_zone_cb, create_ctx); -} - -static int -bdev_ocssd_init_zones(struct bdev_ocssd_create_ctx *create_ctx) -{ - struct ocssd_bdev *ocssd_bdev = create_ctx->ocssd_bdev; - uint64_t offset, num_zones; - - num_zones = bdev_ocssd_num_zones(ocssd_bdev); - - ocssd_bdev->zones = calloc(num_zones, sizeof(*ocssd_bdev->zones)); - if (!ocssd_bdev->zones) { - return -ENOMEM; - } - - create_ctx->chunk_offset = 0; - create_ctx->end_chunk_offset = num_zones; - - /* Mark all zones as busy and clear it as their info is filled */ - for (offset = 0; offset < num_zones; ++offset) { - ocssd_bdev->zones[offset].busy = true; - } - - return bdev_ocssd_init_zone(create_ctx); -} - -void -bdev_ocssd_create_bdev(const char *ctrlr_name, const char *bdev_name, uint32_t nsid, - bdev_ocssd_create_cb cb_fn, void *cb_arg) -{ - struct nvme_ctrlr *nvme_ctrlr; - struct bdev_ocssd_create_ctx *create_ctx = NULL; - struct nvme_bdev *nvme_bdev = NULL; - struct ocssd_bdev *ocssd_bdev = NULL; - struct spdk_nvme_ns *ns; - struct nvme_ns *nvme_ns; - struct bdev_ocssd_ns *ocssd_ns; - struct spdk_ocssd_geometry_data *geometry; - int rc = 0; - - nvme_ctrlr = nvme_ctrlr_get_by_name(ctrlr_name); - if (!nvme_ctrlr) { - SPDK_ERRLOG("Unable to find controller %s\n", ctrlr_name); - rc = -ENODEV; - goto error; - } - - ns = spdk_nvme_ctrlr_get_ns(nvme_ctrlr->ctrlr, nsid); - if (!ns) { - SPDK_ERRLOG("Unable to retrieve namespace %"PRIu32"\n", nsid); - rc = -ENODEV; - goto error; - } - - if (!spdk_nvme_ns_is_active(ns)) { - SPDK_ERRLOG("Namespace %"PRIu32" is inactive\n", nsid); - rc = -EACCES; - goto error; - } - - assert(nsid <= nvme_ctrlr->num_ns); - nvme_ns = nvme_ctrlr->namespaces[nsid - 1]; - if (nvme_ns == NULL) { - SPDK_ERRLOG("Namespace %"PRIu32" is not initialized\n", nsid); - rc = -EINVAL; - goto error; - } - - ocssd_ns = bdev_ocssd_get_ns_from_nvme(nvme_ns); - if (ocssd_ns == NULL) { - SPDK_ERRLOG("Namespace %"PRIu32" is not an OCSSD namespace\n", nsid); - rc = -EINVAL; - goto error; - } - - if (spdk_bdev_get_by_name(bdev_name) != NULL) { - SPDK_ERRLOG("Device with provided name (%s) already exists\n", bdev_name); - rc = -EEXIST; - goto error; - } - - ocssd_bdev = calloc(1, sizeof(*ocssd_bdev)); - if (!ocssd_bdev) { - rc = -ENOMEM; - goto error; - } - - create_ctx = calloc(1, sizeof(*create_ctx)); - if (!create_ctx) { - rc = -ENOMEM; - goto error; - } - - create_ctx->ocssd_bdev = ocssd_bdev; - create_ctx->nvme_ns = nvme_ns; - create_ctx->cb_fn = cb_fn; - create_ctx->cb_arg = cb_arg; - - nvme_bdev = &ocssd_bdev->nvme_bdev; - nvme_bdev->nvme_ns = nvme_ns; - geometry = &ocssd_ns->geometry; - - nvme_bdev->disk.name = strdup(bdev_name); - if (!nvme_bdev->disk.name) { - rc = -ENOMEM; - goto error; - } - - nvme_bdev->disk.product_name = "Open Channel SSD"; - nvme_bdev->disk.ctxt = ocssd_bdev; - nvme_bdev->disk.fn_table = &ocssdlib_fn_table; - nvme_bdev->disk.module = &ocssd_if; - nvme_bdev->disk.blocklen = spdk_nvme_ns_get_extended_sector_size(ns); - nvme_bdev->disk.zoned = true; - nvme_bdev->disk.blockcnt = geometry->num_grp * geometry->num_pu * - geometry->num_chk * geometry->clba; - nvme_bdev->disk.zone_size = geometry->clba; - /* Since zone appends are emulated using writes, use max io xfer size (but in blocks) */ - nvme_bdev->disk.max_zone_append_size = spdk_nvme_ns_get_max_io_xfer_size(ns) / - spdk_nvme_ns_get_extended_sector_size(ns); - nvme_bdev->disk.max_open_zones = geometry->maxoc; - nvme_bdev->disk.optimal_open_zones = geometry->num_grp * geometry->num_pu; - nvme_bdev->disk.write_unit_size = geometry->ws_opt; - nvme_bdev->disk.media_events = true; - - if (geometry->maxocpu != 0 && geometry->maxocpu != geometry->maxoc) { - SPDK_WARNLOG("Maximum open chunks per PU is not zero. Reducing the maximum " - "number of open zones: %"PRIu32" -> %"PRIu32"\n", - geometry->maxoc, geometry->maxocpu); - nvme_bdev->disk.max_open_zones = geometry->maxocpu; - } - - rc = bdev_ocssd_init_zones(create_ctx); - if (spdk_unlikely(rc != 0)) { - SPDK_ERRLOG("Failed to initialize zones on bdev %s\n", nvme_bdev->disk.name); - goto error; - } - - return; -error: - bdev_ocssd_free_bdev(ocssd_bdev); - cb_fn(NULL, rc, cb_arg); - free(create_ctx); -} - -struct bdev_ocssd_delete_ctx { - bdev_ocssd_delete_cb cb_fn; - void *cb_arg; -}; - -static void -bdev_ocssd_unregister_cb(void *cb_arg, int status) -{ - struct bdev_ocssd_delete_ctx *delete_ctx = cb_arg; - - delete_ctx->cb_fn(status, delete_ctx->cb_arg); - free(delete_ctx); -} - -void -bdev_ocssd_delete_bdev(const char *bdev_name, bdev_ocssd_delete_cb cb_fn, void *cb_arg) -{ - struct spdk_bdev *bdev; - struct bdev_ocssd_delete_ctx *delete_ctx; - - bdev = spdk_bdev_get_by_name(bdev_name); - if (!bdev) { - SPDK_ERRLOG("Unable to find bdev %s\n", bdev_name); - cb_fn(-ENODEV, cb_arg); - return; - } - - if (bdev->module != &ocssd_if) { - SPDK_ERRLOG("Specified bdev %s is not an OCSSD bdev\n", bdev_name); - cb_fn(-EINVAL, cb_arg); - return; - } - - delete_ctx = calloc(1, sizeof(*delete_ctx)); - if (!delete_ctx) { - SPDK_ERRLOG("Unable to allocate deletion context\n"); - cb_fn(-ENOMEM, cb_arg); - return; - } - - delete_ctx->cb_fn = cb_fn; - delete_ctx->cb_arg = cb_arg; - - spdk_bdev_unregister(bdev, bdev_ocssd_unregister_cb, delete_ctx); -} - -struct bdev_ocssd_populate_ns_ctx { - struct nvme_async_probe_ctx *nvme_ctx; - struct nvme_ns *nvme_ns; -}; - -static void -bdev_ocssd_geometry_cb(void *_ctx, const struct spdk_nvme_cpl *cpl) -{ - struct bdev_ocssd_populate_ns_ctx *ctx = _ctx; - struct nvme_async_probe_ctx *nvme_ctx = ctx->nvme_ctx; - struct nvme_ns *nvme_ns = ctx->nvme_ns; - struct bdev_ocssd_ns *ocssd_ns = bdev_ocssd_get_ns_from_nvme(nvme_ns); - const struct spdk_ocssd_geometry_data *geometry = &ocssd_ns->geometry; - struct bdev_ocssd_lba_offsets *offsets = &ocssd_ns->lba_offsets; - int rc = 0; - - free(ctx); - - if (spdk_unlikely(spdk_nvme_cpl_is_error(cpl))) { - SPDK_ERRLOG("Failed to retrieve geometry for namespace %"PRIu32"\n", nvme_ns->id); - free(nvme_ns->type_ctx); - nvme_ns->type_ctx = NULL; - rc = -EIO; - } else { - offsets->lbk = 0; - offsets->chk = offsets->lbk + geometry->lbaf.lbk_len; - offsets->pu = offsets->chk + geometry->lbaf.chk_len; - offsets->grp = offsets->pu + geometry->lbaf.pu_len; - ocssd_ns->chunk_notify_pending = true; - } - - nvme_ctrlr_populate_namespace_done(nvme_ctx, nvme_ns, rc); -} - -void -bdev_ocssd_populate_namespace(struct nvme_ctrlr *nvme_ctrlr, - struct nvme_ns *nvme_ns, - struct nvme_async_probe_ctx *nvme_ctx) -{ - struct bdev_ocssd_ns *ocssd_ns; - struct bdev_ocssd_populate_ns_ctx *ctx; - struct spdk_nvme_ns *ns; - int rc; - - ns = spdk_nvme_ctrlr_get_ns(nvme_ctrlr->ctrlr, nvme_ns->id); - if (ns == NULL) { - rc = -EINVAL; - goto error; - } - - ctx = calloc(1, sizeof(*ctx)); - if (ctx == NULL) { - rc = -ENOMEM; - goto error; - } - - ocssd_ns = calloc(1, sizeof(*ocssd_ns)); - if (ocssd_ns == NULL) { - free(ctx); - rc = -ENOMEM; - goto error; - } - - nvme_ns->type_ctx = ocssd_ns; - nvme_ns->ns = ns; - nvme_ns->populated = true; - ctx->nvme_ctx = nvme_ctx; - ctx->nvme_ns = nvme_ns; - - rc = spdk_nvme_ocssd_ctrlr_cmd_geometry(nvme_ctrlr->ctrlr, nvme_ns->id, - &ocssd_ns->geometry, - sizeof(ocssd_ns->geometry), - bdev_ocssd_geometry_cb, ctx); - if (spdk_unlikely(rc != 0)) { - SPDK_ERRLOG("Failed to retrieve OC geometry: %s\n", spdk_strerror(-rc)); - nvme_ns->type_ctx = NULL; - free(ocssd_ns); - free(ctx); - goto error; - } - - return; - -error: - nvme_ctrlr_populate_namespace_done(nvme_ctx, nvme_ns, rc); -} - -void -bdev_ocssd_depopulate_namespace(struct nvme_ns *nvme_ns) -{ - struct bdev_ocssd_ns *ocssd_ns; - - ocssd_ns = bdev_ocssd_get_ns_from_nvme(nvme_ns); - - /* If there are outstanding admin requests, we cannot free the context - * here, as they'd write over deallocated memory. Set the populating - * flag, so that the completion callback knows that the namespace is - * being depopulated and finish its deallocation once all requests are - * completed. - */ - if (ocssd_ns->num_outstanding == 0) { - bdev_ocssd_free_namespace(nvme_ns); - } else { - ocssd_ns->depopulate_pending = true; - } -} - -int -bdev_ocssd_create_io_channel(struct nvme_ctrlr_channel *ctrlr_ch) -{ - struct ocssd_io_channel *ocssd_ch; - - ocssd_ch = calloc(1, sizeof(*ocssd_ch)); - if (ocssd_ch == NULL) { - return -ENOMEM; - } - - ocssd_ch->pending_poller = SPDK_POLLER_REGISTER(bdev_ocssd_poll_pending, ctrlr_ch, 0); - if (ocssd_ch->pending_poller == NULL) { - SPDK_ERRLOG("Failed to register pending requests poller\n"); - free(ocssd_ch); - return -ENOMEM; - } - - /* Start the poller paused and only resume it once there are pending requests */ - spdk_poller_pause(ocssd_ch->pending_poller); - - TAILQ_INIT(&ocssd_ch->pending_requests); - ctrlr_ch->ocssd_ch = ocssd_ch; - - return 0; -} - -void -bdev_ocssd_destroy_io_channel(struct nvme_ctrlr_channel *ctrlr_ch) -{ - spdk_poller_unregister(&ctrlr_ch->ocssd_ch->pending_poller); - free(ctrlr_ch->ocssd_ch); -} - -int -bdev_ocssd_init_ctrlr(struct nvme_ctrlr *nvme_ctrlr) -{ - struct ocssd_bdev_ctrlr *ocssd_ctrlr; - - ocssd_ctrlr = calloc(1, sizeof(*ocssd_ctrlr)); - if (!ocssd_ctrlr) { - return -ENOMEM; - } - - ocssd_ctrlr->mm_poller = SPDK_POLLER_REGISTER(bdev_ocssd_poll_mm, nvme_ctrlr, - 10000ULL); - if (!ocssd_ctrlr->mm_poller) { - free(ocssd_ctrlr); - return -ENOMEM; - } - - nvme_ctrlr->ocssd_ctrlr = ocssd_ctrlr; - - return 0; -} - -void -bdev_ocssd_fini_ctrlr(struct nvme_ctrlr *nvme_ctrlr) -{ - spdk_poller_unregister(&nvme_ctrlr->ocssd_ctrlr->mm_poller); - free(nvme_ctrlr->ocssd_ctrlr); - nvme_ctrlr->ocssd_ctrlr = NULL; -} - -SPDK_LOG_REGISTER_COMPONENT(bdev_ocssd) diff --git a/module/bdev/nvme/bdev_ocssd.h b/module/bdev/nvme/bdev_ocssd.h deleted file mode 100644 index fb534be22..000000000 --- a/module/bdev/nvme/bdev_ocssd.h +++ /dev/null @@ -1,61 +0,0 @@ -/*- - * BSD LICENSE - * - * Copyright (c) Intel Corporation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SPDK_BDEV_OCSSD_H -#define SPDK_BDEV_OCSSD_H - -#include "spdk/stdinc.h" -#include "common.h" - -typedef void (*bdev_ocssd_create_cb)(const char *bdev_name, int status, void *ctx); -typedef void (*bdev_ocssd_delete_cb)(int status, void *ctx); - -void bdev_ocssd_create_bdev(const char *ctrlr_name, const char *bdev_name, uint32_t nsid, - bdev_ocssd_create_cb cb_fn, void *cb_arg); -void bdev_ocssd_delete_bdev(const char *bdev_name, bdev_ocssd_delete_cb cb_fn, void *cb_arg); - -void bdev_ocssd_populate_namespace(struct nvme_ctrlr *nvme_ctrlr, - struct nvme_ns *nvme_ns, - struct nvme_async_probe_ctx *ctx); -void bdev_ocssd_depopulate_namespace(struct nvme_ns *nvme_ns); -void bdev_ocssd_namespace_config_json(struct spdk_json_write_ctx *w, struct nvme_ns *nvme_ns); - -int bdev_ocssd_create_io_channel(struct nvme_ctrlr_channel *ioch); -void bdev_ocssd_destroy_io_channel(struct nvme_ctrlr_channel *ioch); - -int bdev_ocssd_init_ctrlr(struct nvme_ctrlr *nvme_ctrlr); -void bdev_ocssd_fini_ctrlr(struct nvme_ctrlr *nvme_ctrlr); - -void bdev_ocssd_handle_chunk_notification(struct nvme_ctrlr *nvme_ctrlr); - -#endif /* SPDK_BDEV_OCSSD_H */ diff --git a/module/bdev/nvme/bdev_ocssd_rpc.c b/module/bdev/nvme/bdev_ocssd_rpc.c deleted file mode 100644 index f0d4b0ef7..000000000 --- a/module/bdev/nvme/bdev_ocssd_rpc.c +++ /dev/null @@ -1,177 +0,0 @@ -/*- - * BSD LICENSE - * - * Copyright (c) Intel Corporation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "spdk/stdinc.h" -#include "spdk/rpc.h" -#include "spdk/string.h" -#include "spdk/util.h" -#include "spdk/log.h" -#include "spdk/likely.h" -#include "bdev_ocssd.h" - -#define BDEV_OCSSD_DEFAULT_NSID 1 - -struct rpc_create_ocssd_bdev { - char *ctrlr_name; - char *bdev_name; - uint32_t nsid; -}; - -static const struct spdk_json_object_decoder rpc_create_ocssd_bdev_decoders[] = { - {"ctrlr_name", offsetof(struct rpc_create_ocssd_bdev, ctrlr_name), spdk_json_decode_string}, - {"bdev_name", offsetof(struct rpc_create_ocssd_bdev, bdev_name), spdk_json_decode_string}, - {"nsid", offsetof(struct rpc_create_ocssd_bdev, nsid), spdk_json_decode_uint32, true}, -}; - -static void -free_rpc_create_ocssd_bdev(struct rpc_create_ocssd_bdev *rpc) -{ - free(rpc->ctrlr_name); - free(rpc->bdev_name); -} - -struct rpc_bdev_ocssd_create_ctx { - struct spdk_jsonrpc_request *request; - struct rpc_create_ocssd_bdev rpc; -}; - -static void -rpc_bdev_ocssd_create_done(const char *bdev_name, int status, void *_ctx) -{ - struct rpc_bdev_ocssd_create_ctx *ctx = _ctx; - struct spdk_json_write_ctx *w; - - if (status != 0) { - spdk_jsonrpc_send_error_response(ctx->request, status, spdk_strerror(-status)); - goto out; - } - - w = spdk_jsonrpc_begin_result(ctx->request); - spdk_json_write_string(w, bdev_name); - spdk_jsonrpc_end_result(ctx->request, w); -out: - free_rpc_create_ocssd_bdev(&ctx->rpc); - free(ctx); -} - -static void -rpc_bdev_ocssd_create(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) -{ - struct rpc_bdev_ocssd_create_ctx *ctx; - - ctx = calloc(1, sizeof(*ctx)); - if (!ctx) { - spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM)); - return; - } - - ctx->rpc.nsid = BDEV_OCSSD_DEFAULT_NSID; - ctx->request = request; - - if (spdk_json_decode_object(params, rpc_create_ocssd_bdev_decoders, - SPDK_COUNTOF(rpc_create_ocssd_bdev_decoders), - &ctx->rpc)) { - spdk_jsonrpc_send_error_response(request, -EINVAL, "Failed to parse the request"); - goto out; - } - - bdev_ocssd_create_bdev(ctx->rpc.ctrlr_name, ctx->rpc.bdev_name, ctx->rpc.nsid, - rpc_bdev_ocssd_create_done, ctx); - return; -out: - free_rpc_create_ocssd_bdev(&ctx->rpc); - free(ctx); -} - -SPDK_RPC_REGISTER("bdev_ocssd_create", rpc_bdev_ocssd_create, SPDK_RPC_RUNTIME) - -struct rpc_delete_ocssd_bdev { - char *name; -}; - -static const struct spdk_json_object_decoder rpc_delete_ocssd_bdev_decoders[] = { - {"name", offsetof(struct rpc_delete_ocssd_bdev, name), spdk_json_decode_string}, -}; - -static void -free_rpc_delete_ocssd_bdev(struct rpc_delete_ocssd_bdev *rpc) -{ - free(rpc->name); -} - -struct rpc_bdev_ocssd_delete_ctx { - struct spdk_jsonrpc_request *request; - struct rpc_delete_ocssd_bdev rpc; -}; - -static void -rpc_bdev_ocssd_delete_done(int status, void *_ctx) -{ - struct rpc_bdev_ocssd_delete_ctx *ctx = _ctx; - - if (status != 0) { - spdk_jsonrpc_send_error_response(ctx->request, status, spdk_strerror(-status)); - goto out; - } - - spdk_jsonrpc_send_bool_response(ctx->request, true); -out: - free_rpc_delete_ocssd_bdev(&ctx->rpc); - free(ctx); -} - -static void -rpc_bdev_ocssd_delete(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) -{ - struct rpc_bdev_ocssd_delete_ctx *ctx; - - ctx = calloc(1, sizeof(*ctx)); - if (!ctx) { - spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM)); - return; - } - - ctx->request = request; - if (spdk_json_decode_object(params, rpc_delete_ocssd_bdev_decoders, - SPDK_COUNTOF(rpc_delete_ocssd_bdev_decoders), - &ctx->rpc)) { - spdk_jsonrpc_send_error_response(request, -EINVAL, "Failed to parse the request"); - free_rpc_delete_ocssd_bdev(&ctx->rpc); - free(ctx); - return; - } - - bdev_ocssd_delete_bdev(ctx->rpc.name, rpc_bdev_ocssd_delete_done, ctx); -} - -SPDK_RPC_REGISTER("bdev_ocssd_delete", rpc_bdev_ocssd_delete, SPDK_RPC_RUNTIME) diff --git a/module/bdev/nvme/common.c b/module/bdev/nvme/common.c index 9e0c57fa4..033dacb3c 100644 --- a/module/bdev/nvme/common.c +++ b/module/bdev/nvme/common.c @@ -32,7 +32,6 @@ */ #include "spdk/env.h" -#include "bdev_ocssd.h" #include "common.h" struct nvme_ctrlrs g_nvme_ctrlrs = TAILQ_HEAD_INITIALIZER(g_nvme_ctrlrs); @@ -130,10 +129,6 @@ nvme_ctrlr_delete(struct nvme_ctrlr *nvme_ctrlr) nvme_ctrlr->opal_dev = NULL; } - if (nvme_ctrlr->ocssd_ctrlr) { - bdev_ocssd_fini_ctrlr(nvme_ctrlr); - } - pthread_mutex_lock(&g_bdev_nvme_mutex); TAILQ_REMOVE(&g_nvme_ctrlrs, nvme_ctrlr, tailq); pthread_mutex_unlock(&g_bdev_nvme_mutex); diff --git a/module/bdev/nvme/common.h b/module/bdev/nvme/common.h index 7cd38c539..1585a6a3c 100644 --- a/module/bdev/nvme/common.h +++ b/module/bdev/nvme/common.h @@ -84,13 +84,11 @@ struct nvme_ns { struct spdk_nvme_ns *ns; struct nvme_ctrlr *ctrlr; struct nvme_bdev *bdev; - void *type_ctx; uint32_t ana_group_id; enum spdk_nvme_ana_state ana_state; }; struct nvme_bdev_io; -struct ocssd_bdev_ctrlr; struct nvme_ctrlr_trid { struct spdk_nvme_transport_id trid; @@ -129,8 +127,6 @@ struct nvme_ctrlr { struct spdk_poller *adminq_timer_poller; struct spdk_thread *thread; - struct ocssd_bdev_ctrlr *ocssd_ctrlr; - bdev_nvme_reset_cb reset_cb_fn; void *reset_cb_arg; struct spdk_nvme_ctrlr_reset_ctx *reset_ctx; @@ -166,14 +162,11 @@ struct nvme_poll_group { uint64_t end_ticks; }; -struct ocssd_io_channel; - struct nvme_ctrlr_channel { struct nvme_ctrlr *ctrlr; struct spdk_nvme_qpair *qpair; struct nvme_poll_group *group; TAILQ_HEAD(, spdk_bdev_io) pending_resets; - struct ocssd_io_channel *ocssd_ch; }; struct nvme_bdev_channel { diff --git a/scripts/rpc.py b/scripts/rpc.py index 05a22fa0d..308e31bc5 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -2362,30 +2362,6 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse help='How often the hotplug is processed for insert and remove events', type=int) p.set_defaults(func=bdev_virtio_blk_set_hotplug) - # OCSSD - def bdev_ocssd_create(args): - nsid = int(args.nsid) if args.nsid is not None else None - print_json(rpc.bdev.bdev_ocssd_create(args.client, - ctrlr_name=args.ctrlr_name, - bdev_name=args.name, - nsid=nsid)) - - p = subparsers.add_parser('bdev_ocssd_create', - help='Creates zoned bdev on specified Open Channel controller') - p.add_argument('-c', '--ctrlr_name', help='Name of the OC NVMe controller', required=True) - p.add_argument('-b', '--name', help='Name of the bdev to create', required=True) - p.add_argument('-n', '--nsid', help='Namespace ID', required=False) - p.set_defaults(func=bdev_ocssd_create) - - def bdev_ocssd_delete(args): - print_json(rpc.bdev.bdev_ocssd_delete(args.client, - name=args.name)) - - p = subparsers.add_parser('bdev_ocssd_delete', - help='Deletes Open Channel bdev') - p.add_argument('name', help='Name of the Open Channel bdev') - p.set_defaults(func=bdev_ocssd_delete) - # ioat def ioat_scan_accel_engine(args): rpc.ioat.ioat_scan_accel_engine(args.client) diff --git a/scripts/rpc/bdev.py b/scripts/rpc/bdev.py index 5e8f5ccdf..b892473b0 100644 --- a/scripts/rpc/bdev.py +++ b/scripts/rpc/bdev.py @@ -1115,34 +1115,6 @@ def bdev_ftl_delete(client, name): return client.call('bdev_ftl_delete', params) -def bdev_ocssd_create(client, ctrlr_name, bdev_name, nsid=None, range=None): - """Creates Open Channel zoned bdev on specified Open Channel controller - - Args: - ctrlr_name: name of the OC NVMe controller - bdev_name: name of the bdev to create - nsid: namespace ID - """ - params = {'ctrlr_name': ctrlr_name, - 'bdev_name': bdev_name} - - if nsid is not None: - params['nsid'] = nsid - - return client.call('bdev_ocssd_create', params) - - -def bdev_ocssd_delete(client, name): - """Deletes Open Channel bdev - - Args: - name: name of the bdev - """ - params = {'name': name} - - return client.call('bdev_ocssd_delete', params) - - @deprecated_alias('get_bdevs') def bdev_get_bdevs(client, name=None): """Get information about block devices. diff --git a/test/common/skipped_tests.txt b/test/common/skipped_tests.txt index 1abcc8cdc..9e1ab3f91 100644 --- a/test/common/skipped_tests.txt +++ b/test/common/skipped_tests.txt @@ -5,6 +5,11 @@ ftl_dirty_shutdown ftl_fio_basic ftl_fio_extended ftl_restore_nv_cache +ftl_bdevperf +ftl_bdevperf_append +ftl_json +ftl_fio +ftl_restore # Waiting for test refactor iscsi_tgt_fio_remote_nvme diff --git a/test/ftl/ftl.sh b/test/ftl/ftl.sh index 7acf6c9b1..940159ad3 100755 --- a/test/ftl/ftl.sh +++ b/test/ftl/ftl.sh @@ -5,6 +5,9 @@ rootdir=$(readlink -f $testdir/../..) source $rootdir/test/common/autotest_common.sh source $testdir/common.sh +# The FTL tests are currently disabled, pending conversion to ZNS from OCSSD. +exit 0 + function at_ftl_exit() { # restore original driver PCI_ALLOWED="$device" PCI_BLOCKED="" DRIVER_OVERRIDE="$ocssd_original_dirver" $rootdir/scripts/setup.sh diff --git a/test/setup/devices.sh b/test/setup/devices.sh index 570fdb024..df196f5d0 100755 --- a/test/setup/devices.sh +++ b/test/setup/devices.sh @@ -175,11 +175,6 @@ min_disk_size=$((1024 ** 3 * 2)) # 2GB for block in "/sys/block/nvme"*; do pci=$(readlink -f "$block/device/device") pci=${pci##*/} - # Skip OCSSD drives if somehow some are still bound to the - # nvme driver. - for ocssd in $OCSSD_PCI_DEVICES; do - [[ $pci == "$ocssd" ]] && continue 2 - done # Skip devices that are in use - simple blkid it to see if # there's any metadata (pt, fs, etc.) present on the drive. # If the drive's size is less than 2G, skip it as we need diff --git a/test/unit/lib/bdev/nvme/Makefile b/test/unit/lib/bdev/nvme/Makefile index 1c56a33d0..7a32ae036 100644 --- a/test/unit/lib/bdev/nvme/Makefile +++ b/test/unit/lib/bdev/nvme/Makefile @@ -34,7 +34,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk -DIRS-y = bdev_nvme.c bdev_ocssd.c +DIRS-y = bdev_nvme.c .PHONY: all clean $(DIRS-y) diff --git a/test/unit/lib/bdev/nvme/bdev_nvme.c/bdev_nvme_ut.c b/test/unit/lib/bdev/nvme/bdev_nvme.c/bdev_nvme_ut.c index c04f95c68..001923eca 100644 --- a/test/unit/lib/bdev/nvme/bdev_nvme.c/bdev_nvme_ut.c +++ b/test/unit/lib/bdev/nvme/bdev_nvme.c/bdev_nvme_ut.c @@ -207,24 +207,6 @@ DEFINE_STUB(spdk_opal_dev_construct, struct spdk_opal_dev *, (struct spdk_nvme_c DEFINE_STUB_V(spdk_opal_dev_destruct, (struct spdk_opal_dev *dev)); -DEFINE_STUB_V(bdev_ocssd_populate_namespace, (struct nvme_ctrlr *nvme_ctrlr, - struct nvme_ns *nvme_ns, struct nvme_async_probe_ctx *ctx)); - -DEFINE_STUB_V(bdev_ocssd_depopulate_namespace, (struct nvme_ns *nvme_ns)); - -DEFINE_STUB_V(bdev_ocssd_namespace_config_json, (struct spdk_json_write_ctx *w, - struct nvme_ns *nvme_ns)); - -DEFINE_STUB(bdev_ocssd_create_io_channel, int, (struct nvme_ctrlr_channel *ioch), 0); - -DEFINE_STUB_V(bdev_ocssd_destroy_io_channel, (struct nvme_ctrlr_channel *ioch)); - -DEFINE_STUB(bdev_ocssd_init_ctrlr, int, (struct nvme_ctrlr *nvme_ctrlr), 0); - -DEFINE_STUB_V(bdev_ocssd_fini_ctrlr, (struct nvme_ctrlr *nvme_ctrlr)); - -DEFINE_STUB_V(bdev_ocssd_handle_chunk_notification, (struct nvme_ctrlr *nvme_ctrlr)); - DEFINE_STUB(spdk_accel_submit_crc32cv, int, (struct spdk_io_channel *ch, uint32_t *dst, struct iovec *iov, uint32_t iov_cnt, uint32_t seed, spdk_accel_completion_cb cb_fn, void *cb_arg), 0); diff --git a/test/unit/lib/bdev/nvme/bdev_ocssd.c/Makefile b/test/unit/lib/bdev/nvme/bdev_ocssd.c/Makefile deleted file mode 100644 index 82046a8a8..000000000 --- a/test/unit/lib/bdev/nvme/bdev_ocssd.c/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -# -# BSD LICENSE -# -# Copyright (c) Intel Corporation. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Intel Corporation nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../../..) - -TEST_FILE = bdev_ocssd_ut.c - -include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk diff --git a/test/unit/lib/bdev/nvme/bdev_ocssd.c/bdev_ocssd_ut.c b/test/unit/lib/bdev/nvme/bdev_ocssd.c/bdev_ocssd_ut.c deleted file mode 100644 index d36dab59c..000000000 --- a/test/unit/lib/bdev/nvme/bdev_ocssd.c/bdev_ocssd_ut.c +++ /dev/null @@ -1,1084 +0,0 @@ -/*- - * BSD LICENSE - * - * Copyright (c) Intel Corporation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "spdk/stdinc.h" -#include "spdk_cunit.h" -#include "spdk/nvme_ocssd_spec.h" -#include "spdk/bdev_module.h" -#include "spdk/util.h" -#include "spdk_internal/mock.h" -#include "thread/thread_internal.h" - -#include "bdev/nvme/bdev_ocssd.c" -#include "bdev/nvme/common.c" -#include "common/lib/test_env.c" -#include "unit/lib/json_mock.c" - -DEFINE_STUB_V(spdk_bdev_module_list_add, (struct spdk_bdev_module *bdev_module)); -DEFINE_STUB(spdk_nvme_ctrlr_is_ocssd_ns, bool, (struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid), - true); -DEFINE_STUB(spdk_nvme_ns_get_extended_sector_size, uint32_t, (struct spdk_nvme_ns *ns), 4096); -DEFINE_STUB(spdk_nvme_ns_get_max_io_xfer_size, uint32_t, (struct spdk_nvme_ns *ns), 0); -DEFINE_STUB(spdk_nvme_ns_is_active, bool, (struct spdk_nvme_ns *ns), true); -DEFINE_STUB_V(spdk_opal_dev_destruct, (struct spdk_opal_dev *dev)); -DEFINE_STUB_V(spdk_bdev_io_complete_nvme_status, (struct spdk_bdev_io *bdev_io, uint32_t cdw0, - int sct, int sc)); -DEFINE_STUB(spdk_bdev_push_media_events, int, (struct spdk_bdev *bdev, - const struct spdk_bdev_media_event *events, - size_t num_events), 0); -DEFINE_STUB_V(spdk_bdev_notify_media_management, (struct spdk_bdev *bdev)); -DEFINE_STUB_V(spdk_bdev_module_fini_done, (void)); -DEFINE_STUB(spdk_nvme_transport_id_trtype_str, const char *, (enum spdk_nvme_transport_type trtype), - NULL); -DEFINE_STUB(spdk_nvme_transport_id_adrfam_str, const char *, (enum spdk_nvmf_adrfam adrfam), NULL); - -struct nvme_request { - spdk_nvme_cmd_cb cb_fn; - void *cb_arg; - TAILQ_ENTRY(nvme_request) tailq; -}; - -struct spdk_nvme_qpair { - TAILQ_HEAD(, nvme_request) requests; -}; - -struct spdk_nvme_ns { - uint32_t nsid; - struct spdk_nvme_ctrlr *ctrlr; -}; - -struct spdk_nvme_ctrlr { - struct spdk_nvme_transport_id trid; - struct spdk_ocssd_geometry_data geometry; - struct spdk_nvme_qpair *admin_qpair; - struct spdk_nvme_ns *ns; - uint32_t ns_count; - struct spdk_ocssd_chunk_information_entry *chunk_info; - uint64_t num_chunks; - - LIST_ENTRY(spdk_nvme_ctrlr) list; -}; - -static LIST_HEAD(, spdk_nvme_ctrlr) g_ctrlr_list = LIST_HEAD_INITIALIZER(g_ctrlr_list); -static TAILQ_HEAD(, spdk_bdev) g_bdev_list = TAILQ_HEAD_INITIALIZER(g_bdev_list); -static struct spdk_thread *g_thread; - -static struct spdk_nvme_ctrlr * -find_controller(const struct spdk_nvme_transport_id *trid) -{ - struct spdk_nvme_ctrlr *ctrlr; - - LIST_FOREACH(ctrlr, &g_ctrlr_list, list) { - if (!spdk_nvme_transport_id_compare(trid, &ctrlr->trid)) { - return ctrlr; - } - } - - return NULL; -} - -static void -free_controller(struct spdk_nvme_ctrlr *ctrlr) -{ - CU_ASSERT(!nvme_ctrlr_get(&ctrlr->trid)); - LIST_REMOVE(ctrlr, list); - spdk_nvme_ctrlr_free_io_qpair(ctrlr->admin_qpair); - free(ctrlr->chunk_info); - free(ctrlr->ns); - free(ctrlr); -} - -static uint64_t -chunk_offset_to_lba(struct spdk_ocssd_geometry_data *geo, uint64_t offset) -{ - uint64_t chk, pu, grp; - uint64_t chk_off, pu_off, grp_off; - - chk_off = geo->lbaf.lbk_len; - pu_off = geo->lbaf.chk_len + chk_off; - grp_off = geo->lbaf.pu_len + pu_off; - - chk = offset % geo->num_chk; - pu = (offset / geo->num_chk) % geo->num_pu; - grp = (offset / (geo->num_chk * geo->num_pu)) % geo->num_grp; - - return chk << chk_off | - pu << pu_off | - grp << grp_off; -} - -static struct spdk_nvme_ctrlr * -create_controller(const struct spdk_nvme_transport_id *trid, uint32_t ns_count, - const struct spdk_ocssd_geometry_data *geo) -{ - struct spdk_nvme_ctrlr *ctrlr; - uint32_t nsid, offset; - - SPDK_CU_ASSERT_FATAL(!find_controller(trid)); - - ctrlr = calloc(1, sizeof(*ctrlr)); - SPDK_CU_ASSERT_FATAL(ctrlr != NULL); - - ctrlr->ns = calloc(ns_count, sizeof(*ctrlr->ns)); - SPDK_CU_ASSERT_FATAL(ctrlr->ns != NULL); - - ctrlr->num_chunks = geo->num_grp * geo->num_pu * geo->num_chk; - ctrlr->chunk_info = calloc(ctrlr->num_chunks, sizeof(*ctrlr->chunk_info)); - SPDK_CU_ASSERT_FATAL(ctrlr->chunk_info != NULL); - - for (nsid = 0; nsid < ns_count; ++nsid) { - ctrlr->ns[nsid].nsid = nsid + 1; - ctrlr->ns[nsid].ctrlr = ctrlr; - } - - ctrlr->geometry = *geo; - ctrlr->trid = *trid; - ctrlr->ns_count = ns_count; - ctrlr->admin_qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0); - - for (offset = 0; offset < ctrlr->num_chunks; ++offset) { - ctrlr->chunk_info[offset].cs.free = 1; - ctrlr->chunk_info[offset].slba = chunk_offset_to_lba(&ctrlr->geometry, offset); - ctrlr->chunk_info[offset].wp = ctrlr->chunk_info[offset].slba; - } - - SPDK_CU_ASSERT_FATAL(ctrlr->admin_qpair != NULL); - - LIST_INSERT_HEAD(&g_ctrlr_list, ctrlr, list); - - return ctrlr; -} - -static int -io_channel_create_cb(void *io_device, void *ctx_buf) -{ - return 0; -} - -static void -io_channel_destroy_cb(void *io_device, void *ctx_buf) -{} - -void -nvme_ctrlr_populate_namespace_done(struct nvme_async_probe_ctx *ctx, - struct nvme_ns *ns, int rc) -{ - CU_ASSERT_EQUAL(rc, 0); - ns->ctrlr->ref++; -} - -static struct nvme_ctrlr * -create_nvme_bdev_controller(const struct spdk_nvme_transport_id *trid, const char *name) -{ - struct spdk_nvme_ctrlr *ctrlr; - struct nvme_ctrlr *nvme_ctrlr; - struct nvme_ctrlr_trid *trid_entry; - uint32_t nsid; - int rc; - - ctrlr = find_controller(trid); - - SPDK_CU_ASSERT_FATAL(ctrlr != NULL); - SPDK_CU_ASSERT_FATAL(!nvme_ctrlr_get(trid)); - - nvme_ctrlr = calloc(1, sizeof(*nvme_ctrlr)); - SPDK_CU_ASSERT_FATAL(nvme_ctrlr != NULL); - - rc = pthread_mutex_init(&nvme_ctrlr->mutex, NULL); - SPDK_CU_ASSERT_FATAL(rc == 0); - - nvme_ctrlr->namespaces = calloc(ctrlr->ns_count, sizeof(struct nvme_ns *)); - SPDK_CU_ASSERT_FATAL(nvme_ctrlr->namespaces != NULL); - - trid_entry = calloc(1, sizeof(struct nvme_ctrlr_trid)); - SPDK_CU_ASSERT_FATAL(trid_entry != NULL); - trid_entry->trid = *trid; - - nvme_ctrlr->ctrlr = ctrlr; - nvme_ctrlr->num_ns = ctrlr->ns_count; - nvme_ctrlr->ref = 1; - nvme_ctrlr->connected_trid = &trid_entry->trid; - nvme_ctrlr->name = strdup(name); - for (nsid = 0; nsid < ctrlr->ns_count; ++nsid) { - nvme_ctrlr->namespaces[nsid] = calloc(1, sizeof(struct nvme_ns)); - SPDK_CU_ASSERT_FATAL(nvme_ctrlr->namespaces[nsid] != NULL); - - nvme_ctrlr->namespaces[nsid]->id = nsid + 1; - nvme_ctrlr->namespaces[nsid]->ctrlr = nvme_ctrlr; - nvme_ctrlr->namespaces[nsid]->type = NVME_NS_OCSSD; - - bdev_ocssd_populate_namespace(nvme_ctrlr, nvme_ctrlr->namespaces[nsid], NULL); - } - - while (spdk_thread_poll(g_thread, 0, 0) > 0) {} - - spdk_io_device_register(nvme_ctrlr, io_channel_create_cb, - io_channel_destroy_cb, 0, name); - - TAILQ_INSERT_TAIL(&g_nvme_ctrlrs, nvme_ctrlr, tailq); - - TAILQ_INIT(&nvme_ctrlr->trids); - TAILQ_INSERT_HEAD(&nvme_ctrlr->trids, trid_entry, link); - - return nvme_ctrlr; -} - -static struct nvme_request * -alloc_request(spdk_nvme_cmd_cb cb_fn, void *cb_arg) -{ - struct nvme_request *ctx; - - ctx = calloc(1, sizeof(*ctx)); - SPDK_CU_ASSERT_FATAL(ctx != NULL); - - ctx->cb_fn = cb_fn; - ctx->cb_arg = cb_arg; - - return ctx; -} - -uint32_t -spdk_nvme_ctrlr_get_num_ns(struct spdk_nvme_ctrlr *ctrlr) -{ - return ctrlr->ns_count; -} - -uint32_t -spdk_nvme_ns_get_id(struct spdk_nvme_ns *ns) -{ - return ns->nsid; -} - -struct spdk_nvme_ctrlr * -spdk_nvme_ns_get_ctrlr(struct spdk_nvme_ns *ns) -{ - return ns->ctrlr; -} - -struct spdk_nvme_ns * -spdk_nvme_ctrlr_get_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid) -{ - if (nsid == 0 || nsid > ctrlr->ns_count) { - return NULL; - } - - return &ctrlr->ns[nsid - 1]; -} - -struct spdk_nvme_ctrlr * -spdk_nvme_connect(const struct spdk_nvme_transport_id *trid, - const struct spdk_nvme_ctrlr_opts *opts, - size_t opts_size) -{ - return find_controller(trid); -} - -int -spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr) -{ - return 0; -} - -struct spdk_bdev * -spdk_bdev_get_by_name(const char *bdev_name) -{ - struct spdk_bdev *bdev; - - SPDK_CU_ASSERT_FATAL(bdev_name != NULL); - - TAILQ_FOREACH(bdev, &g_bdev_list, internal.link) { - if (!strcmp(bdev->name, bdev_name)) { - return bdev; - } - } - - return NULL; -} - -const char * -spdk_bdev_get_name(const struct spdk_bdev *bdev) -{ - return bdev->name; -} - -int -spdk_bdev_register(struct spdk_bdev *bdev) -{ - CU_ASSERT_PTR_NULL(spdk_bdev_get_by_name(bdev->name)); - TAILQ_INSERT_TAIL(&g_bdev_list, bdev, internal.link); - - return 0; -} - -void -spdk_bdev_unregister(struct spdk_bdev *bdev, spdk_bdev_unregister_cb cb_fn, void *cb_arg) -{ - int rc; - - CU_ASSERT_EQUAL(spdk_bdev_get_by_name(bdev->name), bdev); - TAILQ_REMOVE(&g_bdev_list, bdev, internal.link); - - rc = bdev->fn_table->destruct(bdev->ctxt); - if (rc <= 0 && cb_fn != NULL) { - cb_fn(cb_arg, 0); - } -} - -size_t -spdk_bdev_get_zone_size(const struct spdk_bdev *bdev) -{ - return bdev->zone_size; -} - -int -spdk_nvme_ocssd_ctrlr_cmd_geometry(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, - void *payload, uint32_t payload_size, - spdk_nvme_cmd_cb cb_fn, void *cb_arg) -{ - struct spdk_nvme_cpl cpl = {}; - - CU_ASSERT_EQUAL(payload_size, sizeof(ctrlr->geometry)); - memcpy(payload, &ctrlr->geometry, sizeof(ctrlr->geometry)); - - cb_fn(cb_arg, &cpl); - - return 0; -} - -int -spdk_nvme_transport_id_compare(const struct spdk_nvme_transport_id *trid1, - const struct spdk_nvme_transport_id *trid2) -{ - return memcmp(trid1, trid2, sizeof(*trid1)); -} - -void -spdk_bdev_io_get_buf(struct spdk_bdev_io *bdev_io, spdk_bdev_io_get_buf_cb cb, uint64_t len) -{ -} - -void -spdk_bdev_io_complete(struct spdk_bdev_io *bdev_io, enum spdk_bdev_io_status status) -{ -} - -struct spdk_io_channel * -spdk_bdev_io_get_io_channel(struct spdk_bdev_io *bdev_io) -{ - return (struct spdk_io_channel *)bdev_io->internal.ch; -} - -int32_t -spdk_nvme_ctrlr_process_admin_completions(struct spdk_nvme_ctrlr *ctrlr) -{ - return spdk_nvme_qpair_process_completions(ctrlr->admin_qpair, 0); -} - -struct spdk_nvme_qpair * -spdk_nvme_ctrlr_alloc_io_qpair(struct spdk_nvme_ctrlr *ctrlr, - const struct spdk_nvme_io_qpair_opts *opts, - size_t opts_size) -{ - struct spdk_nvme_qpair *qpair; - - qpair = calloc(1, sizeof(*qpair)); - SPDK_CU_ASSERT_FATAL(qpair != NULL); - - TAILQ_INIT(&qpair->requests); - return qpair; -} - -int -spdk_nvme_ctrlr_free_io_qpair(struct spdk_nvme_qpair *qpair) -{ - CU_ASSERT(TAILQ_EMPTY(&qpair->requests)); - free(qpair); - - return 0; -} - -int32_t -spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions) -{ - struct nvme_request *req; - struct spdk_nvme_cpl cpl = {}; - int32_t num_requests = 0; - - while ((req = TAILQ_FIRST(&qpair->requests))) { - TAILQ_REMOVE(&qpair->requests, req, tailq); - - req->cb_fn(req->cb_arg, &cpl); - free(req); - - num_requests++; - } - - return num_requests; -} - -int -spdk_nvme_ns_cmd_readv_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, - uint64_t lba, uint32_t lba_count, - spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags, - spdk_nvme_req_reset_sgl_cb reset_sgl_fn, - spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata, - uint16_t apptag_mask, uint16_t apptag) -{ - struct nvme_request *req; - - req = alloc_request(cb_fn, cb_arg); - TAILQ_INSERT_TAIL(&qpair->requests, req, tailq); - - return 0; -} - -int -spdk_nvme_ns_cmd_writev_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, - uint64_t lba, uint32_t lba_count, - spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags, - spdk_nvme_req_reset_sgl_cb reset_sgl_fn, - spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata, - uint16_t apptag_mask, uint16_t apptag) -{ - struct nvme_request *req; - - req = alloc_request(cb_fn, cb_arg); - TAILQ_INSERT_TAIL(&qpair->requests, req, tailq); - - return 0; -} - -int -spdk_nvme_ocssd_ns_cmd_vector_reset(struct spdk_nvme_ns *ns, - struct spdk_nvme_qpair *qpair, - uint64_t *lba_list, uint32_t num_lbas, - struct spdk_ocssd_chunk_information_entry *chunk_info, - spdk_nvme_cmd_cb cb_fn, void *cb_arg) -{ - struct nvme_request *req; - - req = alloc_request(cb_fn, cb_arg); - TAILQ_INSERT_TAIL(&qpair->requests, req, tailq); - - return 0; -} - -static struct spdk_nvme_cpl g_chunk_info_cpl; -static bool g_zone_info_status = true; - -int -spdk_nvme_ctrlr_cmd_get_log_page(struct spdk_nvme_ctrlr *ctrlr, - uint8_t log_page, uint32_t nsid, - void *payload, uint32_t payload_size, - uint64_t offset, - spdk_nvme_cmd_cb cb_fn, void *cb_arg) -{ - SPDK_CU_ASSERT_FATAL(offset + payload_size <= sizeof(*ctrlr->chunk_info) * ctrlr->num_chunks); - memcpy(payload, ((char *)ctrlr->chunk_info) + offset, payload_size); - - cb_fn(cb_arg, &g_chunk_info_cpl); - - return 0; -} - -static void -create_bdev_cb(const char *bdev_name, int status, void *ctx) -{ - *(int *)ctx = status; -} - -static int -create_bdev(const char *ctrlr_name, const char *bdev_name, uint32_t nsid) -{ - int status = EFAULT; - - bdev_ocssd_create_bdev(ctrlr_name, bdev_name, nsid, create_bdev_cb, &status); - - while (spdk_thread_poll(g_thread, 0, 0) > 0) {} - - return status; -} - -static void -delete_nvme_bdev_controller(struct nvme_ctrlr *nvme_ctrlr) -{ - uint32_t nsid; - - nvme_ctrlr->destruct = true; - - for (nsid = 0; nsid < nvme_ctrlr->num_ns; ++nsid) { - bdev_ocssd_depopulate_namespace(nvme_ctrlr->namespaces[nsid]); - } - - nvme_ctrlr_release(nvme_ctrlr); - spdk_delay_us(1000); - - while (spdk_thread_poll(g_thread, 0, 0) > 0) {} - - CU_ASSERT(TAILQ_EMPTY(&g_nvme_ctrlrs)); -} - -static void -test_create_controller(void) -{ - struct spdk_nvme_ctrlr *ctrlr; - struct nvme_ctrlr *nvme_ctrlr; - struct spdk_nvme_transport_id trid = { .traddr = "00:00:00" }; - struct spdk_ocssd_geometry_data geometry = {}; - struct spdk_bdev *bdev; - const char *controller_name = "nvme0"; - const size_t ns_count = 16; - char namebuf[128]; - uint32_t nsid; - int rc; - - geometry = (struct spdk_ocssd_geometry_data) { - .clba = 512, - .num_chk = 64, - .num_pu = 8, - .num_grp = 4, - .maxoc = 69, - .maxocpu = 68, - .ws_opt = 86, - .lbaf = { - .lbk_len = 9, - .chk_len = 6, - .pu_len = 3, - .grp_len = 2, - } - }; - - ctrlr = create_controller(&trid, ns_count, &geometry); - nvme_ctrlr = create_nvme_bdev_controller(&trid, controller_name); - - for (nsid = 1; nsid <= ns_count; ++nsid) { - snprintf(namebuf, sizeof(namebuf), "%sn%"PRIu32, controller_name, nsid); - rc = create_bdev(controller_name, namebuf, nsid); - CU_ASSERT_EQUAL(rc, 0); - - bdev = spdk_bdev_get_by_name(namebuf); - SPDK_CU_ASSERT_FATAL(bdev != NULL); - CU_ASSERT_TRUE(bdev->zoned); - } - - delete_nvme_bdev_controller(nvme_ctrlr); - - /* Verify that after deletion the bdevs can still be created */ - nvme_ctrlr = create_nvme_bdev_controller(&trid, controller_name); - - for (nsid = 1; nsid <= ns_count; ++nsid) { - snprintf(namebuf, sizeof(namebuf), "%sn%"PRIu32, controller_name, nsid); - rc = create_bdev(controller_name, namebuf, nsid); - CU_ASSERT_EQUAL(rc, 0); - - bdev = spdk_bdev_get_by_name(namebuf); - SPDK_CU_ASSERT_FATAL(bdev != NULL); - CU_ASSERT_TRUE(bdev->zoned); - } - - delete_nvme_bdev_controller(nvme_ctrlr); - - free_controller(ctrlr); -} - -static void -test_device_geometry(void) -{ - struct spdk_nvme_ctrlr *ctrlr; - struct nvme_ctrlr *nvme_ctrlr; - struct spdk_nvme_transport_id trid = { .traddr = "00:00:00" }; - const char *controller_name = "nvme0"; - const char *bdev_name = "nvme0n1"; - struct spdk_ocssd_geometry_data geometry; - struct spdk_bdev *bdev; - int rc; - - geometry = (struct spdk_ocssd_geometry_data) { - .clba = 512, - .num_chk = 64, - .num_pu = 8, - .num_grp = 4, - .maxoc = 69, - .maxocpu = 68, - .ws_opt = 86, - .lbaf = { - .lbk_len = 9, - .chk_len = 6, - .pu_len = 3, - .grp_len = 2, - } - }; - - ctrlr = create_controller(&trid, 1, &geometry); - nvme_ctrlr = create_nvme_bdev_controller(&trid, controller_name); - - rc = create_bdev(controller_name, bdev_name, 1); - CU_ASSERT_EQUAL(rc, 0); - - bdev = spdk_bdev_get_by_name(bdev_name); - CU_ASSERT_EQUAL(bdev->blockcnt, geometry.clba * - geometry.num_chk * - geometry.num_pu * - geometry.num_grp); - CU_ASSERT_EQUAL(bdev->zone_size, geometry.clba); - CU_ASSERT_EQUAL(bdev->optimal_open_zones, geometry.num_pu * geometry.num_grp); - CU_ASSERT_EQUAL(bdev->max_open_zones, geometry.maxocpu); - CU_ASSERT_EQUAL(bdev->write_unit_size, geometry.ws_opt); - - delete_nvme_bdev_controller(nvme_ctrlr); - - free_controller(ctrlr); -} - -static uint64_t -generate_lba(const struct spdk_ocssd_geometry_data *geo, uint64_t lbk, - uint64_t chk, uint64_t pu, uint64_t grp) -{ - uint64_t lba, len; - - lba = lbk; - len = geo->lbaf.lbk_len; - CU_ASSERT(lbk < (1ull << geo->lbaf.lbk_len)); - - lba |= chk << len; - len += geo->lbaf.chk_len; - CU_ASSERT(chk < (1ull << geo->lbaf.chk_len)); - - lba |= pu << len; - len += geo->lbaf.pu_len; - CU_ASSERT(pu < (1ull << geo->lbaf.pu_len)); - - lba |= grp << len; - - return lba; -} - -static void -test_lba_translation(void) -{ - struct spdk_nvme_ctrlr *ctrlr; - struct nvme_ctrlr *nvme_ctrlr; - struct spdk_nvme_transport_id trid = { .traddr = "00:00:00" }; - const char *controller_name = "nvme0"; - const char *bdev_name = "nvme0n1"; - struct spdk_ocssd_geometry_data geometry = {}; - struct bdev_ocssd_ns *ocssd_ns; - struct spdk_bdev *bdev; - uint64_t lba; - int rc; - - geometry = (struct spdk_ocssd_geometry_data) { - .clba = 512, - .num_chk = 64, - .num_pu = 8, - .num_grp = 4, - .lbaf = { - .lbk_len = 9, - .chk_len = 6, - .pu_len = 3, - .grp_len = 2, - } - }; - - ctrlr = create_controller(&trid, 1, &geometry); - nvme_ctrlr = create_nvme_bdev_controller(&trid, controller_name); - SPDK_CU_ASSERT_FATAL(nvme_ctrlr != NULL); - - SPDK_CU_ASSERT_FATAL(nvme_ctrlr->namespaces[0] != NULL); - ocssd_ns = bdev_ocssd_get_ns_from_nvme(nvme_ctrlr->namespaces[0]); - - rc = create_bdev(controller_name, bdev_name, 1); - CU_ASSERT_EQUAL(rc, 0); - - bdev = spdk_bdev_get_by_name(bdev_name); - SPDK_CU_ASSERT_FATAL(bdev != NULL); - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, 0); - CU_ASSERT_EQUAL(lba, generate_lba(&geometry, 0, 0, 0, 0)); - CU_ASSERT_EQUAL(bdev_ocssd_from_disk_lba(ocssd_ns, lba), 0); - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, bdev->zone_size - 1); - CU_ASSERT_EQUAL(lba, generate_lba(&geometry, bdev->zone_size - 1, 0, 0, 0)); - CU_ASSERT_EQUAL(bdev_ocssd_from_disk_lba(ocssd_ns, lba), bdev->zone_size - 1); - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, bdev->zone_size); - CU_ASSERT_EQUAL(lba, generate_lba(&geometry, 0, 0, 1, 0)); - CU_ASSERT_EQUAL(bdev_ocssd_from_disk_lba(ocssd_ns, lba), bdev->zone_size); - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, bdev->zone_size * geometry.num_pu); - CU_ASSERT_EQUAL(lba, generate_lba(&geometry, 0, 0, 0, 1)); - CU_ASSERT_EQUAL(bdev_ocssd_from_disk_lba(ocssd_ns, lba), - bdev->zone_size * geometry.num_pu); - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, bdev->zone_size * geometry.num_pu + 68); - CU_ASSERT_EQUAL(lba, generate_lba(&geometry, 68, 0, 0, 1)); - CU_ASSERT_EQUAL(bdev_ocssd_from_disk_lba(ocssd_ns, lba), - bdev->zone_size * geometry.num_pu + 68); - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, bdev->zone_size + 68); - CU_ASSERT_EQUAL(lba, generate_lba(&geometry, 68, 0, 1, 0)); - CU_ASSERT_EQUAL(bdev_ocssd_from_disk_lba(ocssd_ns, lba), bdev->zone_size + 68); - - delete_nvme_bdev_controller(nvme_ctrlr); - free_controller(ctrlr); - - geometry = (struct spdk_ocssd_geometry_data) { - .clba = 5120, - .num_chk = 501, - .num_pu = 9, - .num_grp = 1, - .lbaf = { - .lbk_len = 13, - .chk_len = 9, - .pu_len = 4, - .grp_len = 1, - } - }; - - ctrlr = create_controller(&trid, 1, &geometry); - nvme_ctrlr = create_nvme_bdev_controller(&trid, controller_name); - SPDK_CU_ASSERT_FATAL(nvme_ctrlr != NULL); - - SPDK_CU_ASSERT_FATAL(nvme_ctrlr->namespaces[0] != NULL); - ocssd_ns = bdev_ocssd_get_ns_from_nvme(nvme_ctrlr->namespaces[0]); - - rc = create_bdev(controller_name, bdev_name, 1); - CU_ASSERT_EQUAL(rc, 0); - - bdev = spdk_bdev_get_by_name(bdev_name); - SPDK_CU_ASSERT_FATAL(bdev != NULL); - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, 0); - CU_ASSERT_EQUAL(lba, generate_lba(&geometry, 0, 0, 0, 0)); - CU_ASSERT_EQUAL(bdev_ocssd_from_disk_lba(ocssd_ns, lba), 0); - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, bdev->zone_size - 1); - CU_ASSERT_EQUAL(lba, generate_lba(&geometry, bdev->zone_size - 1, 0, 0, 0)); - CU_ASSERT_EQUAL(bdev_ocssd_from_disk_lba(ocssd_ns, lba), bdev->zone_size - 1); - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, bdev->zone_size); - CU_ASSERT_EQUAL(lba, generate_lba(&geometry, 0, 0, 1, 0)); - CU_ASSERT_EQUAL(bdev_ocssd_from_disk_lba(ocssd_ns, lba), bdev->zone_size); - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, bdev->zone_size * (geometry.num_pu - 1)); - CU_ASSERT_EQUAL(lba, generate_lba(&geometry, 0, 0, geometry.num_pu - 1, 0)); - CU_ASSERT_EQUAL(bdev_ocssd_from_disk_lba(ocssd_ns, lba), - bdev->zone_size * (geometry.num_pu - 1)); - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, - bdev->zone_size * geometry.num_pu * geometry.num_grp); - CU_ASSERT_EQUAL(lba, generate_lba(&geometry, 0, 1, 0, 0)); - CU_ASSERT_EQUAL(bdev_ocssd_from_disk_lba(ocssd_ns, lba), - bdev->zone_size * geometry.num_pu * geometry.num_grp); - - lba = bdev_ocssd_to_disk_lba(ocssd_ns, - bdev->zone_size * geometry.num_pu * geometry.num_grp + 68); - CU_ASSERT_EQUAL(lba, generate_lba(&geometry, 68, 1, 0, 0)); - CU_ASSERT_EQUAL(bdev_ocssd_from_disk_lba(ocssd_ns, lba), - bdev->zone_size * geometry.num_pu * geometry.num_grp + 68); - - delete_nvme_bdev_controller(nvme_ctrlr); - - free_controller(ctrlr); -} - -static void -get_zone_info_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) -{ - CU_ASSERT_EQUAL(g_zone_info_status, success); -} - -static uint64_t -generate_chunk_offset(const struct spdk_ocssd_geometry_data *geo, uint64_t chk, - uint64_t pu, uint64_t grp) -{ - return grp * geo->num_pu * geo->num_chk + - pu * geo->num_chk + chk; -} - -static struct spdk_bdev_io * -alloc_ocssd_io(void) -{ - struct spdk_bdev_io *bdev_io; - - bdev_io = calloc(1, sizeof(struct spdk_bdev_io) + sizeof(struct bdev_ocssd_io)); - SPDK_CU_ASSERT_FATAL(bdev_io != NULL); - - return bdev_io; -} - -static struct spdk_ocssd_chunk_information_entry * -get_chunk_info(struct spdk_nvme_ctrlr *ctrlr, uint64_t offset) -{ - assert(offset < ctrlr->num_chunks); - SPDK_CU_ASSERT_FATAL(offset < ctrlr->num_chunks); - return &ctrlr->chunk_info[offset]; -} - -enum chunk_state { - CHUNK_STATE_FREE, - CHUNK_STATE_CLOSED, - CHUNK_STATE_OPEN, - CHUNK_STATE_OFFLINE -}; - -static void -set_chunk_state(struct spdk_ocssd_chunk_information_entry *chunk, enum chunk_state state) -{ - memset(&chunk->cs, 0, sizeof(chunk->cs)); - switch (state) { - case CHUNK_STATE_FREE: - chunk->cs.free = 1; - break; - case CHUNK_STATE_CLOSED: - chunk->cs.closed = 1; - break; - case CHUNK_STATE_OPEN: - chunk->cs.open = 1; - break; - case CHUNK_STATE_OFFLINE: - chunk->cs.offline = 1; - break; - default: - SPDK_CU_ASSERT_FATAL(0 && "Invalid state"); - } -} - -static void -test_get_zone_info(void) -{ - struct spdk_nvme_ctrlr *ctrlr; - struct nvme_ctrlr *nvme_ctrlr; - struct spdk_nvme_transport_id trid = { .traddr = "00:00:00" }; - const char *controller_name = "nvme0"; - const char *bdev_name = "nvme0n1"; - struct spdk_bdev *bdev; - struct nvme_bdev *nvme_bdev; - struct spdk_bdev_io *bdev_io; - struct spdk_io_channel *ch; - struct nvme_bdev_channel *nbdev_ch; - struct nvme_ns *nvme_ns; - struct nvme_ctrlr_channel ctrlr_ch = {}; -#define MAX_ZONE_INFO_COUNT 64 - struct spdk_bdev_zone_info zone_info[MAX_ZONE_INFO_COUNT]; - struct spdk_ocssd_chunk_information_entry *chunk_info; - struct spdk_ocssd_geometry_data geometry; - uint64_t chunk_offset; - int rc, offset; - - geometry = (struct spdk_ocssd_geometry_data) { - .clba = 512, - .num_chk = 64, - .num_pu = 8, - .num_grp = 4, - .lbaf = { - .lbk_len = 9, - .chk_len = 6, - .pu_len = 3, - .grp_len = 2, - } - }; - - ctrlr = create_controller(&trid, 1, &geometry); - nvme_ctrlr = create_nvme_bdev_controller(&trid, controller_name); - - rc = create_bdev(controller_name, bdev_name, 1); - CU_ASSERT_EQUAL(rc, 0); - - bdev = spdk_bdev_get_by_name(bdev_name); - SPDK_CU_ASSERT_FATAL(bdev != NULL); - - nvme_bdev = (struct nvme_bdev *)bdev->ctxt; - nvme_ns = nvme_bdev->nvme_ns; - SPDK_CU_ASSERT_FATAL(nvme_ns != NULL); - - ch = calloc(1, sizeof(*ch) + sizeof(*nbdev_ch)); - SPDK_CU_ASSERT_FATAL(ch != NULL); - - nbdev_ch = spdk_io_channel_get_ctx(ch); - nbdev_ch->nvme_ns = nvme_ns; - nbdev_ch->ctrlr_ch = &ctrlr_ch; - ctrlr_ch.ctrlr = nvme_ctrlr; - ctrlr_ch.qpair = (struct spdk_nvme_qpair *)0x1; - - bdev_io = alloc_ocssd_io(); - bdev_io->internal.cb = get_zone_info_cb; - bdev_io->internal.ch = (struct spdk_bdev_channel *)ch; - bdev_io->bdev = bdev; - bdev_io->type = SPDK_BDEV_IO_TYPE_GET_ZONE_INFO; - - /* Verify empty zone */ - bdev_io->u.zone_mgmt.zone_id = 0; - bdev_io->u.zone_mgmt.num_zones = 1; - bdev_io->u.zone_mgmt.buf = &zone_info; - chunk_info = get_chunk_info(ctrlr, 0); - set_chunk_state(chunk_info, CHUNK_STATE_FREE); - chunk_info->wp = 0; - - rc = _bdev_ocssd_submit_request(ch, bdev_io); - CU_ASSERT_EQUAL(rc, 0); - - CU_ASSERT_EQUAL(zone_info[0].state, SPDK_BDEV_ZONE_STATE_EMPTY); - CU_ASSERT_EQUAL(zone_info[0].zone_id, 0); - CU_ASSERT_EQUAL(zone_info[0].write_pointer, 0); - CU_ASSERT_EQUAL(zone_info[0].capacity, geometry.clba); - - /* Verify open zone */ - bdev_io->u.zone_mgmt.zone_id = bdev->zone_size; - bdev_io->u.zone_mgmt.num_zones = 1; - bdev_io->u.zone_mgmt.buf = &zone_info; - chunk_info = get_chunk_info(ctrlr, generate_chunk_offset(&geometry, 0, 1, 0)); - set_chunk_state(chunk_info, CHUNK_STATE_OPEN); - chunk_info->wp = chunk_info->slba + 68; - chunk_info->cnlb = 511; - chunk_info->ct.size_deviate = 1; - - rc = _bdev_ocssd_submit_request(ch, bdev_io); - CU_ASSERT_EQUAL(rc, 0); - - CU_ASSERT_EQUAL(zone_info[0].state, SPDK_BDEV_ZONE_STATE_OPEN); - CU_ASSERT_EQUAL(zone_info[0].zone_id, bdev->zone_size); - CU_ASSERT_EQUAL(zone_info[0].write_pointer, bdev->zone_size + 68); - CU_ASSERT_EQUAL(zone_info[0].capacity, chunk_info->cnlb); - - /* Verify offline zone at 2nd chunk */ - bdev_io->u.zone_mgmt.zone_id = bdev->zone_size * geometry.num_pu * geometry.num_grp; - bdev_io->u.zone_mgmt.num_zones = 1; - bdev_io->u.zone_mgmt.buf = &zone_info; - chunk_info = get_chunk_info(ctrlr, generate_chunk_offset(&geometry, 1, 0, 0)); - set_chunk_state(chunk_info, CHUNK_STATE_OFFLINE); - chunk_info->wp = chunk_info->slba; - - rc = _bdev_ocssd_submit_request(ch, bdev_io); - CU_ASSERT_EQUAL(rc, 0); - - CU_ASSERT_EQUAL(zone_info[0].state, SPDK_BDEV_ZONE_STATE_OFFLINE); - CU_ASSERT_EQUAL(zone_info[0].zone_id, bdev_io->u.zone_mgmt.zone_id); - CU_ASSERT_EQUAL(zone_info[0].write_pointer, bdev_io->u.zone_mgmt.zone_id); - - /* Verify multiple zones at a time */ - bdev_io->u.zone_mgmt.zone_id = 0; - bdev_io->u.zone_mgmt.num_zones = MAX_ZONE_INFO_COUNT; - bdev_io->u.zone_mgmt.buf = &zone_info; - - for (offset = 0; offset < MAX_ZONE_INFO_COUNT; ++offset) { - chunk_offset = generate_chunk_offset(&geometry, - (offset / (geometry.num_grp * geometry.num_pu)) % geometry.num_chk, - offset % geometry.num_pu, - (offset / geometry.num_pu) % geometry.num_grp); - - - chunk_info = get_chunk_info(ctrlr, chunk_offset); - set_chunk_state(chunk_info, CHUNK_STATE_OPEN); - chunk_info->wp = chunk_info->slba + 68; - chunk_info->ct.size_deviate = 0; - } - - rc = _bdev_ocssd_submit_request(ch, bdev_io); - CU_ASSERT_EQUAL(rc, 0); - - for (offset = 0; offset < MAX_ZONE_INFO_COUNT; ++offset) { - CU_ASSERT_EQUAL(zone_info[offset].state, SPDK_BDEV_ZONE_STATE_OPEN); - CU_ASSERT_EQUAL(zone_info[offset].zone_id, bdev->zone_size * offset); - CU_ASSERT_EQUAL(zone_info[offset].write_pointer, bdev->zone_size * offset + 68); - CU_ASSERT_EQUAL(zone_info[offset].capacity, geometry.clba); - } - - /* Verify misaligned start zone LBA */ - bdev_io->u.zone_mgmt.zone_id = 1; - bdev_io->u.zone_mgmt.num_zones = MAX_ZONE_INFO_COUNT; - bdev_io->u.zone_mgmt.buf = &zone_info; - - rc = _bdev_ocssd_submit_request(ch, bdev_io); - CU_ASSERT_EQUAL(rc, -EINVAL); - - /* Verify correct NVMe error forwarding */ - bdev_io->u.zone_mgmt.zone_id = 0; - bdev_io->u.zone_mgmt.num_zones = MAX_ZONE_INFO_COUNT; - bdev_io->u.zone_mgmt.buf = &zone_info; - chunk_info = get_chunk_info(ctrlr, 0); - set_chunk_state(chunk_info, CHUNK_STATE_FREE); - - rc = _bdev_ocssd_submit_request(ch, bdev_io); - CU_ASSERT_EQUAL(rc, 0); - g_chunk_info_cpl = (struct spdk_nvme_cpl) { - .status = { - .sct = SPDK_NVME_SCT_GENERIC, - .sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR - } - }; - g_zone_info_status = false; - - g_chunk_info_cpl = (struct spdk_nvme_cpl) {}; - g_zone_info_status = true; - - delete_nvme_bdev_controller(nvme_ctrlr); - - free(bdev_io); - free(ch); - free_controller(ctrlr); -} - -int -main(int argc, const char **argv) -{ - CU_pSuite suite = NULL; - unsigned int num_failures; - - CU_set_error_action(CUEA_ABORT); - CU_initialize_registry(); - - suite = CU_add_suite("ocssd", NULL, NULL); - - CU_ADD_TEST(suite, test_create_controller); - CU_ADD_TEST(suite, test_device_geometry); - CU_ADD_TEST(suite, test_lba_translation); - CU_ADD_TEST(suite, test_get_zone_info); - - g_thread = spdk_thread_create("test", NULL); - spdk_set_thread(g_thread); - - CU_basic_set_mode(CU_BRM_VERBOSE); - CU_basic_run_tests(); - num_failures = CU_get_number_of_failures(); - - spdk_thread_exit(g_thread); - while (!spdk_thread_is_exited(g_thread)) { - spdk_thread_poll(g_thread, 0, 0); - } - spdk_thread_destroy(g_thread); - - CU_cleanup_registry(); - - return num_failures; -} diff --git a/test/unit/unittest.sh b/test/unit/unittest.sh index 1fada56bd..4c50fd8b4 100755 --- a/test/unit/unittest.sh +++ b/test/unit/unittest.sh @@ -14,7 +14,6 @@ cd "$rootdir" function unittest_bdev() { $valgrind $testdir/lib/bdev/bdev.c/bdev_ut - $valgrind $testdir/lib/bdev/nvme/bdev_ocssd.c/bdev_ocssd_ut $valgrind $testdir/lib/bdev/nvme/bdev_nvme.c/bdev_nvme_ut $valgrind $testdir/lib/bdev/raid/bdev_raid.c/bdev_raid_ut $valgrind $testdir/lib/bdev/bdev_zone.c/bdev_zone_ut