From: Shai Malin <smalin@marvell.com>
To: <netdev@vger.kernel.org>, <linux-nvme@lists.infradead.org>,
<davem@davemloft.net>, <kuba@kernel.org>, <sagi@grimberg.me>,
<hch@lst.de>, <axboe@fb.com>, <kbusch@kernel.org>
Cc: <aelior@marvell.com>, <mkalderon@marvell.com>,
<okulkarni@marvell.com>, <pkushwaha@marvell.com>,
<malin1024@gmail.com>, <smalin@marvell.com>
Subject: [RFC PATCH v5 26/27] qedn: Add Connection and IO level recovery flows
Date: Wed, 19 May 2021 14:13:39 +0300 [thread overview]
Message-ID: <20210519111340.20613-27-smalin@marvell.com> (raw)
In-Reply-To: <20210519111340.20613-1-smalin@marvell.com>
This patch will present the connection level functionalities:
- conn clear-sq: will release the FW restrictions in order to flush all
the pending IOs.
- drain: in case clear-sq is stuck, will release all the device FW
restrictions in order to flush all the pending IOs.
- task cleanup - will flush the IO level resources.
Acked-by: Igor Russkikh <irusskikh@marvell.com>
Signed-off-by: Prabhakar Kushwaha <pkushwaha@marvell.com>
Signed-off-by: Omkar Kulkarni <okulkarni@marvell.com>
Signed-off-by: Michal Kalderon <mkalderon@marvell.com>
Signed-off-by: Ariel Elior <aelior@marvell.com>
Signed-off-by: Shai Malin <smalin@marvell.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
---
drivers/nvme/hw/qedn/qedn.h | 8 ++
drivers/nvme/hw/qedn/qedn_conn.c | 128 ++++++++++++++++++++++++++++++-
drivers/nvme/hw/qedn/qedn_main.c | 1 +
drivers/nvme/hw/qedn/qedn_task.c | 27 ++++++-
4 files changed, 161 insertions(+), 3 deletions(-)
diff --git a/drivers/nvme/hw/qedn/qedn.h b/drivers/nvme/hw/qedn/qedn.h
index a7be866de6f6..e01584bd8d20 100644
--- a/drivers/nvme/hw/qedn/qedn.h
+++ b/drivers/nvme/hw/qedn/qedn.h
@@ -50,6 +50,8 @@
#define QEDN_FW_CQ_FP_WQ_WORKQUEUE "qedn_fw_cq_fp_wq"
+#define QEDN_DRAIN_MAX_ATTEMPTS 3
+
/* Protocol defines */
#define QEDN_MAX_IO_SIZE QED_NVMETCP_MAX_IO_SIZE
#define QEDN_MAX_PDU_SIZE 0x80000 /* 512KB */
@@ -105,6 +107,8 @@
/* Timeouts and delay constants */
#define QEDN_WAIT_CON_ESTABLSH_TMO 10000 /* 10 seconds */
#define QEDN_RLS_CONS_TMO 5000 /* 5 sec */
+#define QEDN_TASK_CLEANUP_TMO 3000 /* 3 sec */
+#define QEDN_DRAIN_TMO 1000 /* 1 sec */
enum qedn_state {
QEDN_STATE_CORE_PROBED = 0,
@@ -187,7 +191,9 @@ struct qedn_ctx {
};
enum qedn_task_flags {
+ QEDN_TASK_IS_ICREQ,
QEDN_TASK_USED_BY_FW,
+ QEDN_TASK_WAIT_FOR_CLEANUP,
};
struct qedn_task_ctx {
@@ -331,6 +337,8 @@ struct qedn_conn_ctx {
struct list_head active_task_list;
atomic_t num_active_tasks;
atomic_t num_active_fw_tasks;
+ atomic_t task_cleanups_cnt;
+ wait_queue_head_t cleanup_waitq;
/* Connection resources - turned on to indicate what resource was
* allocated, to that it can later be released.
diff --git a/drivers/nvme/hw/qedn/qedn_conn.c b/drivers/nvme/hw/qedn/qedn_conn.c
index ed60ac0306d5..46de8ba17df9 100644
--- a/drivers/nvme/hw/qedn/qedn_conn.c
+++ b/drivers/nvme/hw/qedn/qedn_conn.c
@@ -598,6 +598,11 @@ static int qedn_handle_icresp(struct qedn_conn_ctx *conn_ctx)
return rc;
}
+void qedn_error_recovery(struct nvme_ctrl *nctrl)
+{
+ nvme_tcp_ofld_error_recovery(nctrl);
+}
+
/* Slowpath EQ Callback */
int qedn_event_cb(void *context, u8 fw_event_code, void *event_ring_data)
{
@@ -657,6 +662,7 @@ int qedn_event_cb(void *context, u8 fw_event_code, void *event_ring_data)
}
break;
+
case NVMETCP_EVENT_TYPE_ASYN_TERMINATE_DONE:
if (conn_ctx->state != CONN_STATE_WAIT_FOR_DESTROY_DONE)
pr_err("CID=0x%x - ASYN_TERMINATE_DONE: Unexpected connection state %u\n",
@@ -665,6 +671,19 @@ int qedn_event_cb(void *context, u8 fw_event_code, void *event_ring_data)
queue_work(qctrl->sp_wq, &conn_ctx->sp_wq_entry);
break;
+
+ case NVMETCP_EVENT_TYPE_ASYN_CLOSE_RCVD:
+ case NVMETCP_EVENT_TYPE_ASYN_ABORT_RCVD:
+ case NVMETCP_EVENT_TYPE_ASYN_MAX_RT_TIME:
+ case NVMETCP_EVENT_TYPE_ASYN_MAX_RT_CNT:
+ case NVMETCP_EVENT_TYPE_ASYN_SYN_RCVD:
+ case NVMETCP_EVENT_TYPE_ASYN_MAX_KA_PROBES_CNT:
+ case NVMETCP_EVENT_TYPE_NVMETCP_CONN_ERROR:
+ case NVMETCP_EVENT_TYPE_TCP_CONN_ERROR:
+ qedn_error_recovery(&conn_ctx->ctrl->nctrl);
+
+ break;
+
default:
pr_err("CID=0x%x - Recv Unknown Event %u\n", conn_ctx->fw_cid, fw_event_code);
break;
@@ -798,6 +817,107 @@ static int qedn_prep_and_offload_queue(struct qedn_conn_ctx *conn_ctx)
return -EINVAL;
}
+static void qedn_cleanup_fw_task(struct qedn_ctx *qedn, struct qedn_task_ctx *qedn_task)
+{
+ struct qedn_conn_ctx *conn_ctx = qedn_task->qedn_conn;
+ struct nvmetcp_task_params task_params;
+ struct nvmetcp_wqe *chain_sqe;
+ struct nvmetcp_wqe local_sqe;
+ unsigned long lock_flags;
+
+ /* Take lock to prevent race with fastpath, we don't want to
+ * invoke cleanup flows on tasks that already returned.
+ */
+ spin_lock_irqsave(&qedn_task->lock, lock_flags);
+ if (!qedn_task->valid) {
+ spin_unlock_irqrestore(&qedn_task->lock, lock_flags);
+
+ return;
+ }
+ /* Skip tasks not used by FW */
+ if (!test_bit(QEDN_TASK_USED_BY_FW, &qedn_task->flags)) {
+ spin_unlock_irqrestore(&qedn_task->lock, lock_flags);
+
+ return;
+ }
+ /* Skip tasks that were already invoked for cleanup */
+ if (unlikely(test_bit(QEDN_TASK_WAIT_FOR_CLEANUP, &qedn_task->flags))) {
+ spin_unlock_irqrestore(&qedn_task->lock, lock_flags);
+
+ return;
+ }
+ set_bit(QEDN_TASK_WAIT_FOR_CLEANUP, &qedn_task->flags);
+ spin_unlock_irqrestore(&qedn_task->lock, lock_flags);
+
+ atomic_inc(&conn_ctx->task_cleanups_cnt);
+
+ task_params.sqe = &local_sqe;
+ task_params.itid = qedn_task->itid;
+ qed_ops->init_task_cleanup(&task_params);
+
+ /* spin_lock - doorbell is accessed both Rx flow and response flow */
+ spin_lock(&conn_ctx->ep.doorbell_lock);
+ chain_sqe = qed_chain_produce(&conn_ctx->ep.fw_sq_chain);
+ memcpy(chain_sqe, &local_sqe, sizeof(local_sqe));
+ qedn_ring_doorbell(conn_ctx);
+ spin_unlock(&conn_ctx->ep.doorbell_lock);
+}
+
+inline int qedn_drain(struct qedn_conn_ctx *conn_ctx)
+{
+ int drain_iter = QEDN_DRAIN_MAX_ATTEMPTS;
+ struct qedn_ctx *qedn = conn_ctx->qedn;
+ int wrc;
+
+ while (drain_iter) {
+ qed_ops->common->drain(qedn->cdev);
+ msleep(100);
+
+ wrc = wait_event_interruptible_timeout(conn_ctx->cleanup_waitq,
+ !atomic_read(&conn_ctx->task_cleanups_cnt),
+ msecs_to_jiffies(QEDN_DRAIN_TMO));
+ if (!wrc) {
+ drain_iter--;
+ continue;
+ }
+
+ return 0;
+ }
+
+ pr_err("CID 0x%x: cleanup after drain failed - need hard reset.\n", conn_ctx->fw_cid);
+
+ return -EINVAL;
+}
+
+void qedn_cleanup_all_fw_tasks(struct qedn_conn_ctx *conn_ctx)
+{
+ struct qedn_task_ctx *qedn_task, *task_tmp;
+ struct qedn_ctx *qedn = conn_ctx->qedn;
+ int wrc;
+
+ list_for_each_entry_safe_reverse(qedn_task, task_tmp, &conn_ctx->active_task_list, entry) {
+ qedn_cleanup_fw_task(qedn, qedn_task);
+ }
+
+ wrc = wait_event_interruptible_timeout(conn_ctx->cleanup_waitq,
+ atomic_read(&conn_ctx->task_cleanups_cnt) == 0,
+ msecs_to_jiffies(QEDN_TASK_CLEANUP_TMO));
+ if (!wrc) {
+ if (qedn_drain(conn_ctx))
+ return;
+ }
+}
+
+static void qedn_clear_fw_sq(struct qedn_conn_ctx *conn_ctx)
+{
+ struct qedn_ctx *qedn = conn_ctx->qedn;
+ int rc;
+
+ rc = qed_ops->clear_sq(qedn->cdev, conn_ctx->conn_handle);
+ if (rc)
+ pr_warn("clear_sq failed - rc %u\n", rc);
+}
+
void qedn_destroy_connection(struct qedn_conn_ctx *conn_ctx)
{
struct qedn_ctx *qedn = conn_ctx->qedn;
@@ -808,7 +928,13 @@ void qedn_destroy_connection(struct qedn_conn_ctx *conn_ctx)
if (qedn_set_con_state(conn_ctx, CONN_STATE_WAIT_FOR_DESTROY_DONE))
return;
- /* Placeholder - task cleanup */
+ if (atomic_read(&conn_ctx->num_active_fw_tasks)) {
+ conn_ctx->abrt_flag = QEDN_ABORTIVE_TERMINATION;
+ qedn_clear_fw_sq(conn_ctx);
+ qedn_cleanup_all_fw_tasks(conn_ctx);
+ } else {
+ conn_ctx->abrt_flag = QEDN_NON_ABORTIVE_TERMINATION;
+ }
rc = qed_ops->destroy_conn(qedn->cdev, conn_ctx->conn_handle,
conn_ctx->abrt_flag);
diff --git a/drivers/nvme/hw/qedn/qedn_main.c b/drivers/nvme/hw/qedn/qedn_main.c
index c2721a771822..2a1135fb4ae3 100644
--- a/drivers/nvme/hw/qedn/qedn_main.c
+++ b/drivers/nvme/hw/qedn/qedn_main.c
@@ -299,6 +299,7 @@ static int qedn_create_queue(struct nvme_tcp_ofld_queue *queue, int qid, size_t
qedn_set_pdu_params(conn_ctx);
init_waitqueue_head(&conn_ctx->conn_waitq);
+ init_waitqueue_head(&conn_ctx->cleanup_waitq);
atomic_set(&conn_ctx->est_conn_indicator, 0);
atomic_set(&conn_ctx->destroy_conn_indicator, 0);
diff --git a/drivers/nvme/hw/qedn/qedn_task.c b/drivers/nvme/hw/qedn/qedn_task.c
index 44e5ea2a693a..4fca9a4707cd 100644
--- a/drivers/nvme/hw/qedn/qedn_task.c
+++ b/drivers/nvme/hw/qedn/qedn_task.c
@@ -327,6 +327,17 @@ void qedn_return_active_tasks(struct qedn_conn_ctx *conn_ctx)
/* Return tasks that aren't "Used by FW" to the pool */
list_for_each_entry_safe(qedn_task, task_tmp,
&conn_ctx->active_task_list, entry) {
+ /* If we got this far, cleanup was already done
+ * in which case we want to return the task to the pool and
+ * release it. So we make sure the cleanup indication is down
+ */
+ clear_bit(QEDN_TASK_WAIT_FOR_CLEANUP, &qedn_task->flags);
+
+ /* Special handling in case of ICREQ task */
+ if (unlikely(conn_ctx->state == CONN_STATE_WAIT_FOR_IC_COMP &&
+ test_bit(QEDN_TASK_IS_ICREQ, &(qedn_task)->flags)))
+ qedn_common_clear_fw_sgl(&qedn_task->sgl_task_params);
+
qedn_clear_task(conn_ctx, qedn_task);
num_returned_tasks++;
}
@@ -700,7 +711,8 @@ void qedn_io_work_cq(struct qedn_ctx *qedn, struct nvmetcp_fw_cqe *cqe)
return;
if (likely(cqe->cqe_type == NVMETCP_FW_CQE_TYPE_NORMAL)) {
- /* Placeholder - verify the connection was established */
+ if (unlikely(test_bit(QEDN_TASK_WAIT_FOR_CLEANUP, &qedn_task->flags)))
+ return;
switch (cqe->task_type) {
case NVMETCP_TASK_TYPE_HOST_WRITE:
@@ -741,6 +753,17 @@ void qedn_io_work_cq(struct qedn_ctx *qedn, struct nvmetcp_fw_cqe *cqe)
pr_info("Could not identify task type\n");
}
} else {
- /* Placeholder - Recovery flows */
+ if (cqe->cqe_type == NVMETCP_FW_CQE_TYPE_CLEANUP) {
+ clear_bit(QEDN_TASK_WAIT_FOR_CLEANUP, &qedn_task->flags);
+ qedn_return_task_to_pool(conn_ctx, qedn_task);
+ atomic_dec(&conn_ctx->task_cleanups_cnt);
+ wake_up_interruptible(&conn_ctx->cleanup_waitq);
+
+ return;
+ }
+
+ /* The else is NVMETCP_FW_CQE_TYPE_DUMMY - in which don't return the task.
+ * The task will return during NVMETCP_FW_CQE_TYPE_CLEANUP.
+ */
}
}
--
2.22.0
_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme
next prev parent reply other threads:[~2021-05-19 12:42 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-05-19 11:13 [RFC PATCH v5 00/27] NVMeTCP Offload ULP and QEDN Device Driver Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 01/27] nvme-tcp-offload: Add nvme-tcp-offload - NVMeTCP HW offload ULP Shai Malin
2021-05-21 17:06 ` Himanshu Madhani
2021-05-24 20:11 ` Shai Malin
2021-05-21 22:13 ` Sagi Grimberg
2021-05-24 20:08 ` Shai Malin
2021-06-08 9:28 ` Petr Mladek
2021-05-19 11:13 ` [RFC PATCH v5 02/27] nvme-fabrics: Move NVMF_ALLOWED_OPTS and NVMF_REQUIRED_OPTS definitions Shai Malin
2021-05-21 17:08 ` Himanshu Madhani
2021-05-21 22:15 ` Sagi Grimberg
2021-05-19 11:13 ` [RFC PATCH v5 03/27] nvme-tcp-offload: Add device scan implementation Shai Malin
2021-05-21 17:22 ` Himanshu Madhani
2021-05-21 22:22 ` Sagi Grimberg
2021-05-24 20:14 ` Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 04/27] nvme-tcp-offload: Add controller level implementation Shai Malin
2021-05-21 17:19 ` Himanshu Madhani
2021-05-21 22:31 ` Sagi Grimberg
2021-05-27 20:03 ` Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 05/27] nvme-tcp-offload: Add controller level error recovery implementation Shai Malin
2021-05-21 17:42 ` Himanshu Madhani
2021-05-21 22:34 ` Sagi Grimberg
2021-05-19 11:13 ` [RFC PATCH v5 06/27] nvme-tcp-offload: Add queue level implementation Shai Malin
2021-05-21 18:18 ` Himanshu Madhani
2021-05-21 22:48 ` Sagi Grimberg
2021-05-24 20:16 ` Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 07/27] nvme-tcp-offload: Add IO " Shai Malin
2021-05-21 18:26 ` Himanshu Madhani
2021-05-19 11:13 ` [RFC PATCH v5 08/27] nvme-tcp-offload: Add Timeout and ASYNC Support Shai Malin
2021-05-21 18:36 ` Himanshu Madhani
2021-05-21 22:51 ` Sagi Grimberg
2021-05-24 20:17 ` Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 09/27] qed: Add TCP_ULP FW resource layout Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 10/27] qed: Add NVMeTCP Offload PF Level FW and HW HSI Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 11/27] qed: Add NVMeTCP Offload Connection " Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 12/27] qed: Add support of HW filter block Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 13/27] qed: Add NVMeTCP Offload IO Level FW and HW HSI Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 14/27] qed: Add NVMeTCP Offload IO Level FW Initializations Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 15/27] qed: Add IP services APIs support Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 16/27] qedn: Add qedn - Marvell's NVMeTCP HW offload vendor driver Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 17/27] qedn: Add qedn probe Shai Malin
2021-05-19 12:31 ` Leon Romanovsky
2021-05-19 14:29 ` Shai Malin
2021-05-19 15:31 ` Leon Romanovsky
2021-05-19 11:13 ` [RFC PATCH v5 18/27] qedn: Add qedn_claim_dev API support Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 19/27] qedn: Add IRQ and fast-path resources initializations Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 20/27] qedn: Add connection-level slowpath functionality Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 21/27] qedn: Add support of configuring HW filter block Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 22/27] qedn: Add IO level qedn_send_req and fw_cq workqueue Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 23/27] qedn: Add support of Task and SGL Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 24/27] qedn: Add support of NVME ICReq & ICResp Shai Malin
2021-05-19 11:13 ` [RFC PATCH v5 25/27] qedn: Add IO level fastpath functionality Shai Malin
2021-05-19 11:13 ` Shai Malin [this message]
2021-05-19 11:13 ` [RFC PATCH v5 27/27] qedn: Add support of ASYNC Shai Malin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210519111340.20613-27-smalin@marvell.com \
--to=smalin@marvell.com \
--cc=aelior@marvell.com \
--cc=axboe@fb.com \
--cc=davem@davemloft.net \
--cc=hch@lst.de \
--cc=kbusch@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-nvme@lists.infradead.org \
--cc=malin1024@gmail.com \
--cc=mkalderon@marvell.com \
--cc=netdev@vger.kernel.org \
--cc=okulkarni@marvell.com \
--cc=pkushwaha@marvell.com \
--cc=sagi@grimberg.me \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox