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 | |||
