Commit aaf2e048 authored by Chaitanya Kulkarni's avatar Chaitanya Kulkarni Committed by Christoph Hellwig

nvmet: add ZBD over ZNS backend support

NVMe TP 4053 – Zoned Namespaces (ZNS) allows host software to
communicate with a non-volatile memory subsystem using zones for NVMe
protocol-based controllers. NVMeOF already support the ZNS NVMe
Protocol compliant devices on the target in the passthru mode. There
are generic zoned block devices like  Shingled Magnetic Recording (SMR)
HDDs that are not based on the NVMe protocol.

This patch adds ZNS backend support for non-ZNS zoned block devices as
NVMeOF targets.

This support includes implementing the new command set NVME_CSI_ZNS,
adding different command handlers for ZNS command set such as NVMe
Identify Controller, NVMe Identify Namespace, NVMe Zone Append,
NVMe Zone Management Send and NVMe Zone Management Receive.

With the new command set identifier, we also update the target command
effects logs to reflect the ZNS compliant commands.
Signed-off-by: default avatarChaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
Reviewed-by: default avatarDamien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent ab5d0b38
......@@ -12,6 +12,7 @@ obj-$(CONFIG_NVME_TARGET_TCP) += nvmet-tcp.o
nvmet-y += core.o configfs.o admin-cmd.o fabrics-cmd.o \
discovery.o io-cmd-file.o io-cmd-bdev.o
nvmet-$(CONFIG_NVME_TARGET_PASSTHRU) += passthru.o
nvmet-$(CONFIG_BLK_DEV_ZONED) += zns.o
nvme-loop-y += loop.o
nvmet-rdma-y += rdma.o
nvmet-fc-y += fc.o
......
......@@ -179,6 +179,13 @@ static void nvmet_get_cmd_effects_nvm(struct nvme_effects_log *log)
log->iocs[nvme_cmd_write_zeroes] = cpu_to_le32(1 << 0);
}
static void nvmet_get_cmd_effects_zns(struct nvme_effects_log *log)
{
log->iocs[nvme_cmd_zone_append] = cpu_to_le32(1 << 0);
log->iocs[nvme_cmd_zone_mgmt_send] = cpu_to_le32(1 << 0);
log->iocs[nvme_cmd_zone_mgmt_recv] = cpu_to_le32(1 << 0);
}
static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
{
struct nvme_effects_log *log;
......@@ -194,6 +201,14 @@ static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
case NVME_CSI_NVM:
nvmet_get_cmd_effects_nvm(log);
break;
case NVME_CSI_ZNS:
if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
status = NVME_SC_INVALID_IO_CMD_SET;
goto free;
}
nvmet_get_cmd_effects_nvm(log);
nvmet_get_cmd_effects_zns(log);
break;
default:
status = NVME_SC_INVALID_LOG_PAGE;
goto free;
......@@ -647,6 +662,12 @@ static bool nvmet_handle_identify_desclist(struct nvmet_req *req)
case NVME_CSI_NVM:
nvmet_execute_identify_desclist(req);
return true;
case NVME_CSI_ZNS:
if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
nvmet_execute_identify_desclist(req);
return true;
}
return false;
default:
return false;
}
......@@ -666,12 +687,32 @@ static void nvmet_execute_identify(struct nvmet_req *req)
break;
}
break;
case NVME_ID_CNS_CS_NS:
if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
switch (req->cmd->identify.csi) {
case NVME_CSI_ZNS:
return nvmet_execute_identify_cns_cs_ns(req);
default:
break;
}
}
break;
case NVME_ID_CNS_CTRL:
switch (req->cmd->identify.csi) {
case NVME_CSI_NVM:
return nvmet_execute_identify_ctrl(req);
}
break;
case NVME_ID_CNS_CS_CTRL:
if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
switch (req->cmd->identify.csi) {
case NVME_CSI_ZNS:
return nvmet_execute_identify_cns_cs_ctrl(req);
default:
break;
}
}
break;
case NVME_ID_CNS_NS_ACTIVE_LIST:
switch (req->cmd->identify.csi) {
case NVME_CSI_NVM:
......
......@@ -16,6 +16,7 @@
#include "nvmet.h"
struct workqueue_struct *buffered_io_wq;
struct workqueue_struct *zbd_wq;
static const struct nvmet_fabrics_ops *nvmet_transports[NVMF_TRTYPE_MAX];
static DEFINE_IDA(cntlid_ida);
......@@ -883,6 +884,10 @@ static u16 nvmet_parse_io_cmd(struct nvmet_req *req)
if (req->ns->file)
return nvmet_file_parse_io_cmd(req);
return nvmet_bdev_parse_io_cmd(req);
case NVME_CSI_ZNS:
if (IS_ENABLED(CONFIG_BLK_DEV_ZONED))
return nvmet_bdev_zns_parse_io_cmd(req);
return NVME_SC_INVALID_IO_CMD_SET;
default:
return NVME_SC_INVALID_IO_CMD_SET;
}
......@@ -1592,11 +1597,15 @@ static int __init nvmet_init(void)
nvmet_ana_group_enabled[NVMET_DEFAULT_ANA_GRPID] = 1;
zbd_wq = alloc_workqueue("nvmet-zbd-wq", WQ_MEM_RECLAIM, 0);
if (!zbd_wq)
return -ENOMEM;
buffered_io_wq = alloc_workqueue("nvmet-buffered-io-wq",
WQ_MEM_RECLAIM, 0);
if (!buffered_io_wq) {
error = -ENOMEM;
goto out;
goto out_free_zbd_work_queue;
}
error = nvmet_init_discovery();
......@@ -1612,7 +1621,8 @@ static int __init nvmet_init(void)
nvmet_exit_discovery();
out_free_work_queue:
destroy_workqueue(buffered_io_wq);
out:
out_free_zbd_work_queue:
destroy_workqueue(zbd_wq);
return error;
}
......@@ -1622,6 +1632,7 @@ static void __exit nvmet_exit(void)
nvmet_exit_discovery();
ida_destroy(&cntlid_ida);
destroy_workqueue(buffered_io_wq);
destroy_workqueue(zbd_wq);
BUILD_BUG_ON(sizeof(struct nvmf_disc_rsp_page_entry) != 1024);
BUILD_BUG_ON(sizeof(struct nvmf_disc_rsp_page_hdr) != 1024);
......
......@@ -47,6 +47,14 @@ void nvmet_bdev_set_limits(struct block_device *bdev, struct nvme_id_ns *id)
id->nows = to0based(ql->io_opt / ql->logical_block_size);
}
void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
{
if (ns->bdev) {
blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ);
ns->bdev = NULL;
}
}
static void nvmet_bdev_ns_enable_integrity(struct nvmet_ns *ns)
{
struct blk_integrity *bi = bdev_get_integrity(ns->bdev);
......@@ -86,15 +94,15 @@ int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY_T10))
nvmet_bdev_ns_enable_integrity(ns);
return 0;
}
void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
{
if (ns->bdev) {
blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ);
ns->bdev = NULL;
if (bdev_is_zoned(ns->bdev)) {
if (!nvmet_bdev_zns_enable(ns)) {
nvmet_bdev_ns_disable(ns);
return -EINVAL;
}
ns->csi = NVME_CSI_ZNS;
}
return 0;
}
void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns)
......@@ -102,7 +110,7 @@ void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns)
ns->size = i_size_read(ns->bdev->bd_inode);
}
static u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts)
u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts)
{
u16 status = NVME_SC_SUCCESS;
......
......@@ -250,6 +250,10 @@ struct nvmet_subsys {
unsigned int admin_timeout;
unsigned int io_timeout;
#endif /* CONFIG_NVME_TARGET_PASSTHRU */
#ifdef CONFIG_BLK_DEV_ZONED
u8 zasl;
#endif /* CONFIG_BLK_DEV_ZONED */
};
static inline struct nvmet_subsys *to_subsys(struct config_item *item)
......@@ -335,6 +339,12 @@ struct nvmet_req {
struct work_struct work;
bool use_workqueue;
} p;
#ifdef CONFIG_BLK_DEV_ZONED
struct {
struct bio inline_bio;
struct work_struct zmgmt_work;
} z;
#endif /* CONFIG_BLK_DEV_ZONED */
};
int sg_cnt;
int metadata_sg_cnt;
......@@ -354,6 +364,7 @@ struct nvmet_req {
};
extern struct workqueue_struct *buffered_io_wq;
extern struct workqueue_struct *zbd_wq;
static inline void nvmet_set_result(struct nvmet_req *req, u32 result)
{
......@@ -403,6 +414,7 @@ u16 nvmet_parse_connect_cmd(struct nvmet_req *req);
void nvmet_bdev_set_limits(struct block_device *bdev, struct nvme_id_ns *id);
u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req);
u16 nvmet_file_parse_io_cmd(struct nvmet_req *req);
u16 nvmet_bdev_zns_parse_io_cmd(struct nvmet_req *req);
u16 nvmet_parse_admin_cmd(struct nvmet_req *req);
u16 nvmet_parse_discovery_cmd(struct nvmet_req *req);
u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req);
......@@ -530,6 +542,14 @@ void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid);
void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns);
int nvmet_file_ns_revalidate(struct nvmet_ns *ns);
void nvmet_ns_revalidate(struct nvmet_ns *ns);
u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts);
bool nvmet_bdev_zns_enable(struct nvmet_ns *ns);
void nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req);
void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req);
void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req);
void nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req);
void nvmet_bdev_execute_zone_append(struct nvmet_req *req);
static inline u32 nvmet_rw_data_len(struct nvmet_req *req)
{
......
This diff is collapsed.
......@@ -944,6 +944,13 @@ struct nvme_zone_mgmt_recv_cmd {
enum {
NVME_ZRA_ZONE_REPORT = 0,
NVME_ZRASF_ZONE_REPORT_ALL = 0,
NVME_ZRASF_ZONE_STATE_EMPTY = 0x01,
NVME_ZRASF_ZONE_STATE_IMP_OPEN = 0x02,
NVME_ZRASF_ZONE_STATE_EXP_OPEN = 0x03,
NVME_ZRASF_ZONE_STATE_CLOSED = 0x04,
NVME_ZRASF_ZONE_STATE_READONLY = 0x05,
NVME_ZRASF_ZONE_STATE_FULL = 0x06,
NVME_ZRASF_ZONE_STATE_OFFLINE = 0x07,
NVME_REPORT_ZONE_PARTIAL = 1,
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment