| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #pragma once |
| |
| #include <assert.h> |
| #include <stdint.h> |
| |
| // Registers in PCIE BAR0 MMIO Space |
| #define NVME_REG_CAP 0x00 // Capabilities |
| #define NVME_REG_VS 0x08 // Version |
| #define NVME_REG_INTMS 0x0C // Interrupt Mask Set |
| #define NVME_REG_INTMC 0x10 // Interrupt Mask clear |
| #define NVME_REG_CC 0x14 // Controller Configuration |
| #define NVME_REG_CSTS 0x1C // Controller Status |
| #define NVME_REG_NSSR 0x20 // NVM Subsystem Reset (Optional) |
| #define NVME_REG_AQA 0x24 // Admin Queue Attributes |
| #define NVME_REG_ASQ 0x28 // Admin Submission Queue Base Addr |
| #define NVME_REG_ACQ 0x30 // Admin Completion Queue Base Addr |
| #define NVME_REG_CMBLOC 0x38 // Controller Memory Block Location (Optional) |
| #define NVME_REG_CMBSZ 0x3C // Controller Memory Block Size (Optional) |
| |
| // Submission/Completion Queue Tail/Head are computed based on capabilities |
| #define NVME_REG_SQnTDBL(n, cap) (0x1000 + (2 * (n) + 0) * (4 << (NVME_CAP_DSTRD(cap) - 2))) |
| #define NVME_REG_CQnHDBL(n, cap) (0x1000 + (2 * (n) + 1) * (4 << (NVME_CAP_DSTRD(cap) - 2))) |
| |
| #define NVME_CAP_MPSMAX(n) ((((n) >> 52) & 0xF) + 12) // 2^x bytes |
| #define NVME_CAP_MPSMIN(n) ((((n) >> 48) & 0xF) + 12) // 2^x bytes |
| #define NVME_CAP_BPS(n) (((n) >> 45) & 1) |
| #define NVME_CAP_CSS_NVM(n) (((n) >> 37) & 1) |
| #define NVME_CAP_NSSRS(n) (((n) >> 36) & 1) |
| #define NVME_CAP_DSTRD(n) ((((n) >> 32) & 0xF) + 2) // 2^x bytes |
| #define NVME_CAP_TO(n) ((((n) >> 24) & 0xFF) * 500) // milliseconds |
| #define NVME_CAP_AMS_WRR(n) (((n) >> 17) & 1) |
| #define NVME_CAP_AMS_VS(n) (((n) >> 18) & 1) |
| #define NVME_CAP_CQR(n) (((n) >> 16) & 1) |
| #define NVME_CAP_MQES(n) ((n)&0xFFFF) |
| |
| #define NVME_CC_IOCQES(n) (((n)&0xF) << 20) // IO Completion Entry Size 2^n |
| #define NVME_CC_IOSQES(n) (((n)&0xF) << 16) // IO Submission Entry Size 2^n |
| #define NVME_CC_SHN_NORMAL (1 << 14) // Request Normal Shutdown |
| #define NVME_CC_SHN_ABRUPT (2 << 14) // Request Abrupt Shutdown |
| #define NVME_CC_SHN_MASK (3 << 14) |
| #define NVME_CC_AMS_RR (0 << 11) // Arbitration: Round-Robin |
| #define NVME_CC_AMS_WRR (1 << 11) // Arbitration: Weighted-Round-Robin |
| #define NVME_CC_AMS_VS (7 << 11) // Arbitration: Vendor Specific |
| #define NVME_CC_MPS(n) (((n)&0xF) << 7) // Memory Page Size (2^(n + 12)) |
| #define NVME_CC_EN (1 << 0) // Enable |
| |
| #define NVME_CSTS_PP (1 << 5) // Processing Paused |
| #define NVME_CSTS_NSSRO (1 << 4) // Subsystem Reset Occurred (W1C) |
| #define NVME_CSTS_SHN_MASK (3 << 2) |
| #define NVME_CSTS_SHN_NORMAL_OP (0 << 2) // not shutting done |
| #define NVME_CSTS_SHN_IN_PROGRESS (1 << 2) // Shutdown is in progress |
| #define NVME_CSTS_SHN_COMPLETE (2 << 2) // Shutdown is complete |
| #define NVME_CSTS_CFS (1 << 1) // Controller Fatal Status |
| #define NVME_CSTS_RDY (1 << 0) // Ready |
| |
| #define NVME_AQA_ACQS(n) (((n)&0xFFF) << 16) // Admin Completion Queue Size |
| #define NVME_AQA_ASQS(n) (((n)&0xFFF) << 0) // Admin Submission Queue Size |
| |
| // Completion Queue Entry |
| typedef struct { |
| uint32_t cmd; |
| uint32_t reserved; |
| uint16_t sq_head; |
| uint16_t sq_id; |
| uint16_t cmd_id; |
| uint16_t status; |
| } nvme_cpl_t; |
| |
| #define NVME_CPL_SIZE 16 |
| #define NVME_CPL_SHIFT 4 |
| static_assert(sizeof(nvme_cpl_t) == NVME_CPL_SIZE, ""); |
| static_assert(sizeof(nvme_cpl_t) == (1 << NVME_CPL_SHIFT), ""); |
| |
| #define NVME_CPL_STATUS_CODE(n) (((n) >> 1) & 0x7FF) |
| |
| // Submission Queue Entry |
| typedef struct { |
| uint32_t cmd; |
| uint32_t nsid; |
| uint64_t reserved; |
| uint64_t mptr; |
| union { |
| uint64_t prp[2]; |
| } dptr; |
| union { |
| uint32_t raw[6]; |
| struct { |
| uint64_t start_lba; |
| uint16_t block_count; // minus 1 |
| uint16_t flags; |
| uint32_t dsm; |
| uint32_t eilbrt; |
| uint32_t elbat; |
| } rw; |
| } u; |
| } nvme_cmd_t; |
| |
| #define NVME_CMD_SIZE 64 |
| #define NVME_CMD_SHIFT 6 |
| static_assert(sizeof(nvme_cmd_t) == NVME_CMD_SIZE, ""); |
| static_assert(sizeof(nvme_cmd_t) == (1 << NVME_CMD_SHIFT), ""); |
| |
| // Common |
| #define NVME_CMD_CID(n) (((n)&0xFFFF) << 16) |
| |
| #define NVME_CMD_PRP (0 << 14) // dptr uses PRP, mptr is raw addr |
| #define NVME_CMD_SGL (1 << 14) // dptr uses SGL, mptr is raw addr |
| #define NVME_CMD_SGL_MSGL (2 << 14) // dptr uses SGL, mptr points at SGL[1] |
| |
| #define NVME_CMD_NORMAL (0 << 8) // non-fused command |
| #define NVME_CMD_FUSED_1ST (1 << 8) // 1st part of fused command |
| #define NVME_CMD_FUSED_2ND (2 << 8) // 2nd part of fused command |
| |
| #define NVME_CMD_OPC(n) ((n)&0xFF) |
| |
| // Admin Opcodes |
| #define NVME_ADMIN_OP_DELETE_IOSQ 0x00 |
| #define NVME_ADMIN_OP_CREATE_IOSQ 0x01 |
| #define NVME_ADMIN_OP_DELETE_IOCQ 0x04 |
| #define NVME_ADMIN_OP_CREATE_IOCQ 0x05 |
| #define NVME_ADMIN_OP_IDENTIFY 0x06 |
| #define NVME_ADMIN_OP_ABORT 0x08 |
| #define NVME_ADMIN_OP_SET_FEATURE 0x09 |
| #define NVME_ADMIN_OP_GET_FEATURE 0x0A |
| #define NVME_ADMIN_OP_ASYNC_EVENT 0x0C |
| |
| #define NVME_FEATURE_SEL_CURRENT (0 << 8) |
| #define NVME_FEATURE_SEL_DEFAULT (1 << 8) |
| #define NVME_FEATURE_SEL_SAVED (2 << 8) |
| #define NVME_FEATURE_SEL_SUPPORTED (3 << 8) |
| |
| #define NVME_FEATURE_NUMBER_OF_QUEUES 0x07 |
| |
| #define NVME_LBAFMT_RP(n) (((n) >> 24) & 3) |
| #define NVME_LBAFMT_LBADS(n) (((n) >> 16) & 0xFF) // 2^n bytes |
| #define NVME_LBAFMT_MS(n) ((n)&0xFFFF) |
| |
| // NVM Opcodes |
| #define NVME_OP_FLUSH 0x00 |
| #define NVME_OP_WRITE 0x01 |
| #define NVME_OP_READ 0x02 |
| |
| #define NVME_RW_FLAG_LR (1 << 15) |
| #define NVME_RW_FLAG_FUA (1 << 14) |
| |
| // Identify Page for Controllers |
| typedef struct { |
| uint32_t w[8]; |
| } nvme_psd_t; |
| |
| typedef struct { |
| //--------------------- // Controller Capabilities and Features |
| uint16_t VID; // PCI Vendor ID |
| uint16_t SSVID; // PCI Subsystem Vendor ID |
| uint8_t SN[20]; // Serial Number |
| uint8_t MN[40]; // Model Number |
| uint8_t FR[8]; // Firmware Revision |
| uint8_t RAB; // Recommended Arbitrartion Burst |
| uint8_t IEEE[3]; // IEEE OUI Identifier |
| uint8_t CMIC; // Controller Multi-Path IO and Namespace Sharing Caps |
| uint8_t MDTS; // Maximum Data Transfer Size |
| uint16_t CNTLID; // Controller ID |
| uint32_t VER; // Version |
| uint32_t RTD3R; // RTD3 Resume Latency (uS) |
| uint32_t RTD3E; // RTD3 ENtry Latency (uS) |
| uint32_t OAES; // Optional Asynch Events Supported; |
| uint32_t CTRATT; // Controller Attributes |
| uint8_t zz0[12]; // Reserved |
| uint8_t FGUID[16]; // Field Replaceable Unit GUID |
| uint8_t zz1[112]; // Reserved |
| uint8_t zz2[16]; // Refer to NVMe MI Spec |
| |
| // -------------------- // Admin Command Set Attributes and Capabilities |
| uint16_t OACS; // Optional Admin Command Support |
| uint8_t ACL; // Abort Command Limit |
| uint8_t AERL; // Async Event Request Limit |
| uint8_t FRMW; // Firmware Updates |
| uint8_t LPA; // Log Page Attributes; |
| uint8_t ELPE; // Error Log Page Entries |
| uint8_t NPSS; // Number of Power States Supported |
| uint8_t AVSCC; // Admin Vendor Specific Command Config |
| uint8_t APSTA; // Autonomous Power State Transition Attrs |
| uint16_t WCTEMP; // Warning Composite Temp Threshold |
| uint16_t CCTEMP; // Critical Composite Temp Threshold |
| uint16_t MTFA; // Max Time for Firmware Activation (x 100mS, 0 = undef) |
| uint32_t HMPRE; // Host Memory Buffer Preferred Size (4K pages) |
| uint32_t HMMIN; // Host Memory Buffer Minimum Size (4K pages) |
| uint64_t TNVMCAP_LO; // Total NVM Capacity (bytes) |
| uint64_t TNVMCAP_HI; |
| uint64_t UNVMCAP_LO; // Unallocated NVM Capacity (bytes) |
| uint64_t UNVMCAP_HI; |
| uint32_t RPMBS; // Replay Protected Memory Block Support |
| uint16_t EDSTT; // Extended Device SelfTest Time |
| uint8_t DSTO; // Devcie SelfTest Options |
| uint8_t FWUG; // Firmware Upgreade Granularity |
| uint16_t KAS; // Keep Alive Support |
| uint16_t HCTMA; // Host Controlled Thermal Management Attrs |
| uint16_t MNTMT; // Minimum Thermal Management Temp |
| uint16_t MXTMT; // Maximum Thermal Management Temp |
| uint32_t SANICAP; // Sanitize Capabilities |
| uint8_t zz3[180]; // Reserved |
| |
| // -------------------- // NVM Command Set Attributes |
| uint8_t SQES; // Submission Queue Entry Size |
| uint8_t CQES; // Completion Queue Entry Size |
| uint16_t MAXCMD; // Max Outstanding Commands |
| uint32_t NN; // Number of Namespaces |
| uint16_t ONCS; // Optional NVM Command Support |
| uint16_t FUSES; // Fused Operation Support |
| uint8_t FNA; // Format NVM Attributes |
| uint8_t VWC; // Volatile Write Cache |
| uint16_t AWUN; // Atomic Write Unit Normal |
| uint16_t AWUPF; // Atomic Write Unit Power Fail |
| uint8_t NVSCC; // NVM Vendor Specific Command Config |
| uint8_t zz4; // Reserved |
| uint16_t ACWU; // Atomic Compare and Write Unit |
| uint16_t zz5; // Reserved |
| uint32_t SGLS; // Scatter Gather List Support |
| uint8_t zz6[228]; // Reserved |
| uint8_t SUBNQN[256]; // NVM Subsystem NVMe Qualified Name |
| uint8_t zz7[768]; // Reserved |
| uint8_t zz8[256]; // Refer to NVME over Fabrics Spec |
| |
| // -------------------- // Power State Descriptors |
| nvme_psd_t PSD[32]; |
| |
| // -------------------- // Vendor Specific |
| uint8_t vendor[1024]; |
| } nvme_identify_t; |
| |
| static_assert(sizeof(nvme_identify_t) == 4096, ""); |
| |
| #define OACS_DOORBELL_BUFFER_CONFIG (1 << 8) |
| #define OACS_VIRTUALIZATION_MANAGEMENT (1 << 7) |
| #define OACS_NVME_MI_SEND_RECV (1 << 6) |
| #define OACS_DIRECTIVE_SEND_RECV (1 << 5) |
| #define OACS_DEVICE_SELF_TEST (1 << 4) |
| #define OACS_NAMESPACE_MANAGEMENT (1 << 3) |
| #define OACS_FIRMWARE_DOWNLOAD_COMMIT (1 << 2) |
| #define OACS_FORMAT_NVM (1 << 1) |
| #define OACS_SECURITY_SEND_RECV (1 << 0) |
| |
| #define ONCS_TIMESTAMP (1 << 6) |
| #define ONCS_RESERVATIONS (1 << 5) |
| #define ONCS_SAVE_SELECT_NONZERO (1 << 4) |
| #define ONCS_WRITE_ZEROES (1 << 3) |
| #define ONCS_DATASET_MANAGEMENT (1 << 2) |
| #define ONCS_WRITE_UNCORRECTABLE (1 << 1) |
| #define ONCS_COMPARE (1 << 0) |
| |
| // Identify Page for Namespaces |
| #define NSFEAT_GUIDS_NOT_REUSED (1 << 3) |
| #define NSFEAT_DEALLOC_BLOCK_ERROR (1 << 2) |
| #define NSFEAT_LOCAL_ATOMIC_SIZES (1 << 1) |
| #define NSFEAT_THING_PROVISIONING (1 << 0) |
| |
| typedef struct { |
| // -------------------- // Vendor Specific |
| uint64_t NSSZ; // Namespace Size (blocks) |
| uint64_t NCAP; // Namespace Capacity (blocks) |
| uint64_t NUSE; // Namespace Utilization (blocks) |
| uint8_t NSFEAT; // Namespace Features |
| uint8_t NLBAF; // Number of LBA Formats |
| uint8_t FLBAS; // Formatted LBA Size |
| uint8_t MC; // Metadata Capabilities |
| uint8_t DPC; // End-to-End Data Protection Capabilities |
| uint8_t DPS; // End-to-End Data Protection Type Settings |
| uint8_t NMIC; // Namespace MultiPath IO and Sharing Caps |
| uint8_t RESCAP; // Reservation Capabilities |
| uint8_t FPI; // Format Progress Indicator |
| uint8_t DLFEAT; // Deallocate Logical Block Features |
| uint16_t NAWUN; // Namespace Atomic Write Unit Normal |
| uint16_t NAWUPF; // Namespace Atomic Write Unit Power Fail |
| uint16_t NACWUN; // Namespace Atomic Compare and Write Unit |
| uint16_t NABSN; // Namespace Atomic Boundary Size Normal |
| uint16_t NABO; // Namespace Atomic Boundary Offset |
| uint16_t NABSPF; // Namespace Atomic Boundary Size Power Fail |
| uint16_t NOIOB; // Namespace Optimal IO Boundary |
| uint64_t NVMCAP_LO; // NVM Capacity (bytes) |
| uint64_t NVMCAP_HI; |
| uint8_t zz0[40]; // Reserved |
| uint8_t NGUID[16]; // Namespace GUID |
| uint8_t EUI64[8]; // IEEE Extended Unique Identifier |
| uint32_t LBAF[16]; // LBA Format Support 0..15 |
| uint8_t zz1[192]; // Reserved |
| uint8_t zz2[3712]; // Reserved |
| } nvme_identify_ns_t; |
| |
| static_assert(sizeof(nvme_identify_ns_t) == 4096, ""); |
| |
| #define NSFEAT_GUIDS_NOT_REUSED (1 << 3) |
| #define NSFEAT_DEALLOC_BLOCK_ERROR (1 << 2) |
| #define NSFEAT_LOCAL_ATOMIC_SIZES (1 << 1) |
| #define NSFEAT_THING_PROVISIONING (1 << 0) |