diff options
-rw-r--r-- | drivers/block/nvme-core.c | 68 | ||||
-rw-r--r-- | include/linux/nvme.h | 1 | ||||
-rw-r--r-- | include/uapi/linux/nvme.h | 11 |
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 | ||
119 | static struct nvme_cmd_info *nvme_cmd_info(struct nvme_queue *nvmeq) | 122 | static 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 | ||
179 | static void special_completion(struct nvme_dev *dev, void *ctx, | 184 | static 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 | */ | ||
1024 | static 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 | ||
353 | struct 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 | |||
353 | struct nvme_download_firmware { | 363 | struct 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 | ||