From fa58cf908e76613a4c9ea84bc96c83bd92354822 Mon Sep 17 00:00:00 2001
From: sunshihao <sunshihao@huawei.com>
Date: Mon, 1 Mar 2021 10:59:02 +0800
Subject: [PATCH 23/27] spdk: add nvme support for HSAK

Signed-off-by: sunshihao <sunshihao@huawei.com>
---
 configure                         |   2 +-
 include/spdk/bdev.h               |   7 +-
 include/spdk/bdev_module.h        |   4 +-
 include/spdk/nvme.h               |  51 +--------
 include/spdk/thread.h             |   2 +
 lib/bdev/bdev.c                   |  53 +++++++---
 lib/bdev/bdev_self.c              |  36 +++----
 lib/env_dpdk/env.mk               |   2 +-
 lib/env_dpdk/init.c               |   8 +-
 lib/event/reactor.c               |  13 +--
 lib/nvme/nvme.c                   |  35 +++----
 lib/nvme/nvme_ctrlr.c             |  33 ++++--
 lib/nvme/nvme_ctrlr_cmd.c         |  33 +++---
 lib/nvme/nvme_ctrlr_self.c        |   3 +
 lib/nvme/nvme_internal.h          |   5 +-
 lib/nvme/nvme_ns_cmd.c            |   2 +-
 lib/nvme/nvme_pcie.c              |   6 +-
 lib/nvme/nvme_pcie_common.c       |  12 ++-
 lib/nvme/nvme_qpair.c             |  13 +--
 lib/nvme/nvme_uevent.h            |   2 -
 lib/thread/thread.c               |  21 ++--
 mk/spdk.common.mk                 |   2 +-
 module/bdev/nvme/bdev_nvme.c      |  50 +++++----
 module/bdev/nvme/bdev_nvme_self.c | 167 ++++++++++++------------------
 module/bdev/nvme/bdev_nvme_self.h |   2 +-
 module/bdev/nvme/common.h         |   1 +
 scripts/setup_self.sh             |  11 +-
 27 files changed, 279 insertions(+), 297 deletions(-)

diff --git a/configure b/configure
index 964322e..01db27a 100644
--- a/configure
+++ b/configure
@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/bin/bash
 
 set -e
 
diff --git a/include/spdk/bdev.h b/include/spdk/bdev.h
index d0284d9..5f30340 100644
--- a/include/spdk/bdev.h
+++ b/include/spdk/bdev.h
@@ -862,7 +862,7 @@ int spdk_bdev_read_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *c
  *   * -ENOMEM - spdk_bdev_io buffer cannot be allocated
  */
 int spdk_bdev_read_blocks_with_md(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
-				  void *buf, void *md, int64_t offset_blocks, uint64_t num_blocks,
+				  void *buf, void *md, uint64_t offset_blocks, uint64_t num_blocks,
 				  spdk_bdev_io_completion_cb cb, void *cb_arg);
 
 /**
@@ -1410,12 +1410,13 @@ int spdk_bdev_unmap(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
  * negated errno on failure, in which case the callback will not be called.
  */
 int spdk_bdev_unmap_multiblocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
-				void *unmap_d, uint16_t unmap_count,
+				void *unmap_d, uint32_t unmap_count,
 				spdk_bdev_io_completion_cb cb, void *cb_arg);
 
 void *spdk_bdev_get_channel_group(struct spdk_io_channel *io_ch);
 void *spdk_bdev_io_get_pool(size_t nbytes);
-bool spdk_bdev_have_io_in_channel(struct spdk_io_channel *bdevIoCh);
+bool spdk_bdev_have_io_in_channel(struct spdk_io_channel *io_ch);
+int spdk_bdev_get_channel_state(struct spdk_io_channel *io_ch);
 #endif
 
 /**
diff --git a/include/spdk/bdev_module.h b/include/spdk/bdev_module.h
index 55dc980..e901e14 100644
--- a/include/spdk/bdev_module.h
+++ b/include/spdk/bdev_module.h
@@ -267,8 +267,10 @@ enum reqLocation_E {
 };
 
 void spdk_bdev_nvme_remove_cb(void *cb_ctx, void *ctrlr);
-void spdk_bdev_fail_ctrlr(const char *traddr);
+void spdk_bdev_fail_ctrlr(void *cb_ctx, void *ctrlr);
+struct spdk_nvme_ctrlr *spdk_nvme_bdev_ctrlr_get(char *trid);
 void *nvme_channel_get_group(void *io_ch);
+int nvme_channel_get_state(void *io_ch);
 #endif
 
 /** bdev I/O completion status */
diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h
index 9acfb89..fb2e5f9 100644
--- a/include/spdk/nvme.h
+++ b/include/spdk/nvme.h
@@ -3495,7 +3495,7 @@ bool spdk_nvme_ctrlr_is_format_supported(struct spdk_nvme_ctrlr *ctrlr);
 bool spdk_nvme_ctrlr_is_format_all_ns(struct spdk_nvme_ctrlr *ctrlr);
 bool spdk_nvme_ctrlr_is_directive_supported(struct spdk_nvme_ctrlr *ctrlr);
 bool spdk_nvme_ctrlr_is_streams_supported(struct spdk_nvme_ctrlr *ctrlr);
-int32_t spdk_nvme_ctrlr_identify_directives(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid,
+int32_t spdk_nvme_ctrlr_identify_directives(struct spdk_nvme_ctrlr *ctrlr, uint16_t nsid,
 		void *payload);
 int32_t spdk_nvme_ctrlr_enable_streams(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid);
 int32_t spdk_nvme_ctrlr_ret_streams_param(struct spdk_nvme_ctrlr *ctrlr, void *payload);
@@ -3523,58 +3523,13 @@ int spdk_bdev_nvme_create_self(struct spdk_nvme_transport_id *trid, const char *
 			       const char **names, size_t *count, const char *hostnqn);
 
 int spdk_nvme_detach_ublock(struct spdk_nvme_ctrlr *ctrlr);
-void spdk_nvme_ctrlr_update_unvmcap(struct spdk_nvme_ctrlr *ctrlr);
-
-#define SPDK_NVME_UEVENT_SUBSYSTEM_UIO 1
-#define SPDK_NVME_UEVENT_SUBSYSTEM_NVME 2
-
-enum spdk_nvme_uevent_action {
-	SPDK_NVME_UEVENT_ADD = 0,
-	SPDK_NVME_UEVENT_REMOVE = 1,
-};
-
-struct spdk_uevent {
-	/* remove or add */
-	enum spdk_nvme_uevent_action action;
-	int subsystem;
-	/* pci address of device */
-	char traddr[SPDK_NVMF_TRADDR_MAX_LEN + 1];
-};
-
-int nvme_uevent_connect(void);
-int nvme_get_uevent(int fd, struct spdk_uevent *uevent);
-int nvme_get_uevent_block(int fd, struct spdk_uevent *uevent);
 int32_t spdk_rebind_driver(char *pci_addr, char *driver_name);
+void spdk_nvme_ctrlr_update_unvmcap(struct spdk_nvme_ctrlr *ctrlr);
+void spdk_nvme_ctrlr_fail_hotplug(struct spdk_nvme_ctrlr *ctrlr);
 bool spdk_nvme_ns_pi_md_start(struct spdk_nvme_ns *ns);
 bool spdk_nvme_ns_is_dataset_mng_supported(struct spdk_nvme_ns *ns);
 uint16_t spdk_nvme_get_qpair_id(struct spdk_nvme_qpair *qpair);
 
-/**
- * \brief Submits a write I/O to the specified NVMe namespace.
- *
- * \param ns NVMe namespace to submit the write I/O
- * \param qpair I/O queue pair to submit the request
- * \param lba starting LBA to write the data
- * \param lba_count length (in sectors) for the write operation
- * \param streamId The stream id for write I/O
- * \param cb_fn callback function to invoke when the I/O is completed
- * \param cb_arg argument to pass to the callback function
- * \param io_flags set flags, defined in nvme_spec.h, for this I/O
- * \param reset_sgl_fn callback function to reset scattered payload
- * \param next_sge_fn callback function to iterate each scattered
- * payload memory segment
- *
- * \return 0 if successfully submitted, ENOMEM if an nvme_request
- *	     structure cannot be allocated for the I/O request
- *
- * The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
- * The user must ensure that only one thread submits I/O on a given qpair at any given time.
- */
-int spdk_nvme_ns_cmd_writev_stream(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
-				   uint64_t lba, uint32_t lba_count, uint16_t streamId,
-				   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);
 #endif
 
 /*
diff --git a/include/spdk/thread.h b/include/spdk/thread.h
index 7c52433..9fea1bd 100644
--- a/include/spdk/thread.h
+++ b/include/spdk/thread.h
@@ -73,6 +73,8 @@ void spdk_reactors_use(bool useOrNot);
 bool spdk_get_reactor_type(void);
 
 void spdk_set_thread_exited(struct spdk_thread *thread);
+
+uint32_t spdk_get_channel_ref(void *io_ch);
 #endif
 
 /**
diff --git a/lib/bdev/bdev.c b/lib/bdev/bdev.c
index 1d8ce99..6daaef9 100644
--- a/lib/bdev/bdev.c
+++ b/lib/bdev/bdev.c
@@ -1546,7 +1546,11 @@ void
 spdk_bdev_module_finish_done(void)
 {
 	if (spdk_get_thread() != g_fini_thread) {
+#ifndef SPDK_CONFIG_APP_RW
 		spdk_thread_send_msg(g_fini_thread, bdev_module_finish_iter, NULL);
+#else
+		bdev_module_finish_iter(NULL);
+#endif
 	} else {
 		bdev_module_finish_iter(NULL);
 	}
@@ -3096,10 +3100,12 @@ bdev_channel_destroy(void *io_device, void *ctx_buf)
 	SPDK_DEBUGLOG(bdev, "Destroying channel %p for bdev %s on thread %p\n", ch, ch->bdev->name,
 		      spdk_get_thread());
 
+#ifndef SPDK_CONFIG_APP_RW
 	/* This channel is going away, so add its statistics into the bdev so that they don't get lost. */
 	pthread_mutex_lock(&ch->bdev->internal.mutex);
 	bdev_io_stat_add(&ch->bdev->internal.stat, &ch->stat);
 	pthread_mutex_unlock(&ch->bdev->internal.mutex);
+#endif
 
 	mgmt_ch = shared_resource->mgmt_ch;
 
@@ -3592,7 +3598,7 @@ bdev_build_contig_io(uint8_t type, void *buf, void *md_buf, uint64_t offset_bloc
 
 static int
 bdev_read_blocks_with_md(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf,
-			 void *md_buf, int64_t offset_blocks, uint64_t num_blocks,
+			 void *md_buf, uint64_t offset_blocks, uint64_t num_blocks,
 			 spdk_bdev_io_completion_cb cb, void *cb_arg)
 {
 	struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(desc);
@@ -3656,20 +3662,22 @@ spdk_bdev_read_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
 
 int
 spdk_bdev_read_blocks_with_md(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
-			      void *buf, void *md_buf, int64_t offset_blocks, uint64_t num_blocks,
+			      void *buf, void *md_buf, uint64_t offset_blocks, uint64_t num_blocks,
 			      spdk_bdev_io_completion_cb cb, void *cb_arg)
 {
+#ifndef SPDK_CONFIG_APP_RW
 	struct iovec iov = {
 		.iov_base = buf,
 	};
-#ifndef SPDK_CONFIG_APP_RW
+
 	if (!spdk_bdev_is_md_separate(spdk_bdev_desc_get_bdev(desc))) {
 		return -EINVAL;
 	}
-#endif
+
 	if (!_bdev_io_check_md_buf(&iov, md_buf)) {
 		return -EINVAL;
 	}
+#endif
 
 	return bdev_read_blocks_with_md(desc, ch, buf, md_buf, offset_blocks, num_blocks,
 					cb, cb_arg);
@@ -3835,19 +3843,19 @@ spdk_bdev_write_blocks_with_md(struct spdk_bdev_desc *desc, struct spdk_io_chann
 			       void *buf, void *md_buf, uint64_t offset_blocks, uint64_t num_blocks,
 			       spdk_bdev_io_completion_cb cb, void *cb_arg)
 {
+#ifndef SPDK_CONFIG_APP_RW
 	struct iovec iov = {
 		.iov_base = buf,
 	};
 
-#ifndef SPDK_CONFIG_APP_RW
 	if (!spdk_bdev_is_md_separate(spdk_bdev_desc_get_bdev(desc))) {
 		return -EINVAL;
 	}
-#endif
+
 	if (!_bdev_io_check_md_buf(&iov, md_buf)) {
 		return -EINVAL;
 	}
-
+#endif
 	return bdev_write_blocks_with_md(desc, ch, buf, md_buf, offset_blocks, num_blocks,
 					 cb, cb_arg);
 }
@@ -5158,12 +5166,14 @@ bdev_io_complete(void *ctx)
 			bdev_io->internal.io_submit_ch = NULL;
 		}
 
+		if (bdev_io->internal.in_submit_request) {
+			bdev_io->internal.in_submit_request = false;
+		}
 		/*
 		 * Defer completion to avoid potential infinite recursion if the
 		 * user's completion callback issues a new I/O.
 		 */
-		spdk_thread_send_msg(spdk_bdev_io_get_thread(bdev_io),
-				     bdev_io_complete, bdev_io);
+		bdev_io_complete(bdev_io);
 		return;
 	}
 
@@ -5214,7 +5224,7 @@ bdev_io_complete(void *ctx)
 			break;
 		}
 #ifdef SPDK_CONFIG_APP_RW
-		bdev_io_stat_update(bdev_io, tsc, &bdev_io->internal.ch->stat);
+		bdev_io_stat_update(bdev_io, tsc_diff, &bdev_io->internal.ch->stat);
 #endif
 	}
 
