Commit 7c60aec0 authored by Isaac Otsiabah's avatar Isaac Otsiabah Committed by Daniel Verkamp
Browse files

nvme: add I/O timeout callback



Change-Id: Ie6220590467b88fe1e63b4b0f8a01221fc0c1206
Signed-off-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
parent a4cc346b
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -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).
 *
+12 −0
Original line number Diff line number Diff line
@@ -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)
{
+7 −0
Original line number Diff line number Diff line
@@ -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 {
+50 −2
Original line number Diff line number Diff line
@@ -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);