From b81976658cb8df4ecc4bae70b073eb7a3f18b60f Mon Sep 17 00:00:00 2001 From: brookxu Date: Sun, 29 Sep 2019 14:39:53 +0800 Subject: [PATCH] nvme: add nvme io error/timeout log Add io error and timeout log to nvme devices Signed-off-by: brookxu --- drivers/nvme/host/core.c | 6 ++++ drivers/nvme/host/nvme.h | 1 + drivers/nvme/host/pci.c | 66 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 65f3f1a34..3c30a249f 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -308,6 +308,7 @@ struct request *nvme_alloc_request(struct request_queue *q, req->cmd_flags |= REQ_FAILFAST_DRIVER; nvme_req(req)->cmd = cmd; + nvme_req(req)->opcode = cmd->common.opcode; return req; } @@ -650,6 +651,11 @@ static int nvme_submit_user_cmd(struct request_queue *q, return PTR_ERR(req); req->timeout = timeout ? timeout : ADMIN_TIMEOUT; + if (cmd->common.opcode == nvme_cmd_read || + cmd->common.opcode == nvme_cmd_write) { + req->__sector = meta_seed; + req->__data_len = bufflen; + } if (ubuffer && bufflen) { ret = blk_rq_map_user(q, req, NULL, ubuffer, bufflen, diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 7ef0a8e1c..a1e071c85 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -97,6 +97,7 @@ struct nvme_request { u8 retries; u8 flags; u16 status; + u8 opcode; }; enum { diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 06355ca83..c9d4322f7 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -732,6 +732,7 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx, struct nvme_dev *dev = nvmeq->dev; struct request *req = bd->rq; struct nvme_command cmnd; + struct nvme_request *rq; blk_status_t ret; ret = nvme_setup_cmd(ns, req, &cmnd); @@ -742,6 +743,9 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx, if (ret) goto out_free_cmd; + rq = blk_mq_rq_to_pdu(req); + rq->opcode = cmnd.common.opcode; + if (blk_rq_nr_phys_segments(req)) { ret = nvme_map_data(dev, req, &cmnd); if (ret) @@ -793,6 +797,64 @@ static inline void nvme_ring_cq_doorbell(struct nvme_queue *nvmeq) } } +static inline void nvme_eh_io_timeout(struct request *req) +{ + struct nvme_iod *iod = blk_mq_rq_to_pdu(req); + struct nvme_ctrl *ctrl = &iod->nvmeq->dev->ctrl; + struct nvme_request *rq = nvme_req(req); + + /* admin command error */ + if (req->q == ctrl->admin_q || req->q == ctrl->connect_q) { + dev_warn_ratelimited(ctrl->device, + "Admin command timeout, CMD: %d(+%d)", + rq->opcode, rq->retries); + return; + } + + /* io command timeout */ + if (rq->opcode == nvme_cmd_write || rq->opcode == nvme_cmd_read) + dev_warn_ratelimited(ctrl->device, + "I/O timeout, QID: %d, CMD: %d(+%d), Sector: %llu+%u", + iod->nvmeq->qid, rq->opcode, rq->retries, + (unsigned long long)blk_rq_pos(req), + blk_rq_sectors(req)); + else + dev_warn_ratelimited(ctrl->device, + "I/O timeout, QID: %d, CMD: %d(+%d)", + iod->nvmeq->qid, rq->opcode, rq->retries); +} + +static inline void nvme_eh_io_error(struct request *req, __le16 status) +{ + struct nvme_iod *iod = blk_mq_rq_to_pdu(req); + struct nvme_ctrl *ctrl = &iod->nvmeq->dev->ctrl; + struct nvme_request *rq = nvme_req(req); + + if (status == NVME_SC_SUCCESS || rq->opcode == nvme_admin_abort_cmd) + return; + + /* admin command error */ + if (req->q == ctrl->admin_q || req->q == ctrl->connect_q) { + dev_warn_ratelimited(ctrl->device, + "Admin command error, CMD: %d(+%d), Status: 0x%x", + rq->opcode, rq->retries, status); + return; + } + + /* io command error */ + if (rq->opcode == nvme_cmd_write || rq->opcode == nvme_cmd_read) + dev_warn_ratelimited(ctrl->device, + "I/O error, QID: %d, CMD: %d(+%d), Sector: %llu+%u, Status: 0x%x", + iod->nvmeq->qid, rq->opcode, rq->retries, + (unsigned long long)blk_rq_pos(req), + blk_rq_sectors(req), status); + else + dev_warn_ratelimited(ctrl->device, + "I/O error, QID: %d, CMD: %d(+%d), Status: 0x%x", + iod->nvmeq->qid, rq->opcode, rq->retries, + status); +} + static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, struct nvme_completion *cqe) { @@ -820,6 +882,7 @@ static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, nvmeq->cqe_seen = 1; req = blk_mq_tag_to_rq(*nvmeq->tags, cqe->command_id); + nvme_eh_io_error(req, le16_to_cpu(cqe->status) >> 1); nvme_end_request(req, cqe->status, cqe->result); } @@ -1051,6 +1114,9 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved) struct nvme_command cmd; u32 csts = readl(dev->bar + NVME_REG_CSTS); + /* log error memset */ + nvme_eh_io_timeout(req); + /* If PCI error recovery process is happening, we cannot reset or * the recovery mechanism will surely fail. */