From d39c4443d43c9f9ab10fa35965af4af45b55b593 Mon Sep 17 00:00:00 2001 From: Ben Walker Date: Fri, 27 Aug 2021 13:23:56 -0700 Subject: [PATCH] bdev/nvme: Remove OCSSD support As far as we're aware, this is not in use by anyone. OCSSD has largely been replaced by ZNS and no OCSSD drives made it to the market. Change-Id: I020ee277da5292f8c4777f224acafd87586f8238 Signed-off-by: Ben Walker Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/9328 Tested-by: SPDK CI Jenkins Community-CI: Mellanox Build Bot Community-CI: Broadcom CI Reviewed-by: Shuhei Matsumoto Reviewed-by: Changpeng Liu Reviewed-by: Dong Yi Reviewed-by: Jim Harris --- CHANGELOG.md | 4 + doc/ftl.md | 90 - doc/jsonrpc.md | 73 - module/bdev/nvme/Makefile | 2 +- module/bdev/nvme/bdev_nvme.c | 37 +- module/bdev/nvme/bdev_ocssd.c | 1596 ----------------- module/bdev/nvme/bdev_ocssd.h | 61 - module/bdev/nvme/bdev_ocssd_rpc.c | 177 -- module/bdev/nvme/common.c | 5 - module/bdev/nvme/common.h | 7 - scripts/rpc.py | 24 - scripts/rpc/bdev.py | 28 - test/common/skipped_tests.txt | 5 + test/ftl/ftl.sh | 3 + test/setup/devices.sh | 5 - test/unit/lib/bdev/nvme/Makefile | 2 +- .../lib/bdev/nvme/bdev_nvme.c/bdev_nvme_ut.c | 18 - test/unit/lib/bdev/nvme/bdev_ocssd.c/Makefile | 38 - .../bdev/nvme/bdev_ocssd.c/bdev_ocssd_ut.c | 1084 ----------- test/unit/unittest.sh | 1 - 20 files changed, 18 insertions(+), 3242 deletions(-) delete mode 100644 module/bdev/nvme/bdev_ocssd.c delete mode 100644 module/bdev/nvme/bdev_ocssd.h delete mode 100644 module/bdev/nvme/bdev_ocssd_rpc.c delete mode 100644 test/unit/lib/bdev/nvme/bdev_ocssd.c/Makefile delete mode 100644 test/unit/lib/bdev/nvme/bdev_ocssd.c/bdev_ocssd_ut.c 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