aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/nvme.c
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew.r.wilcox@intel.com>2011-02-06 08:49:55 -0500
committerMatthew Wilcox <matthew.r.wilcox@intel.com>2011-11-04 15:52:55 -0400
commitb36235df01ec4141b4e589571d6789076c346d88 (patch)
tree0fc4ba6cd2cbb4f563f398a48153dbbdf69483c6 /drivers/block/nvme.c
parentbe7b62754e097adc0cb16c25c9ee86ee20de62fb (diff)
NVMe: Detect commands that are completed twice
Set the context value to CMD_CTX_COMPLETED, and print a message in the sync_completion handler if we see it. Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Diffstat (limited to 'drivers/block/nvme.c')
-rw-r--r--drivers/block/nvme.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 802d763d9d06..2dd09e7e142d 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -169,12 +169,15 @@ enum {
169 169
170#define CMD_CTX_BASE (POISON_POINTER_DELTA + sync_completion_id) 170#define CMD_CTX_BASE (POISON_POINTER_DELTA + sync_completion_id)
171#define CMD_CTX_CANCELLED (0x2008 + CMD_CTX_BASE) 171#define CMD_CTX_CANCELLED (0x2008 + CMD_CTX_BASE)
172#define CMD_CTX_COMPLETED (0x2010 + CMD_CTX_BASE)
172 173
173static unsigned long free_cmdid(struct nvme_queue *nvmeq, int cmdid) 174static unsigned long free_cmdid(struct nvme_queue *nvmeq, int cmdid)
174{ 175{
175 unsigned long data; 176 unsigned long data;
177 unsigned offset = cmdid + BITS_TO_LONGS(nvmeq->q_depth);
176 178
177 data = nvmeq->cmdid_data[cmdid + BITS_TO_LONGS(nvmeq->q_depth)]; 179 data = nvmeq->cmdid_data[offset];
180 nvmeq->cmdid_data[offset] = CMD_CTX_COMPLETED;
178 clear_bit(cmdid, nvmeq->cmdid_data); 181 clear_bit(cmdid, nvmeq->cmdid_data);
179 wake_up(&nvmeq->sq_full); 182 wake_up(&nvmeq->sq_full);
180 return data; 183 return data;
@@ -182,8 +185,8 @@ static unsigned long free_cmdid(struct nvme_queue *nvmeq, int cmdid)
182 185
183static void cancel_cmdid_data(struct nvme_queue *nvmeq, int cmdid) 186static void cancel_cmdid_data(struct nvme_queue *nvmeq, int cmdid)
184{ 187{
185 nvmeq->cmdid_data[cmdid + BITS_TO_LONGS(nvmeq->q_depth)] = 188 unsigned offset = cmdid + BITS_TO_LONGS(nvmeq->q_depth);
186 CMD_CTX_CANCELLED; 189 nvmeq->cmdid_data[offset] = CMD_CTX_CANCELLED;
187} 190}
188 191
189static struct nvme_queue *get_nvmeq(struct nvme_ns *ns) 192static struct nvme_queue *get_nvmeq(struct nvme_ns *ns)
@@ -402,6 +405,12 @@ static void sync_completion(struct nvme_queue *nvmeq, void *ctx,
402 struct sync_cmd_info *cmdinfo = ctx; 405 struct sync_cmd_info *cmdinfo = ctx;
403 if ((unsigned long)cmdinfo == CMD_CTX_CANCELLED) 406 if ((unsigned long)cmdinfo == CMD_CTX_CANCELLED)
404 return; 407 return;
408 if (unlikely((unsigned long)cmdinfo == CMD_CTX_COMPLETED)) {
409 dev_warn(nvmeq->q_dmadev,
410 "completed id %d twice on queue %d\n",
411 cqe->command_id, le16_to_cpup(&cqe->sq_id));
412 return;
413 }
405 cmdinfo->result = le32_to_cpup(&cqe->result); 414 cmdinfo->result = le32_to_cpup(&cqe->result);
406 cmdinfo->status = le16_to_cpup(&cqe->status) >> 1; 415 cmdinfo->status = le16_to_cpup(&cqe->status) >> 1;
407 wake_up_process(cmdinfo->task); 416 wake_up_process(cmdinfo->task);