nvme: make ctrlr detach fully asynchronous
The controller detach had asynchronous API (with async/poll), but the register operations were synchronous, so they would block on fabrics controllers. In this patch, they're changed to their non-blocking counterparts, making the detach fully asynchronous. Signed-off-by: Jim Harris <james.r.harris@intel.com> Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com> Change-Id: I74df12ab40a54f1d675639672e03755c89768bef Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/8726 Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com> Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
This commit is contained in:
parent
51b018da0f
commit
b6ecc37298
@ -1043,26 +1043,13 @@ spdk_nvme_ctrlr_fail(struct spdk_nvme_ctrlr *ctrlr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nvme_ctrlr_shutdown_async(struct spdk_nvme_ctrlr *ctrlr,
|
nvme_ctrlr_shutdown_set_cc_done(void *_ctx, uint64_t value, const struct spdk_nvme_cpl *cpl)
|
||||||
struct nvme_ctrlr_detach_ctx *ctx)
|
|
||||||
{
|
{
|
||||||
union spdk_nvme_cc_register cc;
|
struct nvme_ctrlr_detach_ctx *ctx = _ctx;
|
||||||
|
struct spdk_nvme_ctrlr *ctrlr = ctx->ctrlr;
|
||||||
|
|
||||||
if (ctrlr->is_removed) {
|
if (spdk_nvme_cpl_is_error(cpl)) {
|
||||||
ctx->shutdown_complete = true;
|
NVME_CTRLR_ERRLOG(ctrlr, "Failed to write CC.SHN\n");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nvme_ctrlr_get_cc(ctrlr, &cc)) {
|
|
||||||
NVME_CTRLR_ERRLOG(ctrlr, "get_cc() failed\n");
|
|
||||||
ctx->shutdown_complete = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cc.bits.shn = SPDK_NVME_SHN_NORMAL;
|
|
||||||
|
|
||||||
if (nvme_ctrlr_set_cc(ctrlr, &cc)) {
|
|
||||||
NVME_CTRLR_ERRLOG(ctrlr, "set_cc() failed\n");
|
|
||||||
ctx->shutdown_complete = true;
|
ctx->shutdown_complete = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1081,6 +1068,67 @@ nvme_ctrlr_shutdown_async(struct spdk_nvme_ctrlr *ctrlr,
|
|||||||
NVME_CTRLR_DEBUGLOG(ctrlr, "shutdown timeout = %" PRIu32 " ms\n", ctx->shutdown_timeout_ms);
|
NVME_CTRLR_DEBUGLOG(ctrlr, "shutdown timeout = %" PRIu32 " ms\n", ctx->shutdown_timeout_ms);
|
||||||
|
|
||||||
ctx->shutdown_start_tsc = spdk_get_ticks();
|
ctx->shutdown_start_tsc = spdk_get_ticks();
|
||||||
|
ctx->state = NVME_CTRLR_DETACH_CHECK_CSTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nvme_ctrlr_shutdown_get_cc_done(void *_ctx, uint64_t value, const struct spdk_nvme_cpl *cpl)
|
||||||
|
{
|
||||||
|
struct nvme_ctrlr_detach_ctx *ctx = _ctx;
|
||||||
|
struct spdk_nvme_ctrlr *ctrlr = ctx->ctrlr;
|
||||||
|
union spdk_nvme_cc_register cc;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (spdk_nvme_cpl_is_error(cpl)) {
|
||||||
|
NVME_CTRLR_ERRLOG(ctrlr, "Failed to read the CC register\n");
|
||||||
|
ctx->shutdown_complete = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(value <= UINT32_MAX);
|
||||||
|
cc.raw = (uint32_t)value;
|
||||||
|
cc.bits.shn = SPDK_NVME_SHN_NORMAL;
|
||||||
|
|
||||||
|
rc = nvme_ctrlr_set_cc_async(ctrlr, cc.raw, nvme_ctrlr_shutdown_set_cc_done, ctx);
|
||||||
|
if (rc != 0) {
|
||||||
|
NVME_CTRLR_ERRLOG(ctrlr, "Failed to write CC.SHN\n");
|
||||||
|
ctx->shutdown_complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nvme_ctrlr_shutdown_async(struct spdk_nvme_ctrlr *ctrlr,
|
||||||
|
struct nvme_ctrlr_detach_ctx *ctx)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (ctrlr->is_removed) {
|
||||||
|
ctx->shutdown_complete = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->state = NVME_CTRLR_DETACH_SET_CC;
|
||||||
|
rc = nvme_ctrlr_get_cc_async(ctrlr, nvme_ctrlr_shutdown_get_cc_done, ctx);
|
||||||
|
if (rc != 0) {
|
||||||
|
NVME_CTRLR_ERRLOG(ctrlr, "Failed to read the CC register\n");
|
||||||
|
ctx->shutdown_complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nvme_ctrlr_shutdown_get_csts_done(void *_ctx, uint64_t value, const struct spdk_nvme_cpl *cpl)
|
||||||
|
{
|
||||||
|
struct nvme_ctrlr_detach_ctx *ctx = _ctx;
|
||||||
|
|
||||||
|
if (spdk_nvme_cpl_is_error(cpl)) {
|
||||||
|
NVME_CTRLR_ERRLOG(ctx->ctrlr, "Failed to read the CSTS register\n");
|
||||||
|
ctx->shutdown_complete = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(value <= UINT32_MAX);
|
||||||
|
ctx->csts.raw = (uint32_t)value;
|
||||||
|
ctx->state = NVME_CTRLR_DETACH_GET_CSTS_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1090,13 +1138,33 @@ nvme_ctrlr_shutdown_poll_async(struct spdk_nvme_ctrlr *ctrlr,
|
|||||||
union spdk_nvme_csts_register csts;
|
union spdk_nvme_csts_register csts;
|
||||||
uint32_t ms_waited;
|
uint32_t ms_waited;
|
||||||
|
|
||||||
ms_waited = (spdk_get_ticks() - ctx->shutdown_start_tsc) * 1000 / spdk_get_ticks_hz();
|
switch (ctx->state) {
|
||||||
|
case NVME_CTRLR_DETACH_SET_CC:
|
||||||
|
case NVME_CTRLR_DETACH_GET_CSTS:
|
||||||
|
/* We're still waiting for the register operation to complete */
|
||||||
|
spdk_nvme_qpair_process_completions(ctrlr->adminq, 0);
|
||||||
|
return -EAGAIN;
|
||||||
|
|
||||||
if (nvme_ctrlr_get_csts(ctrlr, &csts)) {
|
case NVME_CTRLR_DETACH_CHECK_CSTS:
|
||||||
NVME_CTRLR_ERRLOG(ctrlr, "get_csts() failed\n");
|
ctx->state = NVME_CTRLR_DETACH_GET_CSTS;
|
||||||
return -EIO;
|
if (nvme_ctrlr_get_csts_async(ctrlr, nvme_ctrlr_shutdown_get_csts_done, ctx)) {
|
||||||
|
NVME_CTRLR_ERRLOG(ctrlr, "Failed to read the CSTS register\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
return -EAGAIN;
|
||||||
|
|
||||||
|
case NVME_CTRLR_DETACH_GET_CSTS_DONE:
|
||||||
|
ctx->state = NVME_CTRLR_DETACH_CHECK_CSTS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "Should never happen");
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ms_waited = (spdk_get_ticks() - ctx->shutdown_start_tsc) * 1000 / spdk_get_ticks_hz();
|
||||||
|
csts.raw = ctx->csts.raw;
|
||||||
|
|
||||||
if (csts.bits.shst == SPDK_NVME_SHST_COMPLETE) {
|
if (csts.bits.shst == SPDK_NVME_SHST_COMPLETE) {
|
||||||
NVME_CTRLR_DEBUGLOG(ctrlr, "shutdown complete in %u milliseconds\n", ms_waited);
|
NVME_CTRLR_DEBUGLOG(ctrlr, "shutdown complete in %u milliseconds\n", ms_waited);
|
||||||
return 0;
|
return 0;
|
||||||
@ -4062,7 +4130,7 @@ nvme_ctrlr_destruct_poll_async(struct spdk_nvme_ctrlr *ctrlr,
|
|||||||
void
|
void
|
||||||
nvme_ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr)
|
nvme_ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr)
|
||||||
{
|
{
|
||||||
struct nvme_ctrlr_detach_ctx ctx = {};
|
struct nvme_ctrlr_detach_ctx ctx = { .ctrlr = ctrlr };
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
nvme_ctrlr_destruct_async(ctrlr, &ctx);
|
nvme_ctrlr_destruct_async(ctrlr, &ctx);
|
||||||
|
@ -1009,12 +1009,21 @@ struct spdk_nvme_probe_ctx {
|
|||||||
|
|
||||||
typedef void (*nvme_ctrlr_detach_cb)(struct spdk_nvme_ctrlr *ctrlr);
|
typedef void (*nvme_ctrlr_detach_cb)(struct spdk_nvme_ctrlr *ctrlr);
|
||||||
|
|
||||||
|
enum nvme_ctrlr_detach_state {
|
||||||
|
NVME_CTRLR_DETACH_SET_CC,
|
||||||
|
NVME_CTRLR_DETACH_CHECK_CSTS,
|
||||||
|
NVME_CTRLR_DETACH_GET_CSTS,
|
||||||
|
NVME_CTRLR_DETACH_GET_CSTS_DONE,
|
||||||
|
};
|
||||||
|
|
||||||
struct nvme_ctrlr_detach_ctx {
|
struct nvme_ctrlr_detach_ctx {
|
||||||
struct spdk_nvme_ctrlr *ctrlr;
|
struct spdk_nvme_ctrlr *ctrlr;
|
||||||
nvme_ctrlr_detach_cb cb_fn;
|
nvme_ctrlr_detach_cb cb_fn;
|
||||||
uint64_t shutdown_start_tsc;
|
uint64_t shutdown_start_tsc;
|
||||||
uint32_t shutdown_timeout_ms;
|
uint32_t shutdown_timeout_ms;
|
||||||
bool shutdown_complete;
|
bool shutdown_complete;
|
||||||
|
enum nvme_ctrlr_detach_state state;
|
||||||
|
union spdk_nvme_csts_register csts;
|
||||||
TAILQ_ENTRY(nvme_ctrlr_detach_ctx) link;
|
TAILQ_ENTRY(nvme_ctrlr_detach_ctx) link;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user