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:
parent
1eca87c39c
commit
bdc9fa832d
@ -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,13 +3883,17 @@ nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NVME_CTRLR_STATE_DISABLED:
|
case NVME_CTRLR_STATE_DISABLED:
|
||||||
nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_ENABLE, ready_timeout_in_ms);
|
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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delay 100us before setting CC.EN = 1. Some NVMe SSDs miss CC.EN getting
|
* Delay 100us before setting CC.EN = 1. Some NVMe SSDs miss CC.EN getting
|
||||||
* 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:
|
||||||
spdk_nvme_qpair_process_completions(ctrlr->adminq, 0);
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user