@@ -5647,10 +5657,12 @@ bdev_start(struct spdk_bdev *bdev)
 	SPDK_DEBUGLOG(bdev, "Inserting bdev %s into list\n", bdev->name);
 	TAILQ_INSERT_TAIL(&g_bdev_mgr.bdevs, bdev, internal.link);
 
+#ifndef SPDK_CONFIG_APP_RW
 	/* Examine configuration before initializing I/O */
 	bdev_examine(bdev);
 
 	spdk_bdev_wait_for_examine(bdev_start_finished, bdev);
+#endif
 }
 
 int
@@ -5729,7 +5741,14 @@ bdev_unregister_unsafe(struct spdk_bdev *bdev)
 		 */
 		desc->refs++;
 		pthread_mutex_unlock(&desc->mutex);
-		spdk_thread_send_msg(desc->thread, _remove_notify, desc);
+	}
+
+	TAILQ_FOREACH_SAFE(desc, &bdev->internal.open_descs, link, tmp) {
+		pthread_mutex_unlock(&bdev->internal.mutex);
+		pthread_mutex_unlock(&g_bdev_mgr.mutex);
+		_remove_notify(desc);
+		pthread_mutex_lock(&bdev->internal.mutex);
+		pthread_mutex_lock(&g_bdev_mgr.mutex);
 	}
 
 	/* If there are no descriptors, proceed removing the bdev */
@@ -5794,7 +5813,6 @@ static int
 bdev_start_qos(struct spdk_bdev *bdev)
 {
 	struct set_qos_limit_ctx *ctx;
-
 	/* Enable QoS */
 	if (bdev->internal.qos && bdev->internal.qos->thread == NULL) {
 		ctx = calloc(1, sizeof(*ctx));
@@ -6010,7 +6028,6 @@ spdk_bdev_close(struct spdk_bdev_desc *desc)
 	if (bdev->internal.status == SPDK_BDEV_STATUS_REMOVING && TAILQ_EMPTY(&bdev->internal.open_descs)) {
 		rc = bdev_unregister_unsafe(bdev);
 		pthread_mutex_unlock(&bdev->internal.mutex);
-
 		if (rc == 0) {
 			bdev_fini(bdev);
 		}
@@ -7054,6 +7071,16 @@ spdk_bdev_get_channel_group(struct spdk_io_channel *io_ch)
 	return nvme_channel_get_group(nvme_io_ch);
 }
 
+int
+spdk_bdev_get_channel_state(struct spdk_io_channel *io_ch)
+{
+	struct spdk_bdev_channel *ch = spdk_io_channel_get_ctx(io_ch);
+	struct spdk_io_channel *under_io_ch = ch->channel;
+	void *nvme_io_ch = spdk_io_channel_get_ctx(under_io_ch);
+
+	return nvme_channel_get_state(nvme_io_ch);
+}
+
 bool
 spdk_bdev_have_io_in_channel(struct spdk_io_channel *io_ch)
 {
diff --git a/lib/bdev/bdev_self.c b/lib/bdev/bdev_self.c
index 7050c30..c5b92a3 100644
--- a/lib/bdev/bdev_self.c
+++ b/lib/bdev/bdev_self.c
@@ -30,10 +30,8 @@ struct libstorage_bdev_io_stat *g_io_stat_map;
 int32_t g_libstorage_iostat = 0;
 int32_t g_polltime_threshold = 0;
 
-void
-spdk_bdev_init_iostat(struct spdk_bdev_channel *ch, struct spdk_bdev *bdev,
-		      struct spdk_io_channel *io_ch,
-		      struct spdk_bdev_io_stat *stat)
+void spdk_bdev_init_iostat(struct spdk_bdev_channel *ch, struct spdk_bdev *bdev,
+			   struct spdk_io_channel *io_ch, struct spdk_bdev_io_stat *stat)
 {
 	int		i = 0;
 	bool		find = false;
@@ -95,9 +93,8 @@ spdk_bdev_init_iostat(struct spdk_bdev_channel *ch, struct spdk_bdev *bdev,
 	stat->interval_tsc = spdk_get_ticks_hz() / 10;
 }
 
-void
-spdk_bdev_destroy_iostat(struct spdk_bdev_channel *ch, struct spdk_bdev *bdev,
-			 struct spdk_io_channel *io_ch)
+void spdk_bdev_destroy_iostat(struct spdk_bdev_channel *ch, struct spdk_bdev *bdev,
+			      struct spdk_io_channel *io_ch)
 {
 	int		i = 0;
 	uint16_t	channel_id;
@@ -127,10 +124,9 @@ spdk_bdev_destroy_iostat(struct spdk_bdev_channel *ch, struct spdk_bdev *bdev,
 	}
 }
 
-int
-spdk_bdev_unmap_multiblocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
-			    void *unmap_d, uint16_t unmap_count,
-			    spdk_bdev_io_completion_cb cb, void *cb_arg)
+int spdk_bdev_unmap_multiblocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
+				void *unmap_d, uint32_t unmap_count,
+				spdk_bdev_io_completion_cb cb, void *cb_arg)
 {
 	struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(desc);
 	struct spdk_bdev_io *bdev_io = NULL;
@@ -152,38 +148,38 @@ spdk_bdev_unmap_multiblocks(struct spdk_bdev_desc *desc, struct spdk_io_channel
 	return 0;
 }
 
-void
-bdev_io_stat_update(struct spdk_bdev_io *bdev_io, uint64_t tsc, struct spdk_bdev_io_stat *stat)
+void bdev_io_stat_update(struct spdk_bdev_io *bdev_io, uint64_t tsc_diff,
+			 struct spdk_bdev_io_stat *stat)
 {
 	switch (bdev_io->type) {
 	case SPDK_BDEV_IO_TYPE_READ_NVME:
 		stat->bytes_read += bdev_io->u.contig.nbytes + bdev_io->u.contig.md_len;
 		stat->num_read_ops++;
-		stat->read_latency_ticks += (tsc - bdev_io->internal.submit_tsc);
+		stat->read_latency_ticks += tsc_diff;
 		break;
 	case SPDK_BDEV_IO_TYPE_WRITE_NVME:
 		stat->bytes_written += bdev_io->u.contig.nbytes + bdev_io->u.contig.md_len;
 		stat->num_write_ops++;
-		stat->write_latency_ticks += (tsc - bdev_io->internal.submit_tsc);
+		stat->write_latency_ticks += tsc_diff;
 		break;
 	case SPDK_BDEV_IO_TYPE_READV_NVME:
 		stat->bytes_read += bdev_io->u.bdev.nbytes;
 		stat->num_read_ops++;
-		stat->read_latency_ticks += (tsc - bdev_io->internal.submit_tsc);
+		stat->read_latency_ticks += tsc_diff;
 		break;
 	case SPDK_BDEV_IO_TYPE_WRITEV_NVME:
 		stat->bytes_written += bdev_io->u.bdev.nbytes;
 		stat->num_write_ops++;
-		stat->write_latency_ticks += (tsc - bdev_io->internal.submit_tsc);
+		stat->write_latency_ticks += tsc_diff;
 		break;
 	default:
 		break;
 	}
 }
 
-void
-bdev_update_iostat_map(struct spdk_bdev_io *bdev_io, uint64_t tsc, struct spdk_bdev_io_stat *stat,
-		       struct spdk_io_channel *channel, uint64_t io_outstanding)
+void bdev_update_iostat_map(struct spdk_bdev_io *bdev_io, uint64_t tsc,
+			    struct spdk_bdev_io_stat *stat,
+			    struct spdk_io_channel *channel, uint64_t io_outstanding)
 {
 	uint64_t	num_poll_timeout;
 
diff --git a/lib/env_dpdk/env.mk b/lib/env_dpdk/env.mk
index 292dd91..1e4f63c 100644
--- a/lib/env_dpdk/env.mk
+++ b/lib/env_dpdk/env.mk
@@ -120,7 +120,7 @@ endif
 endif
 
 DPDK_SHARED_LIB = $(DPDK_LIB_LIST:%=$(DPDK_ABS_DIR)/lib/lib%.so)
-DPDK_STATIC_LIB = $(DPDK_LIB_LIST:%=$(DPDK_ABS_DIR)/lib/lib%.a)
+DPDK_STATIC_LIB = $(DPDK_LIB_LIST:%=/usr/lib64/lib%.a)
 DPDK_SHARED_LIB_LINKER_ARGS = $(call add_no_as_needed,$(DPDK_SHARED_LIB))
 DPDK_STATIC_LIB_LINKER_ARGS = $(call add_whole_archive,$(DPDK_STATIC_LIB))
 
diff --git a/lib/env_dpdk/init.c b/lib/env_dpdk/init.c
index 3bb713d..1c18a8b 100644
--- a/lib/env_dpdk/init.c
+++ b/lib/env_dpdk/init.c
@@ -561,12 +561,12 @@ spdk_env_init(const struct spdk_env_opts *opts)
 		return -EINVAL;
 	}
 
-	SPDK_PRINTF("Starting %s / %s initialization...\n", SPDK_VERSION_STRING, rte_version());
-	SPDK_PRINTF("[ DPDK EAL parameters: ");
+	printf("Starting %s / %s initialization...\n", SPDK_VERSION_STRING, rte_version());
+	printf("[ DPDK EAL parameters: ");
 	for (i = 0; i < g_eal_cmdline_argcount; i++) {
-		SPDK_PRINTF("%s ", g_eal_cmdline[i]);
+		printf("%s ", g_eal_cmdline[i]);
 	}
-	SPDK_PRINTF("]\n");
+	printf("]\n");
 
 	/* DPDK rearranges the array we pass to it, so make a copy
 	 * before passing so we can still free the individual strings
diff --git a/lib/event/reactor.c b/lib/event/reactor.c
index 3eb8799..9d92875 100644
--- a/lib/event/reactor.c
+++ b/lib/event/reactor.c
@@ -55,6 +55,7 @@
 #endif
 
 #define SPDK_EVENT_BATCH_SIZE		8
+#define SPDK_EVENT_MAX_BATCH_SIZE	32
 
 #ifdef SPDK_CONFIG_APP_RW
 struct spdk_iodev_thread_info lcore_thread_info[RTE_MAX_LCORE];
@@ -262,7 +263,7 @@ spdk_reactors_init(void)
 	sp = spdk_conf_find_section(NULL, "Reactor");
 	if (sp != 0) {
 		g_reactor_batch_size = spdk_conf_section_get_intval(sp, "BatchSize");
-		if (g_reactor_batch_size <= 0 || g_reactor_batch_size > SPDK_EVENT_BATCH_SIZE) {
+		if (g_reactor_batch_size <= 0 || g_reactor_batch_size > SPDK_EVENT_MAX_BATCH_SIZE) {
 			g_reactor_batch_size = SPDK_EVENT_BATCH_SIZE;
 		}
 		syslog(LOG_INFO, "BatchSize is set to %d\n", g_reactor_batch_size);
@@ -550,7 +551,7 @@ static inline uint32_t
 event_queue_run_batch(struct spdk_reactor *reactor)
 {
 	unsigned count, i;
-	void *events[SPDK_EVENT_BATCH_SIZE];
+	void *events[SPDK_EVENT_MAX_BATCH_SIZE];
 	struct spdk_thread *thread;
 	struct spdk_lw_thread *lw_thread;
 
@@ -969,9 +970,6 @@ reactor_run(void *arg)
 		}
 
 		if (g_reactor_state != SPDK_REACTOR_STATE_RUNNING) {
-#ifdef SPDK_CONFIG_APP_RW
-			lcore_thread_info[reactor->lcore].state = SPDK_THREAD_STATE_EXITED;
-#endif
 			break;
 		}
 	}
@@ -1003,7 +1001,10 @@ reactor_run(void *arg)
 			}
 		}
 	}
-
+#ifdef SPDK_CONFIG_APP_RW
+	/* When all thread in reactor is finish, inform libstorage to release resource. */
+	lcore_thread_info[reactor->lcore].state = SPDK_THREAD_STATE_EXITED;
+#endif
 	return 0;
 }
 
diff --git a/lib/nvme/nvme.c b/lib/nvme/nvme.c
index fca2f41..b0cc321 100644
--- a/lib/nvme/nvme.c
+++ b/lib/nvme/nvme.c
@@ -39,6 +39,7 @@
 #include "spdk/nvme.h"
 #include "spdk_internal/debug.h"
 #include "spdk/bdev_module.h"
+#include <sys/prctl.h>
 
 #define SPDK_NVME_DRIVER_NAME "spdk_nvme_driver"
 
@@ -100,6 +101,9 @@ static void admin_timer_timeout(void)
 
 static void *nvme_ctrlr_run_admin_timer(void *arg)
 {
+#if defined(__linux__)
+	prctl(PR_SET_NAME, "nvme-admin", 0, 0, 0);
+#endif
 	sleep(20);
 
 	while (1) {
@@ -561,6 +565,11 @@ nvme_request_check_timeout(struct nvme_request *req, uint16_t cid,
 			   struct spdk_nvme_ctrlr_process *active_proc,
 			   uint64_t now_tick)
 {
+	if (req == NULL) {
+		SPDK_WARNLOG("Get invalid req from tracker!\n");
+		return 1;
+	}
+
 	struct spdk_nvme_qpair *qpair = req->qpair;
 	struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr;
 
@@ -599,26 +608,16 @@ nvme_request_check_timeout(struct nvme_request *req, uint16_t cid,
 				   nvme_qpair_is_admin_queue(qpair) ? NULL : qpair,
 				   cid);
 #else
-	if (!nvme_qpair_is_admin_queue(qpair) && (req->cmd.opc == SPDK_NVME_OPC_WRITE ||
-			req->cmd.opc == SPDK_NVME_OPC_READ)) {
-		SPDK_WARNLOG("IO timeout, OP[%u] NS[%u] LBA[%lu].\n", req->cmd.opc, req->cmd.nsid,
-			     *(uint64_t *)&req->cmd.cdw10);
-	} else {
-		SPDK_WARNLOG("%s Command[%u] timeout.\n", nvme_qpair_is_admin_queue(qpair) ?
-			     "Admin" : "IO", req->cmd.opc);
-	}
-	if (req->timed_out) {
-		/* Reset the controller if the command was already timed out. */
-		SPDK_WARNLOG("IO Command[%u] timeout again, reset controller.\n", cid);
-		active_proc->timeout_cb_fn(active_proc->timeout_cb_arg, ctrlr, NULL, cid);
-	} else {
+	if (!req->timed_out) {
 		req->timed_out = true;
-		active_proc->timeout_cb_fn(active_proc->timeout_cb_arg, ctrlr,
-					   nvme_qpair_is_admin_queue(qpair) ? NULL : qpair,
-					   cid);
-		/* Timing again. Reset the controller if it times out again */
-		req->submit_tick = spdk_get_ticks();
+		SPDK_WARNLOG("%s Command[%u] timeout. ctrlr=%p qpair=%p cid=%u\n",
+			     nvme_qpair_is_admin_queue(qpair) ? "Admin" : "IO",
+			     req->cmd.opc, ctrlr, qpair, cid);
 	}
+	active_proc->timeout_cb_fn(active_proc->timeout_cb_arg, ctrlr,
+				   nvme_qpair_is_admin_queue(qpair) ? NULL : qpair, cid);
+	/* Update submit tick to reduce timeout num. */
+	req->submit_tick = spdk_get_ticks();
 #endif
 	return 0;
 }
diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c
index fa28f07..27468a7 100644
--- a/lib/nvme/nvme_ctrlr.c
+++ b/lib/nvme/nvme_ctrlr.c
@@ -34,6 +34,7 @@
 #include "spdk/stdinc.h"
 
 #include "nvme_internal.h"
+#include "nvme_pcie_internal.h"
 #include "nvme_io_msg.h"
 
 #include "spdk/env.h"
@@ -512,7 +513,6 @@ spdk_nvme_ctrlr_free_io_qpair(struct spdk_nvme_qpair *qpair)
 	}
 
 	ctrlr = qpair->ctrlr;
-
 	if (qpair->in_completion_context) {
 		/*
 		 * There are many cases where it is convenient to delete an io qpair in the context
@@ -543,12 +543,16 @@ spdk_nvme_ctrlr_free_io_qpair(struct spdk_nvme_qpair *qpair)
 	 * exits unexpectedly.  In that case, we must not try to abort any reqs associated
 	 * with that qpair, since the callbacks will also be foreign to this process.
 	 */
+
+	if (ctrlr == NULL) {
+		return 0;
+	}
+
 	if (qpair->active_proc == nvme_ctrlr_get_current_process(ctrlr)) {
 		nvme_qpair_abort_reqs(qpair, 1);
 	}
 
 	nvme_robust_mutex_lock(&ctrlr->ctrlr_lock);
-
 	nvme_ctrlr_proc_remove_io_qpair(qpair);
 
 	TAILQ_REMOVE(&ctrlr->active_io_qpairs, qpair, tailq);
@@ -907,6 +911,16 @@ spdk_nvme_ctrlr_fail(struct spdk_nvme_ctrlr *ctrlr)
 	nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock);
 }
 
+#ifdef SPDK_CONFIG_APP_RW
+void
+spdk_nvme_ctrlr_fail_hotplug(struct spdk_nvme_ctrlr *ctrlr)
+{
+	nvme_robust_mutex_lock(&ctrlr->ctrlr_lock);
+	nvme_ctrlr_fail(ctrlr, true);
+	nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock);
+}
+#endif
+
 static void
 nvme_ctrlr_shutdown_async(struct spdk_nvme_ctrlr *ctrlr,
 			  struct nvme_ctrlr_detach_ctx *ctx)
@@ -1102,7 +1116,6 @@ nvme_ctrlr_disable(struct spdk_nvme_ctrlr *ctrlr)
 	return 0;
 }
 
-#ifdef DEBUG
 static const char *
 nvme_ctrlr_state_string(enum nvme_ctrlr_state state)
 {
@@ -1182,7 +1195,6 @@ nvme_ctrlr_state_string(enum nvme_ctrlr_state state)
 	}
 	return "unknown";
 };
-#endif /* DEBUG */
 
 static void
 nvme_ctrlr_set_state(struct spdk_nvme_ctrlr *ctrlr, enum nvme_ctrlr_state state,
@@ -1209,12 +1221,12 @@ nvme_ctrlr_set_state(struct spdk_nvme_ctrlr *ctrlr, enum nvme_ctrlr_state state,
 	}
 
 	ctrlr->state_timeout_tsc = timeout_in_ticks + now_ticks;
-	SPDK_DEBUGLOG(nvme, "setting state to %s (timeout %" PRIu64 " ms)\n",
-		      nvme_ctrlr_state_string(ctrlr->state), timeout_in_ms);
+	SPDK_NOTICELOG("setting state to %s (timeout %" PRIu64 " ms)\n",
+		       nvme_ctrlr_state_string(ctrlr->state), timeout_in_ms);
 	return;
 inf:
-	SPDK_DEBUGLOG(nvme, "setting state to %s (no timeout)\n",
-		      nvme_ctrlr_state_string(ctrlr->state));
+	SPDK_NOTICELOG("setting state to %s (no timeout)\n",
+		       nvme_ctrlr_state_string(ctrlr->state));
 	ctrlr->state_timeout_tsc = NVME_TIMEOUT_INFINITE;
 }
 
@@ -2729,7 +2741,6 @@ struct spdk_nvme_ctrlr_process *
 nvme_ctrlr_get_process(struct spdk_nvme_ctrlr *ctrlr, pid_t pid)
 {
 	struct spdk_nvme_ctrlr_process	*active_proc;
-
 	TAILQ_FOREACH(active_proc, &ctrlr->active_procs, tailq) {
 		if (active_proc->pid == pid) {
 			return active_proc;
@@ -4135,6 +4146,10 @@ spdk_nvme_ctrlr_alloc_qid(struct spdk_nvme_ctrlr *ctrlr)
 void
 spdk_nvme_ctrlr_free_qid(struct spdk_nvme_ctrlr *ctrlr, uint16_t qid)
 {
+	if (ctrlr->free_io_qids == NULL) {
+		return;
+	}
+
 	assert(qid <= ctrlr->opts.num_io_queues);
 
 	nvme_robust_mutex_lock(&ctrlr->ctrlr_lock);
diff --git a/lib/nvme/nvme_ctrlr_cmd.c b/lib/nvme/nvme_ctrlr_cmd.c
index d335bc6..7a7e625 100644
--- a/lib/nvme/nvme_ctrlr_cmd.c
+++ b/lib/nvme/nvme_ctrlr_cmd.c
@@ -581,16 +581,18 @@ nvme_ctrlr_retry_queued_abort(struct spdk_nvme_ctrlr *ctrlr)
 		rc = nvme_ctrlr_submit_admin_request(ctrlr, next);
 		if (rc < 0) {
 			SPDK_ERRLOG("Failed to submit queued abort.\n");
-#ifndef SPDK_CONFIG_APP_RW
+#ifdef SPDK_CONFIG_APP_RW
+			/* If submit abort fail, free all req in queued aborts */
+			ctrlr->outstanding_aborts--;
+			nvme_free_request(next);
+			goto free;
+#else
 			memset(&next->cpl, 0, sizeof(next->cpl));
 			next->cpl.status.sct = SPDK_NVME_SCT_GENERIC;
 			next->cpl.status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
 			next->cpl.status.dnr = 1;
 			nvme_complete_request(next->cb_fn, next->cb_arg, next->qpair, next, &next->cpl);
 			nvme_free_request(next);
-#else
-			nvme_free_request(next);
-			break;
 #endif
 		} else {
 			/* If the first abort succeeds, stop iterating. */
@@ -598,17 +600,13 @@ nvme_ctrlr_retry_queued_abort(struct spdk_nvme_ctrlr *ctrlr)
 		}
 	}
 
+	return;
 #ifdef SPDK_CONFIG_APP_RW
-	nvme_robust_mutex_lock(&ctrlr->ctrlr_lock);
-	if (rc < 0) {
-		/* If abort fail, free all of the queued abort requests */
-		STAILQ_FOREACH_SAFE(next, &ctrlr->queued_aborts, stailq, tmp) {
-			STAILQ_REMOVE_HEAD(&ctrlr->queued_aborts, stailq);
-			nvme_free_request(next);
-			ctrlr->outstanding_aborts--;
-		}
+free:
+	STAILQ_FOREACH_SAFE(next, &ctrlr->queued_aborts, stailq, tmp) {
+		STAILQ_REMOVE_HEAD(&ctrlr->queued_aborts, stailq);
+		nvme_free_request(next);
 	}
-	nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock);
 #endif
 }
 
@@ -635,9 +633,10 @@ nvme_ctrlr_cmd_abort_cpl(void *ctx, const struct spdk_nvme_cpl *cpl)
 	ctrlr = req->qpair->ctrlr;
 
 	ctrlr->outstanding_aborts--;
-	nvme_ctrlr_retry_queued_abort(ctrlr);
-
+	/* If abort is failed, just reset the ctrlr. */
 	req->user_cb_fn(req->user_cb_arg, cpl);
+
+	nvme_ctrlr_retry_queued_abort(ctrlr);
 }
 
 int
@@ -1006,7 +1005,9 @@ nvme_ctrlr_cmd_directive(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid,
 	cmd->opc = opc_type;
 	cmd->nsid = nsid;
 
-	cmd->cdw10 = (payload_size >> 2) - 1;
+	if (payload_size != 0) {
+		cmd->cdw10 = (payload_size >> 2) - 1;
+	}
 	cmd->cdw11_bits.directive.doper = doper;
 	cmd->cdw11_bits.directive.dtype = dtype;
 	cmd->cdw11_bits.directive.dspec = dspec;
diff --git a/lib/nvme/nvme_ctrlr_self.c b/lib/nvme/nvme_ctrlr_self.c
index 4ac1925..8adabfc 100644
--- a/lib/nvme/nvme_ctrlr_self.c
+++ b/lib/nvme/nvme_ctrlr_self.c
@@ -224,5 +224,8 @@ int32_t spdk_nvme_ctrlr_identify_directives(struct spdk_nvme_ctrlr *ctrlr, uint1
 
 uint16_t spdk_nvme_get_qpair_id(struct spdk_nvme_qpair *qpair)
 {
+	if (qpair == NULL) {
+		return -1;
+	}
 	return qpair->id;
 }
diff --git a/lib/nvme/nvme_internal.h b/lib/nvme/nvme_internal.h
index 6934f9f..31328f0 100644
--- a/lib/nvme/nvme_internal.h
+++ b/lib/nvme/nvme_internal.h
@@ -457,6 +457,8 @@ struct spdk_nvme_qpair {
 	const struct spdk_nvme_transport	*transport;
 
 	uint8_t					transport_failure_reason: 2;
+
+	uint32_t				disconnected_time;
 };
 
 struct spdk_nvme_poll_group {
@@ -1069,10 +1071,9 @@ typedef int (*spdk_nvme_parse_ana_log_page_cb)(
 	const struct spdk_nvme_ana_group_descriptor *desc, void *cb_arg);
 int	nvme_ctrlr_parse_ana_log_page(struct spdk_nvme_ctrlr *ctrlr,
 				      spdk_nvme_parse_ana_log_page_cb cb_fn, void *cb_arg);
-
+bool	nvme_qpair_check_enabled(struct spdk_nvme_qpair *qpair);
 #ifdef SPDK_CONFIG_APP_RW
 void	nvme_ctrlr_destruct_ublock(struct spdk_nvme_ctrlr *ctrlr);
-void	nvme_qpair_abort_reqs(struct spdk_nvme_qpair *qpair, uint32_t dnr);
 #endif
 
 static inline struct nvme_request *
diff --git a/lib/nvme/nvme_ns_cmd.c b/lib/nvme/nvme_ns_cmd.c
index 9b67b8e..b8d9a90 100644
--- a/lib/nvme/nvme_ns_cmd.c
+++ b/lib/nvme/nvme_ns_cmd.c
@@ -462,7 +462,7 @@ _nvme_ns_cmd_rw(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
 	uint32_t		sector_size = _nvme_get_host_buffer_sector_size(ns, io_flags);
 	uint32_t		sectors_per_max_io = ns->sectors_per_max_io;
 	uint32_t		sectors_per_stripe = ns->sectors_per_stripe;
-	int			rc;
+	int			rc = 0;
 
 	req = nvme_allocate_request(qpair, payload, lba_count * sector_size, lba_count * ns->md_size,
 				    cb_fn, cb_arg);
diff --git a/lib/nvme/nvme_pcie.c b/lib/nvme/nvme_pcie.c
index 0e9e24d..1b4b958 100644
--- a/lib/nvme/nvme_pcie.c
+++ b/lib/nvme/nvme_pcie.c
@@ -755,9 +755,7 @@ nvme_pcie_ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr)
 		spdk_pci_device_unclaim(devhandle);
 		spdk_pci_device_detach(devhandle);
 	}
-
 	spdk_free(pctrlr);
-
 	return 0;
 }
 
@@ -1244,6 +1242,10 @@ nvme_pcie_qpair_submit_request(struct spdk_nvme_qpair *qpair, struct nvme_reques
 	bool			sgl_supported;
 	bool			dword_aligned = true;
 
+	if (!nvme_qpair_check_enabled(qpair)) {
+		return -EBUSY;
+	}
+
 	if (spdk_unlikely(nvme_qpair_is_admin_queue(qpair))) {
 		nvme_robust_mutex_lock(&ctrlr->ctrlr_lock);
 	}
diff --git a/lib/nvme/nvme_pcie_common.c b/lib/nvme/nvme_pcie_common.c
index 564f81b..1dc9c99 100644
--- a/lib/nvme/nvme_pcie_common.c
+++ b/lib/nvme/nvme_pcie_common.c
@@ -840,7 +840,7 @@ nvme_pcie_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_
 		if (tr->req) {
 			nvme_pcie_qpair_complete_tracker(qpair, tr, cpl, true);
 		} else {
-			SPDK_ERRLOG("cpl does not map to outstanding cmd\n");
+			SPDK_NOTICELOG("cpl does not map to outstanding cmd\n");
 			spdk_nvme_qpair_print_completion(qpair, cpl);
 			assert(0);
 		}
@@ -905,7 +905,6 @@ nvme_pcie_qpair_destroy(struct spdk_nvme_qpair *qpair)
 	nvme_qpair_deinit(qpair);
 
 	spdk_free(pqpair);
-
 	return 0;
 }
 
@@ -952,8 +951,6 @@ nvme_pcie_ctrlr_delete_io_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_
 	struct nvme_completion_poll_status *status;
 	int rc;
 
-	assert(ctrlr != NULL);
-
 	if (ctrlr->is_removed) {
 		goto free;
 	}
@@ -1005,6 +1002,7 @@ free:
 		nvme_pcie_qpair_abort_trackers(qpair, 1);
 	}
 
+	nvme_qpair_abort_reqs(qpair, 1);
 	nvme_pcie_qpair_destroy(qpair);
 	return 0;
 }
@@ -1064,6 +1062,11 @@ nvme_pcie_poll_group_process_completions(struct spdk_nvme_transport_poll_group *
 		local_completions = spdk_nvme_qpair_process_completions(qpair, completions_per_qpair);
 		if (local_completions < 0) {
 			disconnected_qpair_cb(qpair, tgroup->group->ctx);
+			qpair->disconnected_time++;
+			if (qpair->disconnected_time > 50) {
+				qpair->poll_group->num_qpairs_to_delete++;
+				qpair->delete_after_completion_context = 1;
+			}
 			local_completions = 0;
 		}
 		total_completions += local_completions;
@@ -1078,7 +1081,6 @@ nvme_pcie_poll_group_destroy(struct spdk_nvme_transport_poll_group *tgroup)
 	if (!STAILQ_EMPTY(&tgroup->connected_qpairs) || !STAILQ_EMPTY(&tgroup->disconnected_qpairs)) {
 		return -EBUSY;
 	}
-
 	free(tgroup);
 
 	return 0;
diff --git a/lib/nvme/nvme_qpair.c b/lib/nvme/nvme_qpair.c
index 3aabd63..f11d070 100644
--- a/lib/nvme/nvme_qpair.c
+++ b/lib/nvme/nvme_qpair.c
@@ -600,7 +600,7 @@ nvme_qpair_abort_queued_reqs(struct spdk_nvme_qpair *qpair, void *cmd_cb_arg)
 	return aborting;
 }
 
-static inline bool
+bool
 nvme_qpair_check_enabled(struct spdk_nvme_qpair *qpair)
 {
 	struct nvme_request *req;
@@ -612,8 +612,7 @@ nvme_qpair_check_enabled(struct spdk_nvme_qpair *qpair)
 	 * from the old transport connection and encourage the application to retry them. We also need
 	 * to submit any queued requests that built up while we were in the connected or enabling state.
 	 */
-	if (nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTED && !qpair->ctrlr->is_resetting
-	    && !qpair->ctrlr->is_removed && !qpair->ctrlr->is_destructed) {
+	if (nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTED && !qpair->ctrlr->is_resetting) {
 		nvme_qpair_set_state(qpair, NVME_QPAIR_ENABLING);
 		/*
 		 * PCIe is special, for fabrics transports, we can abort requests before disconnect during reset
@@ -857,13 +856,7 @@ _nvme_qpair_submit_request(struct spdk_nvme_qpair *qpair, struct nvme_request *r
 				rc = nvme_qpair_submit_request(qpair, child_req);
 				if (spdk_unlikely(rc != 0)) {
 					child_req_failed = true;
-#ifdef SPDK_CONFIG_APP_RW
-					if (rc == -ENXIO && child_req->num_children == 0) {
-						SPDK_WARNLOG("Warning: child req submit failed.\n");
-						nvme_request_remove_child(req, child_req);
-						nvme_free_request(child_req);
-					}
-#endif
+					SPDK_WARNLOG("Warning: child req submit failed.\n");
 				}
 			} else { /* free remaining child_reqs since one child_req fails */
 				nvme_request_remove_child(req, child_req);
diff --git a/lib/nvme/nvme_uevent.h b/lib/nvme/nvme_uevent.h
index 1921801..94f6710 100644
--- a/lib/nvme/nvme_uevent.h
+++ b/lib/nvme/nvme_uevent.h
@@ -41,7 +41,6 @@
 #ifndef SPDK_UEVENT_H_
 #define SPDK_UEVENT_H_
 
-#ifndef SPDK_CONFIG_APP_RW
 #define SPDK_NVME_UEVENT_SUBSYSTEM_UNRECOGNIZED 0
 #define SPDK_NVME_UEVENT_SUBSYSTEM_UIO 1
 #define SPDK_NVME_UEVENT_SUBSYSTEM_VFIO 2
@@ -59,6 +58,5 @@ struct spdk_uevent {
 
 int nvme_uevent_connect(void);
 int nvme_get_uevent(int fd, struct spdk_uevent *uevent);
-#endif
 
 #endif /* SPDK_UEVENT_H_ */
diff --git a/lib/thread/thread.c b/lib/thread/thread.c
index 1ab822b..a3d342e 100644
--- a/lib/thread/thread.c
+++ b/lib/thread/thread.c
@@ -57,6 +57,12 @@ void spdk_set_thread_exited(struct spdk_thread *thread)
 {
 	thread->state = SPDK_THREAD_STATE_EXITED;
 }
+
+uint32_t spdk_get_channel_ref(void *io_ch)
+{
+	struct spdk_io_channel *ch = io_ch;
+	return ch->ref;
+}
 #endif
 
 static pthread_mutex_t g_devlist_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -1147,11 +1153,6 @@ spdk_poller_unregister(struct spdk_poller **ppoller)
 	struct spdk_thread *thread;
 	struct spdk_poller *poller;
 
-	if (!g_bRunReactor) {
-		*ppoller = NULL;
-		return;
-	}
-
 	poller = *ppoller;
 	if (poller == NULL) {
 		return;
@@ -1413,12 +1414,10 @@ _finish_unregister(void *arg)
 	struct spdk_thread *thread;
 
 	thread = spdk_get_thread();
-	assert(thread == dev->unregister_thread);
 
 	SPDK_DEBUGLOG(thread, "Finishing unregistration of io_device %s (%p) on thread %s\n",
 		      dev->name, dev->io_device, thread->name);
 
-	assert(thread->pending_unregister_count > 0);
 	thread->pending_unregister_count--;
 
 	dev->unregister_cb(dev->io_device);
@@ -1468,7 +1467,6 @@ spdk_io_device_unregister(void *io_device, spdk_io_device_unregister_cb unregist
 
 	if (!dev) {
 		SPDK_ERRLOG("io_device %p not found\n", io_device);
-		assert(false);
 		pthread_mutex_unlock(&g_devlist_mutex);
 		return;
 	}
@@ -1545,8 +1543,8 @@ spdk_get_io_channel(void *io_device)
 		if (ch->dev == dev) {
 			ch->ref++;
 
-			SPDK_DEBUGLOG(thread, "Get io_channel %p for io_device %s (%p) on thread %s refcnt %u\n",
-				      ch, dev->name, dev->io_device, thread->name, ch->ref);
+			SPDK_NOTICELOG("Get io_channel %p for io_device %s (%p) on thread %s refcnt %u\n",
+				       ch, dev->name, dev->io_device, thread->name, ch->ref);
 
 			/*
 			 * An I/O channel already exists for this device on this
@@ -1798,7 +1796,6 @@ spdk_for_each_channel(void *io_device, spdk_channel_msg fn, void *ctx,
 #else
 				_call_channel(i);
 #endif
-				assert(rc == 0);
 				return;
 			}
 		}
@@ -1821,7 +1818,7 @@ spdk_for_each_channel_continue(struct spdk_io_channel_iter *i, int status)
 	struct spdk_io_channel *ch;
 	int rc __attribute__((unused));
 
-	assert(i->cur_thread == spdk_get_thread());
+	/* assert(i->cur_thread == spdk_get_thread()); */
 
 	i->status = status;
 
diff --git a/mk/spdk.common.mk b/mk/spdk.common.mk
index 6bdc1dd..da214c8 100644
--- a/mk/spdk.common.mk
+++ b/mk/spdk.common.mk
@@ -254,7 +254,7 @@ CXXFLAGS += $(COMMON_CFLAGS)
 SYS_LIBS += -lrt
 SYS_LIBS += -luuid
 SYS_LIBS += -lcrypto
-SYS_LIBS += -lsecurec
+SYS_LIBS += -lboundscheck
 
 ifneq ($(CONFIG_NVME_CUSE)$(CONFIG_FUSE),nn)
 SYS_LIBS += -lfuse3
diff --git a/module/bdev/nvme/bdev_nvme.c b/module/bdev/nvme/bdev_nvme.c
index 01d0238..d291646 100644
--- a/module/bdev/nvme/bdev_nvme.c
+++ b/module/bdev/nvme/bdev_nvme.c
@@ -280,9 +280,6 @@ bdev_nvme_poll(void *arg)
 		}
 	}
 
-	if (!spdk_get_reactor_type()) {
-		return num_completions;
-	}
 	return num_completions > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
 }
 
@@ -315,7 +312,6 @@ bdev_nvme_destruct(void *ctx)
 	pthread_mutex_unlock(&g_bdev_nvme_mutex);
 
 	nvme_bdev_ns_detach(nvme_ns);
-
 	free(nvme_disk->disk.name);
 	free(nvme_disk);
 
@@ -930,6 +926,7 @@ bdev_nvme_create_cb(void *io_device, void *ctx_buf)
 		goto err_qpair;
 	}
 
+	nvme_ch->state = 0;
 	return 0;
 
 err_qpair:
@@ -956,6 +953,7 @@ bdev_nvme_destroy_cb(void *io_device, void *ctx_buf)
 	spdk_nvme_ctrlr_free_io_qpair(nvme_ch->qpair);
 
 	spdk_put_io_channel(spdk_io_channel_from_ctx(nvme_ch->group));
+	nvme_ch->state = 1;
 }
 
 static int
@@ -970,7 +968,7 @@ bdev_nvme_poll_group_create_cb(void *io_device, void *ctx_buf)
 
 	group->poller = SPDK_POLLER_REGISTER(bdev_nvme_poll, group, g_opts.nvme_ioq_poll_period_us);
 
-	if (group->poller == NULL && spdk_get_reactor_type()) {
+	if (group->poller == NULL) {
 		spdk_nvme_poll_group_destroy(group->group);
 		return -1;
 	}
@@ -985,7 +983,7 @@ bdev_nvme_poll_group_destroy_cb(void *io_device, void *ctx_buf)
 
 	spdk_poller_unregister(&group->poller);
 	if (spdk_nvme_poll_group_destroy(group->group)) {
-		SPDK_ERRLOG("Unable to destroy a poll group for the NVMe bdev module.");
+		SPDK_ERRLOG("Unable to destroy a poll group for the NVMe bdev module.\n");
 		assert(false);
 	}
 }
@@ -1320,8 +1318,9 @@ nvme_abort_cpl(void *ctx, const struct spdk_nvme_cpl *cpl)
 	struct nvme_bdev_ctrlr *nvme_bdev_ctrlr = ctx;
 
 	if (spdk_nvme_cpl_is_error(cpl)) {
-		SPDK_WARNLOG("Abort failed. Resetting controller.\n");
-		_bdev_nvme_reset(nvme_bdev_ctrlr, NULL);
+		SPDK_WARNLOG("Abort failed, sc is %u, sct is %u. Resetting controller.\n", cpl->status.sc,
+			     cpl->status.sct);
+		spdk_nvme_ctrlr_reset(nvme_bdev_ctrlr->ctrlr);
 	}
 }
 
@@ -1335,8 +1334,6 @@ timeout_cb(void *cb_arg, struct spdk_nvme_ctrlr *ctrlr,
 
 	assert(nvme_bdev_ctrlr->ctrlr == ctrlr);
 
-	SPDK_WARNLOG("Warning: Detected a timeout. ctrlr=%p qpair=%p cid=%u\n", ctrlr, qpair, cid);
-
 	/* Only try to read CSTS if it's a PCIe controller or we have a timeout on an I/O
 	 * queue.  (Note: qpair == NULL when there's an admin cmd timeout.)  Otherwise we
 	 * would submit another fabrics cmd on the admin queue to read CSTS and check for its
@@ -1359,8 +1356,7 @@ timeout_cb(void *cb_arg, struct spdk_nvme_ctrlr *ctrlr,
 			if (rc == 0) {
 				return;
 			}
-
-			SPDK_ERRLOG("Unable to send abort. Resetting.\n");
+			SPDK_ERRLOG("Unable to send abort. Resetting, rc is %d.\n", rc);
 		}
 
 	/* FALLTHROUGH */
@@ -2245,9 +2241,14 @@ bdev_nvme_library_fini(void)
 			continue;
 		}
 		nvme_bdev_ctrlr->destruct = true;
-
+#ifndef SPDK_CONFIG_APP_RW
 		spdk_thread_send_msg(nvme_bdev_ctrlr->thread, _nvme_bdev_ctrlr_destruct,
 				     nvme_bdev_ctrlr);
+#else
+		pthread_mutex_unlock(&g_bdev_nvme_mutex);
+		_nvme_bdev_ctrlr_destruct(nvme_bdev_ctrlr);
+		pthread_mutex_lock(&g_bdev_nvme_mutex);
+#endif
 	}
 
 	g_bdev_nvme_module_finish = true;
