aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeith Busch <keith.busch@intel.com>2013-12-10 15:10:38 -0500
committerMatthew Wilcox <matthew.r.wilcox@intel.com>2014-01-27 19:27:53 -0500
commitc30341dc3c436cf43508cd44cdfbb3810c38c195 (patch)
tree36759f0401b539717d738d1c4548b2a2b18172e1
parentd4b4ff8e28b474fac0fbfa9cfc40f88b9e41e380 (diff)
NVMe: Abort timed out commands
Send nvme abort command to io requests that have timed out on an initialized device. If the command is not returned after another timeout, schedule the controller for reset. Signed-off-by: Keith Busch <keith.busch@intel.com> [fix endianness issues] Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
-rw-r--r--drivers/block/nvme-core.c68
-rw-r--r--include/linux/nvme.h1
-rw-r--r--include/uapi/linux/nvme.h11
3 files changed, 79 insertions, 1 deletions
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index 2f5b9f5f5a21..75049532df96 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -83,6 +83,7 @@ struct nvme_queue {
83 u16 sq_head; 83 u16 sq_head;
84 u16 sq_tail; 84 u16 sq_tail;
85 u16 cq_head; 85 u16 cq_head;
86 u16 qid;
86 u8 cq_phase; 87 u8 cq_phase;
87 u8 cqe_seen; 88 u8 cqe_seen;
88 u8 q_suspended; 89 u8 q_suspended;
@@ -100,6 +101,7 @@ static inline void _nvme_check_size(void)
100 BUILD_BUG_ON(sizeof(struct nvme_delete_queue) != 64); 101 BUILD_BUG_ON(sizeof(struct nvme_delete_queue) != 64);
101 BUILD_BUG_ON(sizeof(struct nvme_features) != 64); 102 BUILD_BUG_ON(sizeof(struct nvme_features) != 64);
102 BUILD_BUG_ON(sizeof(struct nvme_format_cmd) != 64); 103 BUILD_BUG_ON(sizeof(struct nvme_format_cmd) != 64);
104 BUILD_BUG_ON(sizeof(struct nvme_abort_cmd) != 64);
103 BUILD_BUG_ON(sizeof(struct nvme_command) != 64); 105 BUILD_BUG_ON(sizeof(struct nvme_command) != 64);
104 BUILD_BUG_ON(sizeof(struct nvme_id_ctrl) != 4096); 106 BUILD_BUG_ON(sizeof(struct nvme_id_ctrl) != 4096);
105 BUILD_BUG_ON(sizeof(struct nvme_id_ns) != 4096); 107 BUILD_BUG_ON(sizeof(struct nvme_id_ns) != 4096);
@@ -114,6 +116,7 @@ struct nvme_cmd_info {
114 nvme_completion_fn fn; 116 nvme_completion_fn fn;
115 void *ctx; 117 void *ctx;
116 unsigned long timeout; 118 unsigned long timeout;
119 int aborted;
117}; 120};
118 121
119static struct nvme_cmd_info *nvme_cmd_info(struct nvme_queue *nvmeq) 122static struct nvme_cmd_info *nvme_cmd_info(struct nvme_queue *nvmeq)
@@ -157,6 +160,7 @@ static int alloc_cmdid(struct nvme_queue *nvmeq, void *ctx,
157 info[cmdid].fn = handler; 160 info[cmdid].fn = handler;
158 info[cmdid].ctx = ctx; 161 info[cmdid].ctx = ctx;
159 info[cmdid].timeout = jiffies + timeout; 162 info[cmdid].timeout = jiffies + timeout;
163 info[cmdid].aborted = 0;
160 return cmdid; 164 return cmdid;
161} 165}
162 166
@@ -175,6 +179,7 @@ static int alloc_cmdid_killable(struct nvme_queue *nvmeq, void *ctx,
175#define CMD_CTX_COMPLETED (0x310 + CMD_CTX_BASE) 179#define CMD_CTX_COMPLETED (0x310 + CMD_CTX_BASE)
176#define CMD_CTX_INVALID (0x314 + CMD_CTX_BASE) 180#define CMD_CTX_INVALID (0x314 + CMD_CTX_BASE)
177#define CMD_CTX_FLUSH (0x318 + CMD_CTX_BASE) 181#define CMD_CTX_FLUSH (0x318 + CMD_CTX_BASE)
182#define CMD_CTX_ABORT (0x31C + CMD_CTX_BASE)
178 183
179static void special_completion(struct nvme_dev *dev, void *ctx, 184static void special_completion(struct nvme_dev *dev, void *ctx,
180 struct nvme_completion *cqe) 185 struct nvme_completion *cqe)
@@ -183,6 +188,10 @@ static void special_completion(struct nvme_dev *dev, void *ctx,
183 return; 188 return;
184 if (ctx == CMD_CTX_FLUSH) 189 if (ctx == CMD_CTX_FLUSH)
185 return; 190 return;
191 if (ctx == CMD_CTX_ABORT) {
192 ++dev->abort_limit;
193 return;
194 }
186 if (ctx == CMD_CTX_COMPLETED) { 195 if (ctx == CMD_CTX_COMPLETED) {
187 dev_warn(&dev->pci_dev->dev, 196 dev_warn(&dev->pci_dev->dev,
188 "completed id %d twice on queue %d\n", 197 "completed id %d twice on queue %d\n",
@@ -1005,6 +1014,56 @@ int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,
1005} 1014}
1006 1015
1007/** 1016/**
1017 * nvme_abort_cmd - Attempt aborting a command
1018 * @cmdid: Command id of a timed out IO
1019 * @queue: The queue with timed out IO
1020 *
1021 * Schedule controller reset if the command was already aborted once before and
1022 * still hasn't been returned to the driver, or if this is the admin queue.
1023 */
1024static void nvme_abort_cmd(int cmdid, struct nvme_queue *nvmeq)
1025{
1026 int a_cmdid;
1027 struct nvme_command cmd;
1028 struct nvme_dev *dev = nvmeq->dev;
1029 struct nvme_cmd_info *info = nvme_cmd_info(nvmeq);
1030
1031 if (!nvmeq->qid || info[cmdid].aborted) {
1032 if (work_busy(&dev->reset_work))
1033 return;
1034 list_del_init(&dev->node);
1035 dev_warn(&dev->pci_dev->dev,
1036 "I/O %d QID %d timeout, reset controller\n", cmdid,
1037 nvmeq->qid);
1038 INIT_WORK(&dev->reset_work, nvme_reset_failed_dev);
1039 queue_work(nvme_workq, &dev->reset_work);
1040 return;
1041 }
1042
1043 if (!dev->abort_limit)
1044 return;
1045
1046 a_cmdid = alloc_cmdid(dev->queues[0], CMD_CTX_ABORT, special_completion,
1047 ADMIN_TIMEOUT);
1048 if (a_cmdid < 0)
1049 return;
1050
1051 memset(&cmd, 0, sizeof(cmd));
1052 cmd.abort.opcode = nvme_admin_abort_cmd;
1053 cmd.abort.cid = cmdid;
1054 cmd.abort.sqid = cpu_to_le16(nvmeq->qid);
1055 cmd.abort.command_id = a_cmdid;
1056
1057 --dev->abort_limit;
1058 info[cmdid].aborted = 1;
1059 info[cmdid].timeout = jiffies + ADMIN_TIMEOUT;
1060
1061 dev_warn(nvmeq->q_dmadev, "Aborting I/O %d QID %d\n", cmdid,
1062 nvmeq->qid);
1063 nvme_submit_cmd(dev->queues[0], &cmd);
1064}
1065
1066/**
1008 * nvme_cancel_ios - Cancel outstanding I/Os 1067 * nvme_cancel_ios - Cancel outstanding I/Os
1009 * @queue: The queue to cancel I/Os on 1068 * @queue: The queue to cancel I/Os on
1010 * @timeout: True to only cancel I/Os which have timed out 1069 * @timeout: True to only cancel I/Os which have timed out
@@ -1027,7 +1086,12 @@ static void nvme_cancel_ios(struct nvme_queue *nvmeq, bool timeout)
1027 continue; 1086 continue;
1028 if (info[cmdid].ctx == CMD_CTX_CANCELLED) 1087 if (info[cmdid].ctx == CMD_CTX_CANCELLED)
1029 continue; 1088 continue;
1030 dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d\n", cmdid); 1089 if (timeout && nvmeq->dev->initialized) {
1090 nvme_abort_cmd(cmdid, nvmeq);
1091 continue;
1092 }
1093 dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d QID %d\n", cmdid,
1094 nvmeq->qid);
1031 ctx = cancel_cmdid(nvmeq, cmdid, &fn); 1095 ctx = cancel_cmdid(nvmeq, cmdid, &fn);
1032 fn(nvmeq->dev, ctx, &cqe); 1096 fn(nvmeq->dev, ctx, &cqe);
1033 } 1097 }
@@ -1119,6 +1183,7 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
1119 nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride]; 1183 nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride];
1120 nvmeq->q_depth = depth; 1184 nvmeq->q_depth = depth;
1121 nvmeq->cq_vector = vector; 1185 nvmeq->cq_vector = vector;
1186 nvmeq->qid = qid;
1122 nvmeq->q_suspended = 1; 1187 nvmeq->q_suspended = 1;
1123 dev->queue_count++; 1188 dev->queue_count++;
1124 1189
@@ -1929,6 +1994,7 @@ static int nvme_dev_add(struct nvme_dev *dev)
1929 ctrl = mem; 1994 ctrl = mem;
1930 nn = le32_to_cpup(&ctrl->nn); 1995 nn = le32_to_cpup(&ctrl->nn);
1931 dev->oncs = le16_to_cpup(&ctrl->oncs); 1996 dev->oncs = le16_to_cpup(&ctrl->oncs);
1997 dev->abort_limit = ctrl->acl + 1;
1932 memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn)); 1998 memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn));
1933 memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn)); 1999 memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn));
1934 memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr)); 2000 memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr));
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 117d877e8be5..69ae03f6eb15 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -95,6 +95,7 @@ struct nvme_dev {
95 u32 max_hw_sectors; 95 u32 max_hw_sectors;
96 u32 stripe_size; 96 u32 stripe_size;
97 u16 oncs; 97 u16 oncs;
98 u16 abort_limit;
98 u8 initialized; 99 u8 initialized;
99}; 100};
100 101
diff --git a/include/uapi/linux/nvme.h b/include/uapi/linux/nvme.h
index 989c04e0c563..e5ab62201119 100644
--- a/include/uapi/linux/nvme.h
+++ b/include/uapi/linux/nvme.h
@@ -350,6 +350,16 @@ struct nvme_delete_queue {
350 __u32 rsvd11[5]; 350 __u32 rsvd11[5];
351}; 351};
352 352
353struct nvme_abort_cmd {
354 __u8 opcode;
355 __u8 flags;
356 __u16 command_id;
357 __u32 rsvd1[9];
358 __le16 sqid;
359 __u16 cid;
360 __u32 rsvd11[5];
361};
362
353struct nvme_download_firmware { 363struct nvme_download_firmware {
354 __u8 opcode; 364 __u8 opcode;
355 __u8 flags; 365 __u8 flags;
@@ -384,6 +394,7 @@ struct nvme_command {
384 struct nvme_download_firmware dlfw; 394 struct nvme_download_firmware dlfw;
385 struct nvme_format_cmd format; 395 struct nvme_format_cmd format;
386 struct nvme_dsm_cmd dsm; 396 struct nvme_dsm_cmd dsm;
397 struct nvme_abort_cmd abort;
387 }; 398 };
388}; 399};
389 400