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:
Konrad Sztyber 2021-07-08 11:26:39 +02:00 committed by Tomasz Zawadzki
parent 51b018da0f
commit b6ecc37298
2 changed files with 100 additions and 23 deletions

View File

@ -1043,26 +1043,13 @@ spdk_nvme_ctrlr_fail(struct spdk_nvme_ctrlr *ctrlr)
}
static void
nvme_ctrlr_shutdown_async(struct spdk_nvme_ctrlr *ctrlr,
struct nvme_ctrlr_detach_ctx *ctx)
nvme_ctrlr_shutdown_set_cc_done(void *_ctx, uint64_t value, const struct spdk_nvme_cpl *cpl)
{
union spdk_nvme_cc_register cc;
struct nvme_ctrlr_detach_ctx *ctx = _ctx;
struct spdk_nvme_ctrlr *ctrlr = ctx->ctrlr;
if (ctrlr->is_removed) {
ctx->shutdown_complete = true;
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");
if (spdk_nvme_cpl_is_error(cpl)) {
NVME_CTRLR_ERRLOG(ctrlr, "Failed to write CC.SHN\n");
ctx->shutdown_complete = true;
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);
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
@ -1090,13 +1138,33 @@ nvme_ctrlr_shutdown_poll_async(struct spdk_nvme_ctrlr *ctrlr,
union spdk_nvme_csts_register csts;
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)) {
NVME_CTRLR_ERRLOG(ctrlr, "get_csts() failed\n");
return -EIO;
case NVME_CTRLR_DETACH_CHECK_CSTS:
ctx->state = NVME_CTRLR_DETACH_GET_CSTS;
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) {
NVME_CTRLR_DEBUGLOG(ctrlr, "shutdown complete in %u milliseconds\n", ms_waited);
return 0;
@ -4062,7 +4130,7 @@ nvme_ctrlr_destruct_poll_async(struct spdk_nvme_ctrlr *ctrlr,
void
nvme_ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr)
{
struct nvme_ctrlr_detach_ctx ctx = {};
struct nvme_ctrlr_detach_ctx ctx = { .ctrlr = ctrlr };
int rc;
nvme_ctrlr_destruct_async(ctrlr, &ctx);

View File

@ -1009,12 +1009,21 @@ struct spdk_nvme_probe_ctx {
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 spdk_nvme_ctrlr *ctrlr;
nvme_ctrlr_detach_cb cb_fn;
uint64_t shutdown_start_tsc;
uint32_t shutdown_timeout_ms;
bool shutdown_complete;
enum nvme_ctrlr_detach_state state;
union spdk_nvme_csts_register csts;
TAILQ_ENTRY(nvme_ctrlr_detach_ctx) link;
};