Commit a9aa1908 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.dk/linux-block

Pull block layer fixes from Jens Axboe:
 "A couple of last minute fixes for regressions in this cycle. More
  specifically:

   - Two patches from Andy, adjusting the NVMe APST quirks to avoid some
     issues specific to one Toshiba drive, and some variant of Samsung
     on two specific Dell laptops.

   - A fix for mtip32xx, turning off mq scheduling on that device. We
     have a real fix for this, but it's too late in the cycle.
     Thankfully we already have a NO_SCHED flag we can apply here. A
     prep patch for this is ensuring that we honor the NO_SCHED flag
     when attempting to online switch schedulers, previsouly we only did
     so for drive load time. From Ming.

   - Fixing an oops in blk-mq polling with scheduling attached. This one
     is easily reproducible, it would be a shame to release 4.11 with
     that issue. From me.

  I'd prefer not having to send in patches at this point in time, but
  the above are all things that have regressed in this cycle and the
  fixes are relatively straight forward"

* 'for-linus' of git://git.kernel.dk/linux-block:
  blk-mq: fix potential oops with polling and blk-mq scheduler
  nvme: Quirk APST off on "THNSF5256GPUK TOSHIBA"
  nvme: Adjust the Samsung APST quirk
  mtip32xx: pass BLK_MQ_F_NO_SCHED
  block: respect BLK_MQ_F_NO_SCHED
parents 4664e322 3a07bb1d
...@@ -2928,8 +2928,17 @@ bool blk_mq_poll(struct request_queue *q, blk_qc_t cookie) ...@@ -2928,8 +2928,17 @@ bool blk_mq_poll(struct request_queue *q, blk_qc_t cookie)
hctx = q->queue_hw_ctx[blk_qc_t_to_queue_num(cookie)]; hctx = q->queue_hw_ctx[blk_qc_t_to_queue_num(cookie)];
if (!blk_qc_t_is_internal(cookie)) if (!blk_qc_t_is_internal(cookie))
rq = blk_mq_tag_to_rq(hctx->tags, blk_qc_t_to_tag(cookie)); rq = blk_mq_tag_to_rq(hctx->tags, blk_qc_t_to_tag(cookie));
else else {
rq = blk_mq_tag_to_rq(hctx->sched_tags, blk_qc_t_to_tag(cookie)); rq = blk_mq_tag_to_rq(hctx->sched_tags, blk_qc_t_to_tag(cookie));
/*
* With scheduling, if the request has completed, we'll
* get a NULL return here, as we clear the sched tag when
* that happens. The request still remains valid, like always,
* so we should be safe with just the NULL check.
*/
if (!rq)
return false;
}
return __blk_mq_poll(hctx, rq); return __blk_mq_poll(hctx, rq);
} }
......
...@@ -1098,12 +1098,20 @@ int elevator_change(struct request_queue *q, const char *name) ...@@ -1098,12 +1098,20 @@ int elevator_change(struct request_queue *q, const char *name)
} }
EXPORT_SYMBOL(elevator_change); EXPORT_SYMBOL(elevator_change);
static inline bool elv_support_iosched(struct request_queue *q)
{
if (q->mq_ops && q->tag_set && (q->tag_set->flags &
BLK_MQ_F_NO_SCHED))
return false;
return true;
}
ssize_t elv_iosched_store(struct request_queue *q, const char *name, ssize_t elv_iosched_store(struct request_queue *q, const char *name,
size_t count) size_t count)
{ {
int ret; int ret;
if (!(q->mq_ops || q->request_fn)) if (!(q->mq_ops || q->request_fn) || !elv_support_iosched(q))
return count; return count;
ret = __elevator_change(q, name); ret = __elevator_change(q, name);
...@@ -1135,7 +1143,7 @@ ssize_t elv_iosched_show(struct request_queue *q, char *name) ...@@ -1135,7 +1143,7 @@ ssize_t elv_iosched_show(struct request_queue *q, char *name)
len += sprintf(name+len, "[%s] ", elv->elevator_name); len += sprintf(name+len, "[%s] ", elv->elevator_name);
continue; continue;
} }
if (__e->uses_mq && q->mq_ops) if (__e->uses_mq && q->mq_ops && elv_support_iosched(q))
len += sprintf(name+len, "%s ", __e->elevator_name); len += sprintf(name+len, "%s ", __e->elevator_name);
else if (!__e->uses_mq && !q->mq_ops) else if (!__e->uses_mq && !q->mq_ops)
len += sprintf(name+len, "%s ", __e->elevator_name); len += sprintf(name+len, "%s ", __e->elevator_name);
......
...@@ -3969,7 +3969,7 @@ static int mtip_block_initialize(struct driver_data *dd) ...@@ -3969,7 +3969,7 @@ static int mtip_block_initialize(struct driver_data *dd)
dd->tags.reserved_tags = 1; dd->tags.reserved_tags = 1;
dd->tags.cmd_size = sizeof(struct mtip_cmd); dd->tags.cmd_size = sizeof(struct mtip_cmd);
dd->tags.numa_node = dd->numa_node; dd->tags.numa_node = dd->numa_node;
dd->tags.flags = BLK_MQ_F_SHOULD_MERGE; dd->tags.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_NO_SCHED;
dd->tags.driver_data = dd; dd->tags.driver_data = dd;
dd->tags.timeout = MTIP_NCQ_CMD_TIMEOUT_MS; dd->tags.timeout = MTIP_NCQ_CMD_TIMEOUT_MS;
......
...@@ -1315,6 +1315,14 @@ static void nvme_configure_apst(struct nvme_ctrl *ctrl) ...@@ -1315,6 +1315,14 @@ static void nvme_configure_apst(struct nvme_ctrl *ctrl)
if (target) if (target)
table->entries[state] = target; table->entries[state] = target;
/*
* Don't allow transitions to the deepest state
* if it's quirked off.
*/
if (state == ctrl->npss &&
(ctrl->quirks & NVME_QUIRK_NO_DEEPEST_PS))
continue;
/* /*
* Is this state a useful non-operational state for * Is this state a useful non-operational state for
* higher-power states to autonomously transition to? * higher-power states to autonomously transition to?
...@@ -1387,16 +1395,15 @@ struct nvme_core_quirk_entry { ...@@ -1387,16 +1395,15 @@ struct nvme_core_quirk_entry {
}; };
static const struct nvme_core_quirk_entry core_quirks[] = { static const struct nvme_core_quirk_entry core_quirks[] = {
/*
* Seen on a Samsung "SM951 NVMe SAMSUNG 256GB": using APST causes
* the controller to go out to lunch. It dies when the watchdog
* timer reads CSTS and gets 0xffffffff.
*/
{ {
.vid = 0x144d, /*
.fr = "BXW75D0Q", * This Toshiba device seems to die using any APST states. See:
* https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1678184/comments/11
*/
.vid = 0x1179,
.mn = "THNSF5256GPUK TOSHIBA",
.quirks = NVME_QUIRK_NO_APST, .quirks = NVME_QUIRK_NO_APST,
}, }
}; };
/* match is null-terminated but idstr is space-padded. */ /* match is null-terminated but idstr is space-padded. */
......
...@@ -83,6 +83,11 @@ enum nvme_quirks { ...@@ -83,6 +83,11 @@ enum nvme_quirks {
* APST should not be used. * APST should not be used.
*/ */
NVME_QUIRK_NO_APST = (1 << 4), NVME_QUIRK_NO_APST = (1 << 4),
/*
* The deepest sleep state should not be used.
*/
NVME_QUIRK_NO_DEEPEST_PS = (1 << 5),
}; };
/* /*
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/blk-mq-pci.h> #include <linux/blk-mq-pci.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/genhd.h> #include <linux/genhd.h>
...@@ -1943,10 +1944,31 @@ static int nvme_dev_map(struct nvme_dev *dev) ...@@ -1943,10 +1944,31 @@ static int nvme_dev_map(struct nvme_dev *dev)
return -ENODEV; return -ENODEV;
} }
static unsigned long check_dell_samsung_bug(struct pci_dev *pdev)
{
if (pdev->vendor == 0x144d && pdev->device == 0xa802) {
/*
* Several Samsung devices seem to drop off the PCIe bus
* randomly when APST is on and uses the deepest sleep state.
* This has been observed on a Samsung "SM951 NVMe SAMSUNG
* 256GB", a "PM951 NVMe SAMSUNG 512GB", and a "Samsung SSD
* 950 PRO 256GB", but it seems to be restricted to two Dell
* laptops.
*/
if (dmi_match(DMI_SYS_VENDOR, "Dell Inc.") &&
(dmi_match(DMI_PRODUCT_NAME, "XPS 15 9550") ||
dmi_match(DMI_PRODUCT_NAME, "Precision 5510")))
return NVME_QUIRK_NO_DEEPEST_PS;
}
return 0;
}
static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{ {
int node, result = -ENOMEM; int node, result = -ENOMEM;
struct nvme_dev *dev; struct nvme_dev *dev;
unsigned long quirks = id->driver_data;
node = dev_to_node(&pdev->dev); node = dev_to_node(&pdev->dev);
if (node == NUMA_NO_NODE) if (node == NUMA_NO_NODE)
...@@ -1978,8 +2000,10 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -1978,8 +2000,10 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (result) if (result)
goto put_pci; goto put_pci;
quirks |= check_dell_samsung_bug(pdev);
result = nvme_init_ctrl(&dev->ctrl, &pdev->dev, &nvme_pci_ctrl_ops, result = nvme_init_ctrl(&dev->ctrl, &pdev->dev, &nvme_pci_ctrl_ops,
id->driver_data); quirks);
if (result) if (result)
goto release_pools; goto release_pools;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment