nvme: add I/O timeout callback
Change-Id: Ie6220590467b88fe1e63b4b0f8a01221fc0c1206 Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
parent
a4cc346b17
commit
7c60aec01e
@ -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).
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
{
|
||||
@ -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…
Reference in New Issue
Block a user