diff --git a/include/spdk/nvme_spec.h b/include/spdk/nvme_spec.h index 2026bfb6e..68bd9615d 100644 --- a/include/spdk/nvme_spec.h +++ b/include/spdk/nvme_spec.h @@ -32,6 +32,11 @@ extern "C" { #define SPDK_NVME_ADMIN_QUEUE_MIN_ENTRIES SPDK_NVME_QUEUE_MIN_ENTRIES #define SPDK_NVME_ADMIN_QUEUE_MAX_ENTRIES 4096 +/* Controllers with quirk NVME_QUIRK_MINIMUM_ADMIN_QUEUE_SIZE must have + * admin queue size entries that are an even multiple of this number. + */ +#define SPDK_NVME_ADMIN_QUEUE_QUIRK_ENTRIES_MULTIPLE 64 + #define SPDK_NVME_IO_QUEUE_MIN_ENTRIES SPDK_NVME_QUEUE_MIN_ENTRIES #define SPDK_NVME_IO_QUEUE_MAX_ENTRIES 65536 diff --git a/include/spdk/pci_ids.h b/include/spdk/pci_ids.h index 5896ea3b1..80e52fd9c 100644 --- a/include/spdk/pci_ids.h +++ b/include/spdk/pci_ids.h @@ -27,6 +27,7 @@ extern "C" { #define SPDK_PCI_VID_REDHAT 0x1b36 #define SPDK_PCI_VID_NUTANIX 0x4e58 #define SPDK_PCI_VID_HUAWEI 0x19e5 +#define SPDK_PCI_VID_MICROSOFT 0x1414 #define SPDK_PCI_CLASS_ANY_ID 0xffffff /** diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index 1cb242f35..b1a57bdcb 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -4065,6 +4065,15 @@ nvme_ctrlr_construct(struct spdk_nvme_ctrlr *ctrlr) ctrlr->opts.admin_queue_size = SPDK_NVME_ADMIN_QUEUE_MAX_ENTRIES; } + if (ctrlr->quirks & NVME_QUIRK_MINIMUM_ADMIN_QUEUE_SIZE && + (ctrlr->opts.admin_queue_size % SPDK_NVME_ADMIN_QUEUE_QUIRK_ENTRIES_MULTIPLE) != 0) { + NVME_CTRLR_ERRLOG(ctrlr, + "admin_queue_size %u is invalid for this NVMe device, adjust to next multiple\n", + ctrlr->opts.admin_queue_size); + ctrlr->opts.admin_queue_size = SPDK_ALIGN_CEIL(ctrlr->opts.admin_queue_size, + SPDK_NVME_ADMIN_QUEUE_QUIRK_ENTRIES_MULTIPLE); + } + if (ctrlr->opts.admin_queue_size < SPDK_NVME_ADMIN_QUEUE_MIN_ENTRIES) { NVME_CTRLR_ERRLOG(ctrlr, "admin_queue_size %u is less than minimum defined by NVMe spec, use min value\n", diff --git a/lib/nvme/nvme_internal.h b/lib/nvme/nvme_internal.h index 7e0670004..95861c5f7 100644 --- a/lib/nvme/nvme_internal.h +++ b/lib/nvme/nvme_internal.h @@ -141,6 +141,12 @@ extern pid_t g_spdk_nvme_pid; */ #define NVME_QUIRK_NOT_USE_SGL 0x10000 +/* + * Some SSDs require the admin submission queue size to equate to an even + * 4KiB multiple. + */ +#define NVME_QUIRK_MINIMUM_ADMIN_QUEUE_SIZE 0x20000 + #define NVME_MAX_ASYNC_EVENTS (8) #define NVME_MAX_ADMIN_TIMEOUT_IN_SECS (30) diff --git a/lib/nvme/nvme_pcie.c b/lib/nvme/nvme_pcie.c index d19e771c4..a55c254b9 100644 --- a/lib/nvme/nvme_pcie.c +++ b/lib/nvme/nvme_pcie.c @@ -907,6 +907,8 @@ static struct spdk_nvme_ctrlr * pctrlr->ctrlr.trid = *trid; pctrlr->ctrlr.opts.admin_queue_size = spdk_max(pctrlr->ctrlr.opts.admin_queue_size, NVME_PCIE_MIN_ADMIN_QUEUE_SIZE); + pci_id = spdk_pci_device_get_id(pci_dev); + pctrlr->ctrlr.quirks = nvme_get_quirks(&pci_id); rc = nvme_ctrlr_construct(&pctrlr->ctrlr); if (rc != 0) { @@ -938,9 +940,6 @@ static struct spdk_nvme_ctrlr * * but we want multiples of 4, so drop the + 2 */ pctrlr->doorbell_stride_u32 = 1 << cap.bits.dstrd; - pci_id = spdk_pci_device_get_id(pci_dev); - pctrlr->ctrlr.quirks = nvme_get_quirks(&pci_id); - rc = nvme_pcie_ctrlr_construct_admin_qpair(&pctrlr->ctrlr, pctrlr->ctrlr.opts.admin_queue_size); if (rc != 0) { nvme_ctrlr_destruct(&pctrlr->ctrlr); diff --git a/lib/nvme/nvme_quirks.c b/lib/nvme/nvme_quirks.c index 9680476e3..f72b0f6e7 100644 --- a/lib/nvme/nvme_quirks.c +++ b/lib/nvme/nvme_quirks.c @@ -84,6 +84,9 @@ static const struct nvme_quirk nvme_quirks[] = { { {SPDK_PCI_CLASS_NVME, SPDK_PCI_VID_HUAWEI, SPDK_PCI_ANY_ID, SPDK_PCI_ANY_ID, SPDK_PCI_ANY_ID}, NVME_QUIRK_NOT_USE_SGL }, + { {SPDK_PCI_CLASS_NVME, SPDK_PCI_VID_MICROSOFT, 0xb111, SPDK_PCI_ANY_ID, SPDK_PCI_ANY_ID}, + NVME_QUIRK_MINIMUM_ADMIN_QUEUE_SIZE + }, { {0x000000, 0x0000, 0x0000, 0x0000, 0x0000}, 0} };