Loading include/spdk/nvme.h +22 −0 Original line number Diff line number Diff line Loading @@ -381,6 +381,28 @@ void spdk_nvme_ctrlr_register_aer_callback(struct spdk_nvme_ctrlr *ctrlr, */ struct spdk_nvme_qpair; /** * Signature for the callback function invoked when a timeout is * detected on a request. */ typedef void (*spdk_nvme_timeout_cb)(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair, void *cb_arg); /** * \brief Register for timeout callback on a controller. * * The application can choose to register for timeout callback or not register * for timeout callback. * * \param ctrlr NVMe controller on which to monitor for timeout. * \param timeout_sec Timeout value in seconds. * \param cb_fn A function pointer that points to the callback function * \param cb_arg Argument to the callback function. */ void spdk_nvme_ctrlr_register_timeout_callback(struct spdk_nvme_ctrlr *ctrlr, uint32_t timeout_sec, spdk_nvme_timeout_cb cb_fn, void *cb_arg); /** * \brief Allocate an I/O queue pair (submission and completion queue). * Loading lib/nvme/nvme_ctrlr.c +12 −0 Original line number Diff line number Diff line Loading @@ -1299,6 +1299,9 @@ nvme_ctrlr_construct(struct spdk_nvme_ctrlr *ctrlr) } TAILQ_INIT(&ctrlr->active_procs); ctrlr->timeout_cb_fn = NULL; ctrlr->timeout_cb_arg = NULL; ctrlr->timeout_ticks = 0; return rc; } Loading Loading @@ -1430,6 +1433,15 @@ spdk_nvme_ctrlr_register_aer_callback(struct spdk_nvme_ctrlr *ctrlr, ctrlr->aer_cb_arg = aer_cb_arg; } void spdk_nvme_ctrlr_register_timeout_callback(struct spdk_nvme_ctrlr *ctrlr, uint32_t nvme_timeout, spdk_nvme_timeout_cb cb_fn, void *cb_arg) { ctrlr->timeout_ticks = nvme_timeout * spdk_get_ticks_hz(); ctrlr->timeout_cb_fn = cb_fn; ctrlr->timeout_cb_arg = cb_arg; } bool spdk_nvme_ctrlr_is_log_page_supported(struct spdk_nvme_ctrlr *ctrlr, uint8_t log_page) { Loading lib/nvme/nvme_internal.h +7 −0 Original line number Diff line number Diff line Loading @@ -411,6 +411,13 @@ struct spdk_nvme_ctrlr { /** Track all the processes manage this controller */ TAILQ_HEAD(, spdk_nvme_ctrlr_process) active_procs; /** * A function pointer to timeout callback function */ spdk_nvme_timeout_cb timeout_cb_fn; void *timeout_cb_arg; uint64_t timeout_ticks; }; struct nvme_driver { Loading lib/nvme/nvme_pcie.c +50 −2 Original line number Diff line number Diff line Loading @@ -121,14 +121,13 @@ struct nvme_tracker { uint32_t rsvd2; uint64_t timeout_tick; uint64_t prp_sgl_bus_addr; union { uint64_t prp[NVME_MAX_PRP_LIST_ENTRIES]; struct spdk_nvme_sgl_descriptor sgl[NVME_MAX_SGL_DESCRIPTORS]; } u; uint64_t rsvd3; }; /* * struct nvme_tracker must be exactly 4K so that the prp[] array does not cross a page boundary Loading Loading @@ -933,6 +932,8 @@ nvme_pcie_qpair_submit_tracker(struct spdk_nvme_qpair *qpair, struct nvme_tracke struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair); struct nvme_pcie_ctrlr *pctrlr = nvme_pcie_ctrlr(qpair->ctrlr); tr->timeout_tick = spdk_get_ticks() + qpair->ctrlr->timeout_ticks; req = tr->req; pqpair->tr[tr->cid].active = true; Loading Loading @@ -1725,6 +1726,44 @@ exit: return rc; } static void nvme_pcie_qpair_check_timeout(struct spdk_nvme_qpair *qpair) { uint64_t t02; struct nvme_tracker *tr; struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair); struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; if (TAILQ_EMPTY(&pqpair->outstanding_tr)) { return; } /* * qpair could be either for normal i/o or for admin command. If qpair is admin * and request is SPDK_NVME_OPC_ASYNC_EVENT_REQUEST, skip to next previous. */ tr = TAILQ_LAST(&pqpair->outstanding_tr, nvme_outstanding_tr_head); while (tr->req->cmd.opc == SPDK_NVME_OPC_ASYNC_EVENT_REQUEST) { /* qpair is for admin request */ tr = TAILQ_PREV(tr, nvme_outstanding_tr_head, tq_list); if (!tr) { /* * All request were AER */ return; } } t02 = spdk_get_ticks(); if (tr->timeout_tick <= t02) { /* * Request has timed out. This could be i/o or admin request. * Call the registered timeout function for user to take action. */ ctrlr->timeout_cb_fn(ctrlr, qpair, ctrlr->timeout_cb_arg); } } int32_t nvme_pcie_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions) { Loading Loading @@ -1791,6 +1830,15 @@ nvme_pcie_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_ g_thread_mmio_ctrlr = NULL; } if (qpair->ctrlr->state == NVME_CTRLR_STATE_READY) { if (qpair->ctrlr->timeout_cb_fn) { /* * User registered for timeout callback */ nvme_pcie_qpair_check_timeout(qpair); } } /* Before returning, complete any pending admin request. */ if (nvme_qpair_is_admin_queue(qpair)) { nvme_pcie_qpair_complete_pending_admin_request(qpair); Loading Loading
include/spdk/nvme.h +22 −0 Original line number Diff line number Diff line Loading @@ -381,6 +381,28 @@ void spdk_nvme_ctrlr_register_aer_callback(struct spdk_nvme_ctrlr *ctrlr, */ struct spdk_nvme_qpair; /** * Signature for the callback function invoked when a timeout is * detected on a request. */ typedef void (*spdk_nvme_timeout_cb)(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair, void *cb_arg); /** * \brief Register for timeout callback on a controller. * * The application can choose to register for timeout callback or not register * for timeout callback. * * \param ctrlr NVMe controller on which to monitor for timeout. * \param timeout_sec Timeout value in seconds. * \param cb_fn A function pointer that points to the callback function * \param cb_arg Argument to the callback function. */ void spdk_nvme_ctrlr_register_timeout_callback(struct spdk_nvme_ctrlr *ctrlr, uint32_t timeout_sec, spdk_nvme_timeout_cb cb_fn, void *cb_arg); /** * \brief Allocate an I/O queue pair (submission and completion queue). * Loading
lib/nvme/nvme_ctrlr.c +12 −0 Original line number Diff line number Diff line Loading @@ -1299,6 +1299,9 @@ nvme_ctrlr_construct(struct spdk_nvme_ctrlr *ctrlr) } TAILQ_INIT(&ctrlr->active_procs); ctrlr->timeout_cb_fn = NULL; ctrlr->timeout_cb_arg = NULL; ctrlr->timeout_ticks = 0; return rc; } Loading Loading @@ -1430,6 +1433,15 @@ spdk_nvme_ctrlr_register_aer_callback(struct spdk_nvme_ctrlr *ctrlr, ctrlr->aer_cb_arg = aer_cb_arg; } void spdk_nvme_ctrlr_register_timeout_callback(struct spdk_nvme_ctrlr *ctrlr, uint32_t nvme_timeout, spdk_nvme_timeout_cb cb_fn, void *cb_arg) { ctrlr->timeout_ticks = nvme_timeout * spdk_get_ticks_hz(); ctrlr->timeout_cb_fn = cb_fn; ctrlr->timeout_cb_arg = cb_arg; } bool spdk_nvme_ctrlr_is_log_page_supported(struct spdk_nvme_ctrlr *ctrlr, uint8_t log_page) { Loading
lib/nvme/nvme_internal.h +7 −0 Original line number Diff line number Diff line Loading @@ -411,6 +411,13 @@ struct spdk_nvme_ctrlr { /** Track all the processes manage this controller */ TAILQ_HEAD(, spdk_nvme_ctrlr_process) active_procs; /** * A function pointer to timeout callback function */ spdk_nvme_timeout_cb timeout_cb_fn; void *timeout_cb_arg; uint64_t timeout_ticks; }; struct nvme_driver { Loading
lib/nvme/nvme_pcie.c +50 −2 Original line number Diff line number Diff line Loading @@ -121,14 +121,13 @@ struct nvme_tracker { uint32_t rsvd2; uint64_t timeout_tick; uint64_t prp_sgl_bus_addr; union { uint64_t prp[NVME_MAX_PRP_LIST_ENTRIES]; struct spdk_nvme_sgl_descriptor sgl[NVME_MAX_SGL_DESCRIPTORS]; } u; uint64_t rsvd3; }; /* * struct nvme_tracker must be exactly 4K so that the prp[] array does not cross a page boundary Loading Loading @@ -933,6 +932,8 @@ nvme_pcie_qpair_submit_tracker(struct spdk_nvme_qpair *qpair, struct nvme_tracke struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair); struct nvme_pcie_ctrlr *pctrlr = nvme_pcie_ctrlr(qpair->ctrlr); tr->timeout_tick = spdk_get_ticks() + qpair->ctrlr->timeout_ticks; req = tr->req; pqpair->tr[tr->cid].active = true; Loading Loading @@ -1725,6 +1726,44 @@ exit: return rc; } static void nvme_pcie_qpair_check_timeout(struct spdk_nvme_qpair *qpair) { uint64_t t02; struct nvme_tracker *tr; struct nvme_pcie_qpair *pqpair = nvme_pcie_qpair(qpair); struct spdk_nvme_ctrlr *ctrlr = qpair->ctrlr; if (TAILQ_EMPTY(&pqpair->outstanding_tr)) { return; } /* * qpair could be either for normal i/o or for admin command. If qpair is admin * and request is SPDK_NVME_OPC_ASYNC_EVENT_REQUEST, skip to next previous. */ tr = TAILQ_LAST(&pqpair->outstanding_tr, nvme_outstanding_tr_head); while (tr->req->cmd.opc == SPDK_NVME_OPC_ASYNC_EVENT_REQUEST) { /* qpair is for admin request */ tr = TAILQ_PREV(tr, nvme_outstanding_tr_head, tq_list); if (!tr) { /* * All request were AER */ return; } } t02 = spdk_get_ticks(); if (tr->timeout_tick <= t02) { /* * Request has timed out. This could be i/o or admin request. * Call the registered timeout function for user to take action. */ ctrlr->timeout_cb_fn(ctrlr, qpair, ctrlr->timeout_cb_arg); } } int32_t nvme_pcie_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions) { Loading Loading @@ -1791,6 +1830,15 @@ nvme_pcie_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_ g_thread_mmio_ctrlr = NULL; } if (qpair->ctrlr->state == NVME_CTRLR_STATE_READY) { if (qpair->ctrlr->timeout_cb_fn) { /* * User registered for timeout callback */ nvme_pcie_qpair_check_timeout(qpair); } } /* Before returning, complete any pending admin request. */ if (nvme_qpair_is_admin_queue(qpair)) { nvme_pcie_qpair_complete_pending_admin_request(qpair); Loading