#include <crypto/kpp.h>
 #include "nvmet.h"
 
+static void nvmet_auth_expired_work(struct work_struct *work)
+{
+       struct nvmet_sq *sq = container_of(to_delayed_work(work),
+                       struct nvmet_sq, auth_expired_work);
+
+       pr_debug("%s: ctrl %d qid %d transaction %u expired, resetting\n",
+                __func__, sq->ctrl->cntlid, sq->qid, sq->dhchap_tid);
+       sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE;
+       sq->dhchap_tid = -1;
+}
+
 void nvmet_init_auth(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
 {
        u32 result = le32_to_cpu(req->cqe->result.u32);
 
        /* Initialize in-band authentication */
+       INIT_DELAYED_WORK(&req->sq->auth_expired_work,
+                         nvmet_auth_expired_work);
        req->sq->authenticated = false;
        req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE;
        result |= (u32)NVME_CONNECT_AUTHREQ_ATR << 16;
        req->cqe->result.u64 = 0;
        nvmet_req_complete(req, status);
        if (req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2 &&
-           req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_FAILURE2)
+           req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) {
+               unsigned long auth_expire_secs = ctrl->kato ? ctrl->kato : 120;
+
+               mod_delayed_work(system_wq, &req->sq->auth_expired_work,
+                                auth_expire_secs * HZ);
                return;
+       }
        /* Final states, clear up variables */
        nvmet_auth_sq_free(req->sq);
        if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2)