@@ -3028,12 +3029,18 @@ bdev_nvme_get_ctrlr(struct spdk_bdev *bdev)
 }
 
 #ifdef SPDK_CONFIG_APP_RW
-void *
-nvme_channel_get_group(void *io_ch)
+void *nvme_channel_get_group(void *io_ch)
+{
+	struct nvme_io_channel *nvme_ch = io_ch;
+	return nvme_ch->group;
+}
+
+int nvme_channel_get_state(void *io_ch)
 {
-	struct nvme_io_channel *nvme_io_ch = io_ch;
-	return nvme_io_ch->group;
+	struct nvme_io_channel *nvme_ch = io_ch;
+	return nvme_ch->state;
 }
+
 struct nvme_bdev_io *nvme_bdev_io_update_args(struct nvme_bdev_io *bio, struct iovec *iov,
 		int iovcnt)
 {
@@ -3128,14 +3135,15 @@ int bdev_probe_ctrlr(void)
 	}
 
 	retry_count = spdk_conf_section_get_intval(sp, "RetryCount");
-	if (retry_count >= 0) {
-		g_opts.retry_count = retry_count;
-	}
-	if (retry_count > 255) {
+	if (retry_count < 0) {
+		retry_count = 4;
+	} else if (retry_count > 255) {
 		SPDK_WARNLOG("RetryCount:%d should not be greater than 255, set it to 255 this time\n",
 			     retry_count);
 		retry_count = 255;
 	}
+
+	g_opts.retry_count = retry_count;
 	syslog(LOG_INFO, "RetryCount is set to %d\n", retry_count);
 
 	val = spdk_conf_section_get_val(sp, "TimeoutUsec");
diff --git a/module/bdev/nvme/bdev_nvme_self.c b/module/bdev/nvme/bdev_nvme_self.c
index 1419b1f..dc480ff 100644
--- a/module/bdev/nvme/bdev_nvme_self.c
+++ b/module/bdev/nvme/bdev_nvme_self.c
@@ -15,7 +15,6 @@
 #include "spdk/json.h"
 #include "spdk/likely.h"
 #include "spdk/bdev_module.h"
-#include "spdk/nvme_ocssd.h"
 #include "spdk/nvme.h"
 
 #include "spdk_internal/bdev_stat.h"
@@ -23,11 +22,6 @@
 #include "common.h"
 #include <securec.h>
 
-enum data_direction {
-	BDEV_DISK_READ = 0,
-	BDEV_DISK_WRITE = 1
-};
-
 void bdev_update_ch_timeout(struct nvme_bdev_poll_group *group)
 {
 	uint64_t current_ticks = 0;
@@ -49,8 +43,7 @@ void bdev_update_ch_timeout(struct nvme_bdev_poll_group *group)
 	}
 }
 
-int
-_bdev_nvme_submit_request_self(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
+int _bdev_nvme_submit_request_self(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
 {
 	struct nvme_io_channel *nvme_ch = spdk_io_channel_get_ctx(ch);
 
@@ -65,27 +58,27 @@ _bdev_nvme_submit_request_self(struct spdk_io_channel *ch, struct spdk_bdev_io *
 			      bdev_io->u.contig.offset_blocks);
 		return bdev_nvme_queue_cmd_with_md((struct nvme_bdev *)bdev_io->bdev->ctxt, nvme_ch->qpair,
 						   bdev_io->driver_ctx, bdev_io->u.contig.buf,
-						   bdev_io->u.contig.md_buf, BDEV_DISK_READ,
+						   bdev_io->u.contig.md_buf, SPDK_BDEV_IO_TYPE_READ,
 						   bdev_io->u.contig.num_blocks, bdev_io->u.contig.offset_blocks);
 	case SPDK_BDEV_IO_TYPE_WRITE_NVME:
 		SPDK_DEBUGLOG(bdev_nvme, "write %lu lbas with offset %#lx\n", bdev_io->u.contig.num_blocks,
 			      bdev_io->u.contig.offset_blocks);
 		return bdev_nvme_queue_cmd_with_md((struct nvme_bdev *)bdev_io->bdev->ctxt, nvme_ch->qpair,
 						   bdev_io->driver_ctx, bdev_io->u.contig.buf,
-						   bdev_io->u.contig.md_buf, BDEV_DISK_WRITE,
+						   bdev_io->u.contig.md_buf, SPDK_BDEV_IO_TYPE_WRITE,
 						   bdev_io->u.contig.num_blocks, bdev_io->u.contig.offset_blocks);
 	case SPDK_BDEV_IO_TYPE_READV_NVME:
 		SPDK_DEBUGLOG(bdev_nvme, "readv %lu lbas with offset %#lx\n", bdev_io->u.bdev.num_blocks,
 			      bdev_io->u.bdev.offset_blocks);
 		return bdev_nvme_queue_cmd_v_with_md((struct nvme_bdev *)bdev_io->bdev->ctxt, nvme_ch->qpair,
-						     bdev_io->driver_ctx, BDEV_DISK_READ,
+						     bdev_io->driver_ctx, SPDK_BDEV_IO_TYPE_READ,
 						     bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
 						     bdev_io->u.bdev.num_blocks, bdev_io->u.bdev.offset_blocks);
 	case SPDK_BDEV_IO_TYPE_WRITEV_NVME:
 		SPDK_DEBUGLOG(bdev_nvme, "writev %lu lbas with offset %#lx\n", bdev_io->u.bdev.num_blocks,
 			      bdev_io->u.bdev.offset_blocks);
 		return bdev_nvme_queue_cmd_v_with_md((struct nvme_bdev *)bdev_io->bdev->ctxt, nvme_ch->qpair,
-						     bdev_io->driver_ctx, BDEV_DISK_WRITE,
+						     bdev_io->driver_ctx, SPDK_BDEV_IO_TYPE_WRITE,
 						     bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
 						     bdev_io->u.bdev.num_blocks, bdev_io->u.bdev.offset_blocks);
 	case SPDK_BDEV_IO_TYPE_UNMAP_BLOCKS:
@@ -100,14 +93,12 @@ _bdev_nvme_submit_request_self(struct spdk_io_channel *ch, struct spdk_bdev_io *
 	return 0;
 }
 
-int
-bdev_nvme_dump_info_json_self(void *ctx, struct spdk_json_write_ctx *w)
+int bdev_nvme_dump_info_json_self(void *ctx, struct spdk_json_write_ctx *w)
 {
 	return 0;
 }
 
-uint16_t
-bdev_nvme_get_io_channel_id(struct spdk_io_channel *ch)
+uint16_t bdev_nvme_get_io_channel_id(struct spdk_io_channel *ch)
 {
 	struct nvme_io_channel *nvme_ch = spdk_io_channel_get_ctx(ch);
 	uint16_t channel_id;
@@ -116,15 +107,13 @@ bdev_nvme_get_io_channel_id(struct spdk_io_channel *ch)
 	return channel_id;
 }
 
-uint64_t
-bdev_nvme_get_timeout_count(struct spdk_io_channel *ch)
+uint64_t bdev_nvme_get_timeout_count(struct spdk_io_channel *ch)
 {
 	struct nvme_io_channel *nvme_ch = spdk_io_channel_get_ctx(ch);
 	return nvme_ch->group->num_poll_timeout;
 }
 
-int32_t
-nvme_ctrlr_get_info(const char *ctrlName, struct nvme_ctrlr_info **ppCtrlr)
+int32_t nvme_ctrlr_get_info(const char *ctrlName, struct nvme_ctrlr_info **ppCtrlr)
 {
 	uint32_t num_ctrlr = 0, i = 0;
 	struct nvme_bdev_ctrlr *nvme_bdev_ctrlr = NULL;
@@ -221,8 +210,7 @@ nvme_ctrlr_get_info(const char *ctrlName, struct nvme_ctrlr_info **ppCtrlr)
 	return num_ctrlr;
 }
 
-struct nvme_bdev_ctrlr *
-nvme_ctrlr_get_by_name(const char *name)
+struct nvme_bdev_ctrlr *nvme_ctrlr_get_by_name(const char *name)
 {
 	struct nvme_bdev_ctrlr *nvme_bdev_ctrlr = NULL;
 
@@ -239,8 +227,7 @@ nvme_ctrlr_get_by_name(const char *name)
 	return NULL;
 }
 
-struct spdk_nvme_ctrlr *
-spdk_nvme_ctrlr_get_by_name(const char *ctrlname)
+struct spdk_nvme_ctrlr *spdk_nvme_ctrlr_get_by_name(const char *ctrlname)
 {
 	struct nvme_bdev_ctrlr	*nvme_bdev_ctrlr = NULL;
 
@@ -253,8 +240,7 @@ spdk_nvme_ctrlr_get_by_name(const char *ctrlname)
 	return NULL;
 }
 
-struct spdk_nvme_ctrlr *
-spdk_nvme_ctrlr_get_by_ctrlr(const struct nvme_bdev_ctrlr *nvme_bdev_ctrlr)
+struct spdk_nvme_ctrlr *spdk_nvme_ctrlr_get_by_ctrlr(const struct nvme_bdev_ctrlr *nvme_bdev_ctrlr)
 {
 	if (nvme_bdev_ctrlr == NULL) {
 		return NULL;
@@ -262,8 +248,7 @@ spdk_nvme_ctrlr_get_by_ctrlr(const struct nvme_bdev_ctrlr *nvme_bdev_ctrlr)
 	return nvme_bdev_ctrlr->ctrlr;
 }
 
-void
-nvme_ctrlr_clear_iostat_by_name(const char *ctrlname)
+void nvme_ctrlr_clear_iostat_by_name(const char *ctrlname)
 {
 	int i;
 	size_t size = strnlen(ctrlname, 24);
@@ -288,8 +273,7 @@ nvme_ctrlr_clear_iostat_by_name(const char *ctrlname)
 	}
 }
 
-void
-nvme_ctrlr_clear_iostat_all(void)
+void nvme_ctrlr_clear_iostat_all(void)
 {
 	struct nvme_bdev_ctrlr	*nvme_bdev_ctrlr = NULL;
 
@@ -298,8 +282,7 @@ nvme_ctrlr_clear_iostat_all(void)
 	}
 }
 
-struct spdk_nvme_ns *
-bdev_nvme_get_ns(struct nvme_bdev *nbdev)
+struct spdk_nvme_ns *bdev_nvme_get_ns(struct nvme_bdev *nbdev)
 {
 	return nbdev->nvme_ns->ns;
 }
@@ -331,11 +314,10 @@ void bdev_nvme_update_block_by_nvme_ctrlr(struct spdk_nvme_ctrlr *ctrlr)
 	pthread_mutex_unlock(&g_bdev_nvme_mutex);
 }
 
-int
-bdev_nvme_update_ns(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr, uint32_t nsid)
+int bdev_nvme_update_ns(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr, uint32_t nsid)
 {
-	struct spdk_nvme_ctrlr	*ctrlr = nvme_bdev_ctrlr->ctrlr;
 	struct nvme_bdev_ns	*ns = NULL;
+	bool ns_active = spdk_nvme_ctrlr_is_active_ns(nvme_bdev_ctrlr->ctrlr, nsid);
 
 	if (nvme_bdev_ctrlr == NULL || nsid > nvme_bdev_ctrlr->num_ns) {
 		SPDK_ERRLOG("Parameter error. nsid[%u], the max nsid is[%u]\n", nsid, nvme_bdev_ctrlr->num_ns);
@@ -343,14 +325,9 @@ bdev_nvme_update_ns(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr, uint32_t nsid)
 	}
 
 	ns = nvme_bdev_ctrlr->namespaces[nsid - 1];
+	ns->type = NVME_BDEV_NS_STANDARD;
 
-	if (spdk_nvme_ctrlr_is_ocssd_supported(ctrlr)) {
-		ns->type = NVME_BDEV_NS_OCSSD;
-	} else {
-		ns->type = NVME_BDEV_NS_STANDARD;
-	}
-
-	if (!ns->populated && spdk_nvme_ctrlr_is_active_ns(nvme_bdev_ctrlr->ctrlr, nsid)) {
+	if (!ns->populated && ns_active) {
 		SPDK_NOTICELOG("NSID %u to be added\n", nsid);
 		ns->id = nsid;
 		ns->ctrlr = nvme_bdev_ctrlr;
@@ -360,16 +337,16 @@ bdev_nvme_update_ns(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr, uint32_t nsid)
 		return 0;
 	}
 
-	if (ns->populated && !spdk_nvme_ctrlr_is_active_ns(nvme_bdev_ctrlr->ctrlr, nsid)) {
+	if (ns->populated && !ns_active) {
 		SPDK_NOTICELOG("NSID %u is removed\n", nsid);
 		nvme_ctrlr_depopulate_namespace(nvme_bdev_ctrlr, ns);
 		return 0;
 	}
-	return -1;
+
+	return 0;
 }
 
-bool
-spdk_bdev_can_remove(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr, uint32_t nsid)
+bool spdk_bdev_can_remove(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr, uint32_t nsid)
 {
 	struct nvme_bdev_ns *ns = NULL;
 	struct nvme_bdev *bdev = NULL, *tmp = NULL;
@@ -398,8 +375,7 @@ spdk_bdev_can_remove(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr, uint32_t nsid)
 	return empty;
 }
 
-void
-spdk_bdev_set_ns_normal(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr, uint32_t nsid)
+void spdk_bdev_set_ns_normal(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr, uint32_t nsid)
 {
 	struct nvme_bdev_ns *ns = NULL;
 	struct nvme_bdev *bdev = NULL, *tmp = NULL;
@@ -419,9 +395,18 @@ spdk_bdev_set_ns_normal(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr, uint32_t nsid)
 	}
 }
 
-int
-bdev_nvme_queue_cmd_with_md(struct nvme_bdev *bdev, struct spdk_nvme_qpair *qpair, void *driver_ctx,
-			    void *buffer, void *metadata, int direction, uint64_t lba_count, uint64_t lba)
+static void check_error_type(int rc, bool read, void *qpair)
+{
+	if (rc == -ENOMEM) {
+		SPDK_NOTICELOG("%s failed: rc = %d\n", read ? "read" : "write", rc);
+	} else if (rc < 0) {
+		SPDK_ERRLOG("%s failed: rc = %d, qpair is %p\n", read ? "read" : "write", rc, qpair);
+	}
+}
+
+int bdev_nvme_queue_cmd_with_md(struct nvme_bdev *bdev, struct spdk_nvme_qpair *qpair,
+				void *driver_ctx,
+				void *buffer, void *metadata, int direction, uint64_t lba_count, uint64_t lba)
 {
 	int rc;
 	uint32_t io_flags = 0;
@@ -452,7 +437,7 @@ bdev_nvme_queue_cmd_with_md(struct nvme_bdev *bdev, struct spdk_nvme_qpair *qpai
 		io_flags |= SPDK_NVME_IO_FLAGS_FORCE_UNIT_ACCESS;
 	}
 
-	if (direction == BDEV_DISK_READ) {
+	if (direction == SPDK_BDEV_IO_TYPE_READ) {
 		rc = spdk_nvme_ns_cmd_read_with_md(bdev->nvme_ns->ns, qpair, buffer, metadata, lba,
 						   lba_count, bdev_nvme_queued_done, driver_ctx, io_flags, 0, 0);
 	} else {
@@ -460,21 +445,13 @@ bdev_nvme_queue_cmd_with_md(struct nvme_bdev *bdev, struct spdk_nvme_qpair *qpai
 						    lba_count, bdev_nvme_queued_done, driver_ctx, io_flags, 0, 0);
 	}
 
-	if (rc != 0) {
-		if (rc == -ENOMEM) {
-			SPDK_NOTICELOG("%s failed: rc = %d\n", direction == BDEV_DISK_READ ? "read" : "write", rc);
-		} else {
-			SPDK_ERRLOG("%s failed: rc = %d, qpair is %p\n", direction == BDEV_DISK_READ ? "read" : "write",
-				    rc, qpair);
-		}
-	}
+	check_error_type(rc, direction == SPDK_BDEV_IO_TYPE_READ, qpair);
 	return rc;
 }
 
-int
-bdev_nvme_queue_cmd_v_with_md(struct nvme_bdev *bdev, struct spdk_nvme_qpair *qpair,
-			      void *driver_ctx,
-			      int direction, struct iovec *iov, int iovcnt, uint64_t lba_count, uint64_t lba)
+int bdev_nvme_queue_cmd_v_with_md(struct nvme_bdev *bdev, struct spdk_nvme_qpair *qpair,
+				  void *driver_ctx,
+				  int direction, struct iovec *iov, int iovcnt, uint64_t lba_count, uint64_t lba)
 {
 	int rc;
 	struct nvme_bdev_io *bio = NULL;
@@ -508,29 +485,21 @@ bdev_nvme_queue_cmd_v_with_md(struct nvme_bdev *bdev, struct spdk_nvme_qpair *qp
 
 	bio = nvme_bdev_io_update_args((struct nvme_bdev_io *)driver_ctx, iov, iovcnt);
 
-	if (direction == BDEV_DISK_READ) {
+	if (direction == SPDK_BDEV_IO_TYPE_READ) {
 		rc = spdk_nvme_ns_cmd_readv(bdev->nvme_ns->ns, qpair, lba,
 					    lba_count, bdev_nvme_queued_done, bio, io_flags,
 					    bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge);
 	} else {
 		rc = spdk_nvme_ns_cmd_writev(bdev->nvme_ns->ns, qpair, lba, lba_count,
-						    0, bdev_nvme_queued_done, bio, io_flags,
+						    bdev_nvme_queued_done, bio, io_flags,
 						    bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge);
 	}
 
-	if (rc != 0) {
-		if (rc == -ENOMEM) {
-			SPDK_NOTICELOG("%s failed: rc = %d\n", direction == BDEV_DISK_READ ? "readv" : "writev", rc);
-		} else {
-			SPDK_ERRLOG("%s failed: rc = %d, qpair is %p\n", direction == BDEV_DISK_READ ? "read" : "write", rc,
-				    qpair);
-		}
-	}
+	check_error_type(rc, direction == SPDK_BDEV_IO_TYPE_READ, qpair);
 	return rc;
 }
 
-struct nvme_bdev_ctrlr *
-bdev_nvme_get_ctrlr_by_bdev_desc(void *bdev_desc)
+struct nvme_bdev_ctrlr *bdev_nvme_get_ctrlr_by_bdev_desc(void *bdev_desc)
 {
 	struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(bdev_desc);
 	struct nvme_bdev *nbdev = (struct nvme_bdev *)bdev->ctxt;
@@ -540,12 +509,11 @@ bdev_nvme_get_ctrlr_by_bdev_desc(void *bdev_desc)
 	return nbdev->nvme_ns->ctrlr;
 }
 
-int
-bdev_nvme_unmap_blocks(struct nvme_bdev *nbdev, struct spdk_io_channel *ch, void *driver_ctx,
-		       struct spdk_nvme_dsm_range *unmap_d, uint16_t unmap_count)
+int bdev_nvme_unmap_blocks(struct nvme_bdev *nbdev, struct spdk_io_channel *ch, void *driver_ctx,
+			   struct spdk_nvme_dsm_range *unmap_d, uint32_t unmap_count)
 {
 	struct nvme_io_channel *nvme_ch = spdk_io_channel_get_ctx(ch);
-	int i;
+	uint32_t i;
 
 	if (unmap_count == 0 || unmap_count > SPDK_NVME_DATASET_MANAGEMENT_MAX_RANGES) {
 		SPDK_ERRLOG("Invalid parameter, unmap count: %u\n", unmap_count);
@@ -566,36 +534,39 @@ bdev_nvme_unmap_blocks(struct nvme_bdev *nbdev, struct spdk_io_channel *ch, void
 
 	spdk_bdev_set_io_location(driver_ctx, (uint8_t)LOCAL_LIBSTORAGE_BDEV_NVME);
 	return spdk_nvme_ns_cmd_dataset_management(nbdev->nvme_ns->ns, nvme_ch->qpair,
-						   SPDK_NVME_DSM_ATTR_DEALLOCATE,
-						   unmap_d, unmap_count,
-						   bdev_nvme_queued_done, driver_ctx);
+			SPDK_NVME_DSM_ATTR_DEALLOCATE,
+			unmap_d, unmap_count,
+			bdev_nvme_queued_done, driver_ctx);
 }
 
-void
-spdk_bdev_nvme_remove_cb(void *cb_ctx, void *ctrlr)
+void spdk_bdev_nvme_remove_cb(void *cb_ctx, void *ctrlr)
 {
 	remove_cb(cb_ctx, (struct spdk_nvme_ctrlr *)ctrlr);
 }
 
-void spdk_bdev_fail_ctrlr(const char *traddr)
+void spdk_bdev_fail_ctrlr(void *cb_ctx, void *ctrlr)
 {
-	struct nvme_bdev_ctrlr *nvme_bdev_ctrlr;
+	spdk_nvme_ctrlr_fail_hotplug((struct spdk_nvme_ctrlr *)ctrlr);
+	remove_cb(cb_ctx, (struct spdk_nvme_ctrlr *)ctrlr);
+}
+
+struct spdk_nvme_ctrlr *spdk_nvme_bdev_ctrlr_get(char *pci_trid)
+{
+	struct nvme_bdev_ctrlr	*nvme_bdev_ctrlr;
 
-	pthread_mutex_lock(&g_bdev_nvme_mutex);
 	TAILQ_FOREACH(nvme_bdev_ctrlr, &g_nvme_bdev_ctrlrs, tailq) {
-		if (strcmp(nvme_bdev_ctrlr->connected_trid->traddr, traddr) == 0) {
-			spdk_nvme_ctrlr_fail(nvme_bdev_ctrlr->ctrlr);
-			remove_cb(NULL, nvme_bdev_ctrlr->ctrlr);
-			return;
+		if (strcmp(nvme_bdev_ctrlr->connected_trid->traddr, pci_trid) == 0) {
+			return nvme_bdev_ctrlr->ctrlr;
 		}
 	}
+
+	return NULL;
 }
 
-int
-spdk_bdev_nvme_create_self(struct spdk_nvme_transport_id *trid,
-			   const char *base_name,
-			   const char **names, size_t *count,
-			   const char *hostnqn)
+int spdk_bdev_nvme_create_self(struct spdk_nvme_transport_id *trid,
+			       const char *base_name,
+			       const char **names, size_t *count,
+			       const char *hostnqn)
 {
 	struct nvme_probe_ctx	*probe_ctx;
 	struct nvme_bdev_ctrlr	*nvme_bdev_ctrlr;
@@ -616,7 +587,7 @@ spdk_bdev_nvme_create_self(struct spdk_nvme_transport_id *trid,
 		return -1;
 	}
 
-	if (spdk_nvme_probe(trid, probe_ctx, probe_cb, attach_cb, NULL)) {
+	if (spdk_nvme_probe(trid, probe_ctx, probe_cb, attach_cb, remove_cb)) {
 		SPDK_ERRLOG("Failed to probe for new devices\n");
 		free(probe_ctx);
 		return -1;
diff --git a/module/bdev/nvme/bdev_nvme_self.h b/module/bdev/nvme/bdev_nvme_self.h
index d7cc587..43ad7ee 100644
--- a/module/bdev/nvme/bdev_nvme_self.h
+++ b/module/bdev/nvme/bdev_nvme_self.h
@@ -40,4 +40,4 @@ bdev_nvme_get_ctrlr_by_bdev_desc(void *bdev_desc);
 
 int
 bdev_nvme_unmap_blocks(struct nvme_bdev *nbdev, struct spdk_io_channel *ch, void *driver_ctx,
-		       struct spdk_nvme_dsm_range *unmap_d, uint16_t unmap_count);
+		       struct spdk_nvme_dsm_range *unmap_d, uint32_t unmap_count);
diff --git a/module/bdev/nvme/common.h b/module/bdev/nvme/common.h
index 81b4009..8dbcd87 100644
--- a/module/bdev/nvme/common.h
+++ b/module/bdev/nvme/common.h
@@ -160,6 +160,7 @@ struct nvme_io_channel {
 	struct nvme_bdev_poll_group	*group;
 	TAILQ_HEAD(, spdk_bdev_io)	pending_resets;
 	struct ocssd_io_channel		*ocssd_ch;
+	int 				state;
 };
 
 void nvme_ctrlr_populate_namespace_done(struct nvme_async_probe_ctx *ctx,
diff --git a/scripts/setup_self.sh b/scripts/setup_self.sh
index 9e77c29..90b7f86 100755
--- a/scripts/setup_self.sh
+++ b/scripts/setup_self.sh
@@ -30,8 +30,15 @@ function linux_bind_driver() {
 
 	echo "$bdf ($ven_dev_id): $old_driver_name -> $driver_name"
 
-	echo "$ven_dev_id" > "/sys/bus/pci/drivers/$driver_name/new_id" 2> /dev/null || true
-	echo "$bdf" > "/sys/bus/pci/drivers/$driver_name/bind" 2> /dev/null || true
+	if [ "$driver_name" = "nvme" ]
+        then
+                echo 1 > /sys/bus/pci/devices/$bdf/remove
+                sleep 1
+                echo 1 > /sys/bus/pci/rescan
+        else
+                echo "$ven_dev_id" > "/sys/bus/pci/drivers/$driver_name/new_id" 2> /dev/null || true
+                echo "$bdf" > "/sys/bus/pci/drivers/$driver_name/bind" 2> /dev/null || true
+        fi
 }
 
 function linux_hugetlbfs_mount() {
-- 
2.33.0

