diff --git a/CHANGELOG.md b/CHANGELOG.md index bb0e20af2..67e4a2fb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,10 @@ An `opts_size` element was added in the `spdk_blob_open_opts` structure to solve ABI compatiblity issue between different SPDK version. And also add `opts_size` parameter in `spdk_blob_open_opts_init` function. +### nvme + +Added a new function `spdk_nvme_ctrlr_reset_subsystem` to perform a NVMe +subsystem reset. Note: The NVMf target does not support the subsystem reset yet. ### event diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index c0654a6bb..b27201329 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -900,6 +900,25 @@ void spdk_nvme_ctrlr_set_remove_cb(struct spdk_nvme_ctrlr *ctrlr, */ int spdk_nvme_ctrlr_reset(struct spdk_nvme_ctrlr *ctrlr); +/** + * Perform a NVMe subsystem reset. + * + * This function should be called from a single thread while no other threads + * are actively using the NVMe device. + * A subsystem reset is typically seen by the OS as a hot remove, followed by a + * hot add event. + * + * Any pointers returned from spdk_nvme_ctrlr_get_ns(), spdk_nvme_ns_get_data(), + * spdk_nvme_zns_ns_get_data(), and spdk_nvme_zns_ctrlr_get_data() + * may be invalidated by calling this function. The number of namespaces as returned + * by spdk_nvme_ctrlr_get_num_ns() may also change. + * + * \param ctrlr Opaque handle to NVMe controller. + * + * \return 0 on success, -1 on failure, -ENOTSUP if subsystem reset is not supported. + */ +int spdk_nvme_ctrlr_reset_subsystem(struct spdk_nvme_ctrlr *ctrlr); + /** * Fail the given NVMe controller. * diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index 10f78b249..9f03262d1 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -91,6 +91,13 @@ nvme_ctrlr_get_cmbsz(struct spdk_nvme_ctrlr *ctrlr, union spdk_nvme_cmbsz_regist &cmbsz->raw); } +static int +nvme_ctrlr_set_nssr(struct spdk_nvme_ctrlr *ctrlr, uint32_t nssr_value) +{ + return nvme_transport_ctrlr_set_reg_4(ctrlr, offsetof(struct spdk_nvme_registers, nssr), + nssr_value); +} + bool nvme_ctrlr_multi_iocs_enabled(struct spdk_nvme_ctrlr *ctrlr) { @@ -1431,6 +1438,32 @@ out: return rc; } +int +spdk_nvme_ctrlr_reset_subsystem(struct spdk_nvme_ctrlr *ctrlr) +{ + union spdk_nvme_cap_register cap; + int rc = 0; + + cap = spdk_nvme_ctrlr_get_regs_cap(ctrlr); + if (cap.bits.nssrs == 0) { + SPDK_WARNLOG("subsystem reset is not supported\n"); + return -ENOTSUP; + } + + SPDK_NOTICELOG("resetting subsystem\n"); + nvme_robust_mutex_lock(&ctrlr->ctrlr_lock); + ctrlr->is_resetting = true; + rc = nvme_ctrlr_set_nssr(ctrlr, SPDK_NVME_NSSR_VALUE); + ctrlr->is_resetting = false; + + nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock); + /* + * No more cleanup at this point like in the ctrlr reset. A subsystem reset will cause + * a hot remove for PCIe transport. The hot remove handling does all the necessary ctrlr cleanup. + */ + return rc; +} + int spdk_nvme_ctrlr_set_trid(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_transport_id *trid) { diff --git a/lib/nvme/spdk_nvme.map b/lib/nvme/spdk_nvme.map index 538d5654f..03215e4fc 100644 --- a/lib/nvme/spdk_nvme.map +++ b/lib/nvme/spdk_nvme.map @@ -30,6 +30,7 @@ spdk_nvme_ctrlr_is_discovery; spdk_nvme_ctrlr_get_default_ctrlr_opts; spdk_nvme_ctrlr_set_trid; + spdk_nvme_ctrlr_reset_subsystem; spdk_nvme_ctrlr_reset; spdk_nvme_ctrlr_fail; spdk_nvme_ctrlr_is_failed;