diff --git a/CHANGELOG.md b/CHANGELOG.md index 0888a5f05..a068c341a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -137,6 +137,8 @@ Change the return type of function `spdk_nbd_stop` from void to int. And update ### nvme +Added a new function `spdk_nvme_ctrlr_get_regs_pmrcap` to get the PMR capabilities. + Directives support was added to the NVMe driver. Two async APIs `spdk_nvme_ctrlr_cmd_directive_receive` and `spdk_nvme_ctrlr_cmd_directive_send` diff --git a/examples/nvme/identify/identify.c b/examples/nvme/identify/identify.c index 62e201291..647f4374b 100644 --- a/examples/nvme/identify/identify.c +++ b/examples/nvme/identify/identify.c @@ -1074,6 +1074,7 @@ print_controller(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_transport union spdk_nvme_cap_register cap; union spdk_nvme_vs_register vs; union spdk_nvme_cmbsz_register cmbsz; + union spdk_nvme_pmrcap_register pmrcap; uint8_t str[512]; uint32_t i, j; struct spdk_nvme_error_information_entry *error_entry; @@ -1086,6 +1087,7 @@ print_controller(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_transport cap = spdk_nvme_ctrlr_get_regs_cap(ctrlr); vs = spdk_nvme_ctrlr_get_regs_vs(ctrlr); cmbsz = spdk_nvme_ctrlr_get_regs_cmbsz(ctrlr); + pmrcap = spdk_nvme_ctrlr_get_regs_pmrcap(ctrlr); if (!spdk_nvme_ctrlr_is_discovery(ctrlr)) { /* @@ -1198,6 +1200,9 @@ print_controller(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_transport (uint64_t)1 << (12 + cap.bits.mpsmin)); printf("Memory Page Size Maximum: %" PRIu64 " bytes\n", (uint64_t)1 << (12 + cap.bits.mpsmax)); + printf("Persistent Memory Region: %s\n", + cap.bits.pmrs ? "Supported" : "Not Supported"); + printf("Optional Asynchronous Events Supported\n"); printf(" Namespace Attribute Notices: %s\n", cdata->oaes.ns_attribute_notices ? "Supported" : "Not Supported"); @@ -1233,6 +1238,19 @@ print_controller(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_transport } printf("\n"); + printf("Persistent Memory Region Support\n"); + printf("================================\n"); + if (cap.bits.pmrs != 0) { + printf("Supported: Yes\n"); + printf("Read data and metadata in PMR %s\n", + pmrcap.bits.rds ? "Supported" : "Not Supported"); + printf("Write data and metadata in PMR: %s\n", + pmrcap.bits.wds ? "Supported" : "Not Supported"); + } else { + printf("Supported: No\n"); + } + printf("\n"); + printf("Admin Command Set Attributes\n"); printf("============================\n"); printf("Security Send/Receive: %s\n", diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index 002427537..0866d87c4 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -1017,6 +1017,15 @@ union spdk_nvme_vs_register spdk_nvme_ctrlr_get_regs_vs(struct spdk_nvme_ctrlr * */ union spdk_nvme_cmbsz_register spdk_nvme_ctrlr_get_regs_cmbsz(struct spdk_nvme_ctrlr *ctrlr); +/** + * Get the NVMe controller PMRCAP (Persistent Memory Region Capabilities) register. + * + * \param ctrlr Opaque handle to NVMe controller. + * + * \return the NVMe controller PMRCAP (Persistent Memory Region Capabilities) register. + */ +union spdk_nvme_pmrcap_register spdk_nvme_ctrlr_get_regs_pmrcap(struct spdk_nvme_ctrlr *ctrlr); + /** * Get the number of namespaces for the given NVMe controller. * diff --git a/include/spdk/nvme_spec.h b/include/spdk/nvme_spec.h index 87c327903..362b98677 100644 --- a/include/spdk/nvme_spec.h +++ b/include/spdk/nvme_spec.h @@ -109,7 +109,10 @@ union spdk_nvme_cap_register { /** memory page size maximum */ uint32_t mpsmax : 4; - uint32_t reserved3 : 8; + /** persistent memory region supported */ + uint32_t pmrs : 1; + + uint32_t reserved3 : 7; } bits; }; SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_cap_register) == 8, "Incorrect size"); @@ -299,6 +302,139 @@ union spdk_nvme_cmbsts_register { }; SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_cmbsts_register) == 4, "Incorrect size"); +union spdk_nvme_pmrcap_register { + uint32_t raw; + struct { + uint32_t reserved1 : 3; + + /** read data support */ + uint32_t rds : 1; + + /** write data support */ + uint32_t wds : 1; + + /** base indicator register */ + uint32_t bir : 3; + + /** + * persistent memory region time units + * 00b: 500 milliseconds + * 01b: minutes + */ + uint32_t pmrtu : 2; + + /** persistent memory region write barrier mechanisms */ + uint32_t pmrwbm : 4; + + uint32_t reserved2 : 2; + + /** persistent memory region timeout */ + uint32_t pmrto : 8; + + /** controller memory space supported */ + uint32_t cmss : 1; + + uint32_t reserved3 : 7; + } bits; +}; +SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_pmrcap_register) == 4, "Incorrect size"); + +union spdk_nvme_pmrctl_register { + uint32_t raw; + struct { + /** enable */ + uint32_t en : 1; + + uint32_t reserved : 31; + } bits; +}; +SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_pmrctl_register) == 4, "Incorrect size"); + +union spdk_nvme_pmrsts_register { + uint32_t raw; + struct { + /** err */ + uint32_t err : 8; + + /** not ready */ + uint32_t nrdy : 1; + + /** + * health status + * 000b: Normal Operation + * 001b: Restore Error + * 010b: Read Only + * 011b: Unreliable + */ + uint32_t hsts : 3; + + /** controller base address invalid */ + uint32_t cbai : 1; + + uint32_t reserved : 19; + } bits; +}; +SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_pmrsts_register) == 4, "Incorrect size"); + +union spdk_nvme_pmrebs_register { + uint32_t raw; + struct { + /** + * pmr elasicity buffer size units + * 0h: Bytes + * 1h: 1 KiB + * 2h: 1 MiB + * 3h: 1 GiB + */ + uint32_t pmrszu : 4; + + /** read bypass behavior */ + uint32_t rbb : 1; + + uint32_t reserved : 3; + + /** pmr elasticity buffer size base */ + uint32_t pmrwbz : 24; + } bits; +}; +SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_pmrebs_register) == 4, "Incorrect size"); + +union spdk_nvme_pmrswtp_register { + uint32_t raw; + struct { + /** + * pmr sustained write throughput units + * 0h: Bytes per second + * 1h: 1 KiB / s + * 2h: 1 MiB / s + * 3h: 1 GiB / s + */ + uint32_t pmrswtu : 4; + + uint32_t reserved : 4; + + /** pmr sustained write throughput */ + uint32_t pmrswtv : 24; + } bits; +}; +SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_pmrswtp_register) == 4, "Incorrect size"); + +union spdk_nvme_pmrmscl_register { + uint32_t raw; + struct { + uint32_t reserved1 : 1; + + /** controller memory space enable */ + uint32_t cmse : 1; + + uint32_t reserved2 : 10; + + /** controller base address */ + uint32_t cba : 20; + } bits; +}; +SPDK_STATIC_ASSERT(sizeof(union spdk_nvme_pmrmscl_register) == 4, "Incorrect size"); + /** Boot partition information */ union spdk_nvme_bpinfo_register { uint32_t raw; @@ -387,7 +523,29 @@ struct spdk_nvme_registers { /** controller memory buffer status */ union spdk_nvme_cmbsts_register cmbsts; - uint32_t reserved3[0x3e9]; + uint32_t reserved2[0x369]; + + /** persistent memory region capabilities */ + union spdk_nvme_pmrcap_register pmrcap; + + /** persistent memory region control */ + union spdk_nvme_pmrctl_register pmrctl; + + /** persistent memory region status */ + union spdk_nvme_pmrsts_register pmrsts; + + /** persistent memory region elasticity buffer size */ + union spdk_nvme_pmrebs_register pmrebs; + + /** persistent memory region sustained write throughput */ + union spdk_nvme_pmrswtp_register pmrswtp; + + /** persistent memory region memory space control lower */ + union spdk_nvme_pmrmscl_register pmrmscl; + + uint32_t pmrmscu; /* persistent memory region memory space control upper */ + + uint32_t reserved3[0x79]; struct { uint32_t sq_tdbl; /* submission queue tail doorbell */ @@ -423,6 +581,20 @@ SPDK_STATIC_ASSERT(0x50 == offsetof(struct spdk_nvme_registers, cmbmsc), "Incorrect register offset"); SPDK_STATIC_ASSERT(0x58 == offsetof(struct spdk_nvme_registers, cmbsts), "Incorrect register offset"); +SPDK_STATIC_ASSERT(0xE00 == offsetof(struct spdk_nvme_registers, pmrcap), + "Incorrect register offset"); +SPDK_STATIC_ASSERT(0xE04 == offsetof(struct spdk_nvme_registers, pmrctl), + "Incorrect register offset"); +SPDK_STATIC_ASSERT(0xE08 == offsetof(struct spdk_nvme_registers, pmrsts), + "Incorrect register offset"); +SPDK_STATIC_ASSERT(0xE0C == offsetof(struct spdk_nvme_registers, pmrebs), + "Incorrect register offset"); +SPDK_STATIC_ASSERT(0xE10 == offsetof(struct spdk_nvme_registers, pmrswtp), + "Incorrect register offset"); +SPDK_STATIC_ASSERT(0xE14 == offsetof(struct spdk_nvme_registers, pmrmscl), + "Incorrect register offset"); +SPDK_STATIC_ASSERT(0xE18 == offsetof(struct spdk_nvme_registers, pmrmscu), + "Incorrect register offset"); enum spdk_nvme_sgl_descriptor_type { SPDK_NVME_SGL_TYPE_DATA_BLOCK = 0x0, diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index ff277714b..7814d6ad6 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -91,6 +91,13 @@ nvme_ctrlr_get_cmbsz(struct spdk_nvme_ctrlr *ctrlr, union spdk_nvme_cmbsz_regist &cmbsz->raw); } +int +nvme_ctrlr_get_pmrcap(struct spdk_nvme_ctrlr *ctrlr, union spdk_nvme_pmrcap_register *pmrcap) +{ + return nvme_transport_ctrlr_get_reg_4(ctrlr, offsetof(struct spdk_nvme_registers, pmrcap.raw), + &pmrcap->raw); +} + static int nvme_ctrlr_set_nssr(struct spdk_nvme_ctrlr *ctrlr, uint32_t nssr_value) { @@ -3539,6 +3546,17 @@ union spdk_nvme_cmbsz_register spdk_nvme_ctrlr_get_regs_cmbsz(struct spdk_nvme_c return cmbsz; } +union spdk_nvme_pmrcap_register spdk_nvme_ctrlr_get_regs_pmrcap(struct spdk_nvme_ctrlr *ctrlr) +{ + union spdk_nvme_pmrcap_register pmrcap; + + if (nvme_ctrlr_get_pmrcap(ctrlr, &pmrcap)) { + pmrcap.raw = 0; + } + + return pmrcap; +} + uint32_t spdk_nvme_ctrlr_get_num_ns(struct spdk_nvme_ctrlr *ctrlr) { diff --git a/lib/nvme/nvme_internal.h b/lib/nvme/nvme_internal.h index 95553f016..b3e23945c 100644 --- a/lib/nvme/nvme_internal.h +++ b/lib/nvme/nvme_internal.h @@ -1019,6 +1019,7 @@ int nvme_ctrlr_submit_admin_request(struct spdk_nvme_ctrlr *ctrlr, int nvme_ctrlr_get_cap(struct spdk_nvme_ctrlr *ctrlr, union spdk_nvme_cap_register *cap); int nvme_ctrlr_get_vs(struct spdk_nvme_ctrlr *ctrlr, union spdk_nvme_vs_register *vs); int nvme_ctrlr_get_cmbsz(struct spdk_nvme_ctrlr *ctrlr, union spdk_nvme_cmbsz_register *cmbsz); +int nvme_ctrlr_get_pmrcap(struct spdk_nvme_ctrlr *ctrlr, union spdk_nvme_pmrcap_register *pmrcap); bool nvme_ctrlr_multi_iocs_enabled(struct spdk_nvme_ctrlr *ctrlr); void nvme_ctrlr_init_cap(struct spdk_nvme_ctrlr *ctrlr, const union spdk_nvme_cap_register *cap, const union spdk_nvme_vs_register *vs); diff --git a/lib/nvme/spdk_nvme.map b/lib/nvme/spdk_nvme.map index d2455748b..be70c3c81 100644 --- a/lib/nvme/spdk_nvme.map +++ b/lib/nvme/spdk_nvme.map @@ -41,6 +41,7 @@ spdk_nvme_ctrlr_get_regs_cap; spdk_nvme_ctrlr_get_regs_vs; spdk_nvme_ctrlr_get_regs_cmbsz; + spdk_nvme_ctrlr_get_regs_pmrcap; spdk_nvme_ctrlr_get_num_ns; spdk_nvme_ctrlr_get_pci_device; spdk_nvme_ctrlr_get_max_xfer_size;