Put a workaround in for command timeout malfunctioning

At least one NVMe drive has a bug that makeing the Command Time Out
PCIe feature unreliable. The workaround is to disable this
feature. The driver wouldn't deal correctly with a timeout anyway.
Only do this for drives that are known bad.

Sponsored by: Netflix, Inc
Differential Revision: https://reviews.freebsd.org/D17708
This commit is contained in:
Warner Losh 2018-10-26 14:27:37 +00:00
parent b7b391934d
commit 09efa3dfb2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=339775
2 changed files with 22 additions and 1 deletions

View File

@ -106,6 +106,7 @@ static struct _pcsid
{ 0x05401c5f, 0, 0, "Memblaze Pblaze4", QUIRK_DELAY_B4_CHK_RDY },
{ 0xa821144d, 0, 0, "Samsung PM1725", QUIRK_DELAY_B4_CHK_RDY },
{ 0xa822144d, 0, 0, "Samsung PM1725a", QUIRK_DELAY_B4_CHK_RDY },
{ 0x01161179, 0, 0, "Toshiba XG5", QUIRK_DISABLE_TIMEOUT },
{ 0x00000000, 0, 0, NULL }
};
@ -278,6 +279,25 @@ nvme_attach(device_t dev)
return (status);
}
/*
* Some drives do not implement the completion timeout feature
* correctly. There's a WAR from the manufacturer to just disable it.
* The driver wouldn't respond correctly to a timeout anyway.
*/
if (ep->quirks & QUIRK_DISABLE_TIMEOUT) {
int ptr;
uint16_t devctl2;
status = pci_find_cap(dev, PCIY_EXPRESS, &ptr);
if (status) {
device_printf(dev, "Can't locate PCIe capability?");
return (status);
}
devctl2 = pci_read_config(dev, ptr + PCIER_DEVICE_CTL2, sizeof(devctl2));
devctl2 |= PCIEM_CTL2_COMP_TIMO_DISABLE;
pci_write_config(dev, ptr + PCIER_DEVICE_CTL2, devctl2, sizeof(devctl2));
}
/*
* Enable busmastering so the completion status messages can
* be busmastered back to the host.

View File

@ -247,7 +247,8 @@ struct nvme_controller {
uint32_t ready_timeout_in_ms;
uint32_t quirks;
#define QUIRK_DELAY_B4_CHK_RDY 1 /* Can't touch MMIO on disable */
#define QUIRK_DELAY_B4_CHK_RDY 1 /* Can't touch MMIO on disable */
#define QUIRK_DISABLE_TIMEOUT 2 /* Disable broken completion timeout feature */
bus_space_tag_t bus_tag;
bus_space_handle_t bus_handle;