nvme: Add helper functions to do a Controller Level Reset (Set CC.EN to 0)

Previously, we did not do any Controller Level Reset when disconnecting
the admin qpair.

However, for PCIe transport, we need to stop any activity of the
controller, i.e., delete all I/O SQ and CQs before
nvme_transport_ctrlr_disconnect_qpair_done() calls
nvme_transport_qpair_abort_reqs() (i.e., nvme_pcie_qpair_abort_trackers()).
Otherwise, some corruption may occur because completed I/Os may still be
in progress on the NVMe device.

Not to change any public API, nvme_pcie_ctrlr_disconnect_qpair() is a
convenient place to initiate a Controller Level Reset because it is
called from spdk_nvme_ctrlr_disconnect(). Then
nvme_pcie_qpair_process_completions() can process it until completion.

However, necessary functions are not accessible from PCIe transport.

This patch adds two helper functions and guards us from some undesirable
behaviors because it was not assumed that nvme_ctrlr_process_init() is
called from the completion context and ends in the middle of transition.

Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I3d986e94ba71b83beeff7e75cf92033b5fa6f075
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/12559
Community-CI: Mellanox Build Bot
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Reviewed-by: Michael Haeuptle <michaelhaeuptle@gmail.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Shuhei Matsumoto 2022-05-09 11:27:03 +09:00 committed by Tomasz Zawadzki
parent 1eca87c39c
commit bdc9fa832d
2 changed files with 50 additions and 7 deletions

View File

@ -1788,6 +1788,37 @@ spdk_nvme_ctrlr_reconnect_poll_async(struct spdk_nvme_ctrlr *ctrlr)
return rc; return rc;
} }
/*
* For PCIe transport, spdk_nvme_ctrlr_disconnect() will do a Controller Level Reset
* (Change CC.EN from 1 to 0) as a operation to disconnect the admin qpair.
* The following two functions are added to do a Controller Level Reset. They have
* to be called under the nvme controller's lock.
*/
void
nvme_ctrlr_disable(struct spdk_nvme_ctrlr *ctrlr)
{
assert(ctrlr->is_disconnecting == true);
nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_CHECK_EN, NVME_TIMEOUT_INFINITE);
}
int
nvme_ctrlr_disable_poll(struct spdk_nvme_ctrlr *ctrlr)
{
int rc = 0;
if (nvme_ctrlr_process_init(ctrlr) != 0) {
NVME_CTRLR_ERRLOG(ctrlr, "failed to disable controller\n");
rc = -1;
}
if (ctrlr->state != NVME_CTRLR_STATE_DISABLED && rc != -1) {
return -EAGAIN;
}
return rc;
}
int int
spdk_nvme_ctrlr_reset(struct spdk_nvme_ctrlr *ctrlr) spdk_nvme_ctrlr_reset(struct spdk_nvme_ctrlr *ctrlr)
{ {
@ -3852,6 +3883,9 @@ nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr)
break; break;
case NVME_CTRLR_STATE_DISABLED: case NVME_CTRLR_STATE_DISABLED:
if (ctrlr->is_disconnecting) {
NVME_CTRLR_DEBUGLOG(ctrlr, "Ctrlr was disabled.\n");
} else {
nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_ENABLE, ready_timeout_in_ms); nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_ENABLE, ready_timeout_in_ms);
/* /*
@ -3859,6 +3893,7 @@ nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr)
* set to 1 if it is too soon after CSTS.RDY is reported as 0. * set to 1 if it is too soon after CSTS.RDY is reported as 0.
*/ */
spdk_delay_us(100); spdk_delay_us(100);
}
break; break;
case NVME_CTRLR_STATE_ENABLE: case NVME_CTRLR_STATE_ENABLE:
@ -3974,7 +4009,13 @@ nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr)
case NVME_CTRLR_STATE_WAIT_FOR_SUPPORTED_INTEL_LOG_PAGES: case NVME_CTRLR_STATE_WAIT_FOR_SUPPORTED_INTEL_LOG_PAGES:
case NVME_CTRLR_STATE_WAIT_FOR_DB_BUF_CFG: case NVME_CTRLR_STATE_WAIT_FOR_DB_BUF_CFG:
case NVME_CTRLR_STATE_WAIT_FOR_HOST_ID: case NVME_CTRLR_STATE_WAIT_FOR_HOST_ID:
/*
* nvme_ctrlr_process_init() may be called from the completion context
* for the admin qpair. Avoid recursive calls for this case.
*/
if (!ctrlr->adminq->in_completion_context) {
spdk_nvme_qpair_process_completions(ctrlr->adminq, 0); spdk_nvme_qpair_process_completions(ctrlr->adminq, 0);
}
break; break;
default: default:

View File

@ -1185,6 +1185,8 @@ int nvme_ctrlr_destruct_poll_async(struct spdk_nvme_ctrlr *ctrlr,
struct nvme_ctrlr_detach_ctx *ctx); struct nvme_ctrlr_detach_ctx *ctx);
void nvme_ctrlr_fail(struct spdk_nvme_ctrlr *ctrlr, bool hot_remove); void nvme_ctrlr_fail(struct spdk_nvme_ctrlr *ctrlr, bool hot_remove);
int nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr); int nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr);
void nvme_ctrlr_disable(struct spdk_nvme_ctrlr *ctrlr);
int nvme_ctrlr_disable_poll(struct spdk_nvme_ctrlr *ctrlr);
void nvme_ctrlr_connected(struct spdk_nvme_probe_ctx *probe_ctx, void nvme_ctrlr_connected(struct spdk_nvme_probe_ctx *probe_ctx,
struct spdk_nvme_ctrlr *ctrlr); struct spdk_nvme_ctrlr *ctrlr);