diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index 182741dab..6dee3231c 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -3954,6 +3954,8 @@ struct spdk_nvme_transport_ops { int (*ctrlr_get_memory_domains)(const struct spdk_nvme_ctrlr *ctrlr, struct spdk_memory_domain **domains, int array_size); + + int (*ctrlr_ready)(struct spdk_nvme_ctrlr *ctrlr); }; /** diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index c4a2d46fb..a031c04f3 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -1395,6 +1395,8 @@ nvme_ctrlr_state_string(enum nvme_ctrlr_state state) return "set host ID"; case NVME_CTRLR_STATE_WAIT_FOR_HOST_ID: return "wait for set host ID"; + case NVME_CTRLR_STATE_TRANSPORT_READY: + return "transport ready"; case NVME_CTRLR_STATE_READY: return "ready"; case NVME_CTRLR_STATE_ERROR: @@ -2906,7 +2908,7 @@ nvme_ctrlr_set_host_id_done(void *arg, const struct spdk_nvme_cpl *cpl) NVME_CTRLR_DEBUGLOG(ctrlr, "Set Features - Host ID was successful\n"); } - nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_READY, NVME_TIMEOUT_INFINITE); + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_TRANSPORT_READY, ctrlr->opts.admin_timeout_ms); } static int @@ -2922,7 +2924,7 @@ nvme_ctrlr_set_host_id(struct spdk_nvme_ctrlr *ctrlr) * Set Features - Host Identifier after Connect, so we don't need to do anything here. */ NVME_CTRLR_DEBUGLOG(ctrlr, "NVMe-oF transport - not sending Set Features - Host ID\n"); - nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_READY, NVME_TIMEOUT_INFINITE); + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_TRANSPORT_READY, ctrlr->opts.admin_timeout_ms); return 0; } @@ -2939,7 +2941,7 @@ nvme_ctrlr_set_host_id(struct spdk_nvme_ctrlr *ctrlr) /* If the user specified an all-zeroes host identifier, don't send the command. */ if (spdk_mem_all_zero(host_id, host_id_size)) { NVME_CTRLR_DEBUGLOG(ctrlr, "User did not specify host ID - not sending Set Features - Host ID\n"); - nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_READY, NVME_TIMEOUT_INFINITE); + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_TRANSPORT_READY, ctrlr->opts.admin_timeout_ms); return 0; } @@ -3948,6 +3950,16 @@ nvme_ctrlr_process_init(struct spdk_nvme_ctrlr *ctrlr) rc = nvme_ctrlr_set_host_id(ctrlr); break; + case NVME_CTRLR_STATE_TRANSPORT_READY: + rc = nvme_transport_ctrlr_ready(ctrlr); + if (rc) { + NVME_CTRLR_ERRLOG(ctrlr, "Transport controller ready step failed: rc %d\n", rc); + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_ERROR, NVME_TIMEOUT_INFINITE); + } else { + nvme_ctrlr_set_state(ctrlr, NVME_CTRLR_STATE_READY, NVME_TIMEOUT_INFINITE); + } + break; + case NVME_CTRLR_STATE_READY: NVME_CTRLR_DEBUGLOG(ctrlr, "Ctrlr already in ready state\n"); return 0; diff --git a/lib/nvme/nvme_internal.h b/lib/nvme/nvme_internal.h index fe4657b89..2e3773261 100644 --- a/lib/nvme/nvme_internal.h +++ b/lib/nvme/nvme_internal.h @@ -775,6 +775,11 @@ enum nvme_ctrlr_state { */ NVME_CTRLR_STATE_WAIT_FOR_HOST_ID, + /** + * Let transport layer do its part of initialization. + */ + NVME_CTRLR_STATE_TRANSPORT_READY, + /** * Controller initialization has completed and the controller is ready. */ @@ -1470,6 +1475,7 @@ struct spdk_nvme_ctrlr *nvme_transport_ctrlr_construct(const struct spdk_nvme_tr int nvme_transport_ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr); int nvme_transport_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx, bool direct_connect); int nvme_transport_ctrlr_enable(struct spdk_nvme_ctrlr *ctrlr); +int nvme_transport_ctrlr_ready(struct spdk_nvme_ctrlr *ctrlr); int nvme_transport_ctrlr_set_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t value); int nvme_transport_ctrlr_set_reg_8(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t value); int nvme_transport_ctrlr_get_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t *value); diff --git a/lib/nvme/nvme_transport.c b/lib/nvme/nvme_transport.c index 15623a4c8..277abbe7c 100644 --- a/lib/nvme/nvme_transport.c +++ b/lib/nvme/nvme_transport.c @@ -141,6 +141,19 @@ nvme_transport_ctrlr_enable(struct spdk_nvme_ctrlr *ctrlr) return transport->ops.ctrlr_enable(ctrlr); } +int +nvme_transport_ctrlr_ready(struct spdk_nvme_ctrlr *ctrlr) +{ + const struct spdk_nvme_transport *transport = nvme_get_transport(ctrlr->trid.trstring); + + assert(transport != NULL); + if (transport->ops.ctrlr_ready) { + return transport->ops.ctrlr_ready(ctrlr); + } + + return 0; +} + int nvme_transport_ctrlr_set_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t value) { diff --git a/test/unit/lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c b/test/unit/lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c index 9d1a00df4..0e05b62ce 100644 --- a/test/unit/lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c +++ b/test/unit/lib/nvme/nvme_ctrlr.c/nvme_ctrlr_ut.c @@ -65,6 +65,14 @@ nvme_transport_ctrlr_get_memory_domains(const struct spdk_nvme_ctrlr *ctrlr, return 0; } +DEFINE_RETURN_MOCK(nvme_transport_ctrlr_ready, int); +int +nvme_transport_ctrlr_ready(struct spdk_nvme_ctrlr *ctrlr) +{ + HANDLE_RETURN_MOCK(nvme_transport_ctrlr_ready); + return 0; +} + struct spdk_nvme_ctrlr *nvme_transport_ctrlr_construct(const struct spdk_nvme_transport_id *trid, const struct spdk_nvme_ctrlr_opts *opts, void *devhandle) @@ -3276,6 +3284,24 @@ test_nvme_ctrlr_get_memory_domains(void) MOCK_CLEAR(nvme_transport_ctrlr_get_memory_domains); } +static void +test_nvme_transport_ctrlr_ready(void) +{ + DECLARE_AND_CONSTRUCT_CTRLR(); + + /* Transport init succeeded */ + ctrlr.state = NVME_CTRLR_STATE_TRANSPORT_READY; + SPDK_CU_ASSERT_FATAL(nvme_ctrlr_process_init(&ctrlr) == 0); + CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_READY); + + /* Transport init failed */ + ctrlr.state = NVME_CTRLR_STATE_TRANSPORT_READY; + MOCK_SET(nvme_transport_ctrlr_ready, -1); + SPDK_CU_ASSERT_FATAL(nvme_ctrlr_process_init(&ctrlr) == -1); + CU_ASSERT(ctrlr.state == NVME_CTRLR_STATE_ERROR); + MOCK_CLEAR(nvme_transport_ctrlr_ready); +} + int main(int argc, char **argv) { @@ -3331,6 +3357,7 @@ main(int argc, char **argv) CU_ADD_TEST(suite, test_nvme_ctrlr_parse_ana_log_page); CU_ADD_TEST(suite, test_nvme_ctrlr_ana_resize); CU_ADD_TEST(suite, test_nvme_ctrlr_get_memory_domains); + CU_ADD_TEST(suite, test_nvme_transport_ctrlr_ready); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests();