Commit b6ecc372 authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Tomasz Zawadzki
Browse files

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: default avatarJim Harris <james.r.harris@intel.com>
Signed-off-by: default avatarKonrad 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: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarAleksey Marchuk <alexeymar@mellanox.com>
parent 51b018da
Loading
Loading
Loading
Loading
+91 −23
Original line number Diff line number Diff line
@@ -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;

	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;
	struct nvme_ctrlr_detach_ctx *ctx = _ctx;
	struct spdk_nvme_ctrlr *ctrlr = ctx->ctrlr;

	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,12 +1138,32 @@ 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");
	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);
@@ -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);
+9 −0
Original line number Diff line number Diff line
@@ -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;
};