From 5555513653e02e190d8239cf3564b2139ec6b544 Mon Sep 17 00:00:00 2001 From: Konrad Sztyber Date: Fri, 19 Feb 2021 17:43:53 +0100 Subject: [PATCH] external_code/nvme: basic controller initialization flow Added a simple controller enablement state machine based on the CC.EN and CSTS.RDY bits. The admin queue registers are also filled during this process, so it's now possible to send admin requests. To simplify the code, there are no timeouts for a controller to transition from a specific state to the next one or for the whole initialization process. This means that if a controller gets stuck, the code will hang indefinitely too. Signed-off-by: Konrad Sztyber Change-Id: I93f5a5931d7b24780da242e601dcdf2bec5f6552 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/6673 Tested-by: SPDK CI Jenkins Community-CI: Mellanox Build Bot Reviewed-by: Tomasz Zawadzki Reviewed-by: Jim Harris Reviewed-by: Ben Walker --- test/external_code/nvme/nvme.c | 85 +++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 21 deletions(-) diff --git a/test/external_code/nvme/nvme.c b/test/external_code/nvme/nvme.c index 32b987ee6..9ce61cb75 100644 --- a/test/external_code/nvme/nvme.c +++ b/test/external_code/nvme/nvme.c @@ -178,50 +178,37 @@ nvme_ctrlr_get_cap(struct nvme_ctrlr *ctrlr, union spdk_nvme_cap_register *cap) get_pcie_reg_8(ctrlr, offsetof(struct spdk_nvme_registers, cap), &cap->raw); } -void -nvme_ctrlr_get_cc(struct nvme_ctrlr *ctrlr, union spdk_nvme_cc_register *cc); - -void +static void nvme_ctrlr_get_cc(struct nvme_ctrlr *ctrlr, union spdk_nvme_cc_register *cc) { get_pcie_reg_4(ctrlr, offsetof(struct spdk_nvme_registers, cc), &cc->raw); } -void nvme_ctrlr_get_csts(struct nvme_ctrlr *ctrlr, union spdk_nvme_csts_register *csts); - -void +static void nvme_ctrlr_get_csts(struct nvme_ctrlr *ctrlr, union spdk_nvme_csts_register *csts) { get_pcie_reg_4(ctrlr, offsetof(struct spdk_nvme_registers, csts), &csts->raw); } -void nvme_ctrlr_set_cc(struct nvme_ctrlr *ctrlr, const union spdk_nvme_cc_register *cc); - -void +static void nvme_ctrlr_set_cc(struct nvme_ctrlr *ctrlr, const union spdk_nvme_cc_register *cc) { set_pcie_reg_4(ctrlr, offsetof(struct spdk_nvme_registers, cc.raw), cc->raw); } -void nvme_ctrlr_set_asq(struct nvme_ctrlr *ctrlr, uint64_t value); - -void +static void nvme_ctrlr_set_asq(struct nvme_ctrlr *ctrlr, uint64_t value) { set_pcie_reg_8(ctrlr, offsetof(struct spdk_nvme_registers, asq), value); } -void nvme_ctrlr_set_acq(struct nvme_ctrlr *ctrlr, uint64_t value); - -void +static void nvme_ctrlr_set_acq(struct nvme_ctrlr *ctrlr, uint64_t value) { set_pcie_reg_8(ctrlr, offsetof(struct spdk_nvme_registers, acq), value); } -void nvme_ctrlr_set_aqa(struct nvme_ctrlr *ctrlr, const union spdk_nvme_aqa_register *aqa); - -void +static void nvme_ctrlr_set_aqa(struct nvme_ctrlr *ctrlr, const union spdk_nvme_aqa_register *aqa) { set_pcie_reg_4(ctrlr, offsetof(struct spdk_nvme_registers, aqa.raw), aqa->raw); @@ -362,8 +349,64 @@ pcie_enum_cb(void *ctx, struct spdk_pci_device *pci_dev) static int process_ctrlr_init(struct nvme_ctrlr *ctrlr) { - /* Immediately mark the controller as ready for now */ - ctrlr->state = NVME_CTRLR_STATE_READY; + union spdk_nvme_cc_register cc; + union spdk_nvme_csts_register csts; + union spdk_nvme_aqa_register aqa; + + if (ctrlr->state == NVME_CTRLR_STATE_READY) { + return 0; + } + + nvme_ctrlr_get_cc(ctrlr, &cc); + nvme_ctrlr_get_csts(ctrlr, &csts); + + switch (ctrlr->state) { + case NVME_CTRLR_STATE_INIT: + if (cc.bits.en) { + if (csts.bits.rdy == 0) { + ctrlr->state = NVME_CTRLR_STATE_DISABLE_WAIT_FOR_READY_1; + break; + } + + cc.bits.en = 0; + nvme_ctrlr_set_cc(ctrlr, &cc); + } + ctrlr->state = NVME_CTRLR_STATE_DISABLE_WAIT_FOR_READY_0; + break; + case NVME_CTRLR_STATE_DISABLE_WAIT_FOR_READY_1: + if (csts.bits.rdy) { + cc.bits.en = 0; + nvme_ctrlr_set_cc(ctrlr, &cc); + ctrlr->state = NVME_CTRLR_STATE_DISABLE_WAIT_FOR_READY_0; + } + break; + case NVME_CTRLR_STATE_DISABLE_WAIT_FOR_READY_0: + if (csts.bits.rdy == 0) { + ctrlr->state = NVME_CTRLR_STATE_ENABLE; + } + break; + case NVME_CTRLR_STATE_ENABLE: + nvme_ctrlr_set_asq(ctrlr, ctrlr->admin_qpair->sq_paddr); + nvme_ctrlr_set_acq(ctrlr, ctrlr->admin_qpair->cq_paddr); + + aqa.raw = 0; + aqa.bits.asqs = ctrlr->admin_qpair->num_entries - 1; + aqa.bits.acqs = ctrlr->admin_qpair->num_entries - 1; + nvme_ctrlr_set_aqa(ctrlr, &aqa); + + cc.bits.en = 1; + nvme_ctrlr_set_cc(ctrlr, &cc); + ctrlr->state = NVME_CTRLR_STATE_ENABLE_WAIT_FOR_READY_1; + break; + case NVME_CTRLR_STATE_ENABLE_WAIT_FOR_READY_1: + if (csts.bits.rdy) { + ctrlr->state = NVME_CTRLR_STATE_READY; + } + break; + default: + assert(0 && "should never get here"); + return -1; + } return 0; }