1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
  14  */
  15 
  16 /*
  17  * NVMe hardware interface
  18  */
  19 
  20 #ifndef _NVME_REG_H
  21 #define _NVME_REG_H
  22 
  23 #include <sys/nvme.h>
  24 
  25 #pragma pack(1)
  26 
  27 #ifdef __cplusplus
  28 extern "C" {
  29 #endif
  30 
  31 
  32 /*
  33  * NVMe constants
  34  */
  35 #define NVME_MAX_ADMIN_QUEUE_LEN        4096
  36 
  37 /*
  38  * NVMe registers and register fields
  39  */
  40 #define NVME_REG_CAP    0x0             /* Controller Capabilities */
  41 #define NVME_REG_VS     0x8             /* Version */
  42 #define NVME_REG_INTMS  0xc             /* Interrupt Mask Set */
  43 #define NVME_REG_INTMC  0x10            /* Interrupt Mask Clear */
  44 #define NVME_REG_CC     0x14            /* Controller Configuration */
  45 #define NVME_REG_CSTS   0x1c            /* Controller Status */
  46 #define NVME_REG_NSSR   0x20            /* NVM Subsystem Reset */
  47 #define NVME_REG_AQA    0x24            /* Admin Queue Attributes */
  48 #define NVME_REG_ASQ    0x28            /* Admin Submission Queue */
  49 #define NVME_REG_ACQ    0x30            /* Admin Completion Qeueu */
  50 #define NVME_REG_SQTDBL(nvme, n) \
  51         (0x1000 + ((2 * (n)) * nvme->n_doorbell_stride))
  52 #define NVME_REG_CQHDBL(nvme, n) \
  53         (0x1000 + ((2 * (n) + 1) * nvme->n_doorbell_stride))
  54 
  55 #define  NVME_CAP_CSS_NVM       1       /* NVM Command Set */
  56 #define  NVME_CAP_AMS_WRR       1       /* Weighted Round-Robin */
  57 
  58 /* CAP -- Controller Capabilities */
  59 typedef union {
  60         struct {
  61                 uint16_t cap_mqes;      /* Maximum Queue Entries Supported */
  62                 uint8_t cap_cqr:1;      /* Contiguous Queues Required */
  63                 uint8_t cap_ams:2;      /* Arbitration Mechanisms Supported */
  64                 uint8_t cap_rsvd1:5;
  65                 uint8_t cap_to;         /* Timeout */
  66                 uint16_t cap_dstrd:4;   /* Doorbell Stride */
  67                 uint16_t cap_nssrs:1;   /* NVM Subsystem Reset Supported */
  68                 uint16_t cap_css:8;     /* Command Sets Supported */
  69                 uint16_t cap_rsvd2:3;
  70                 uint8_t cap_mpsmin:4;   /* Memory Page Size Minimum */
  71                 uint8_t cap_mpsmax:4;   /* Memory Page Size Maximum */
  72                 uint8_t cap_rsvd3;
  73         } b;
  74         uint64_t r;
  75 } nvme_reg_cap_t;
  76 
  77 /* VS -- Version */
  78 typedef union {
  79         struct {
  80                 uint8_t vs_rsvd;
  81                 uint8_t vs_mnr;         /* Minor Version Number */
  82                 uint16_t vs_mjr;        /* Major Version Number */
  83         } b;
  84         uint32_t r;
  85 } nvme_reg_vs_t;
  86 
  87 /* CC -- Controller Configuration */
  88 #define NVME_CC_SHN_NORMAL      1       /* Normal Shutdown Notification */
  89 #define NVME_CC_SHN_ABRUPT      2       /* Abrupt Shutdown Notification */
  90 
  91 typedef union {
  92         struct {
  93                 uint16_t cc_en:1;       /* Enable */
  94                 uint16_t cc_rsvd1:3;
  95                 uint16_t cc_css:3;      /* I/O Command Set Selected */
  96                 uint16_t cc_mps:4;      /* Memory Page Size */
  97                 uint16_t cc_ams:3;      /* Arbitration Mechanism Selected */
  98                 uint16_t cc_shn:2;      /* Shutdown Notification */
  99                 uint8_t cc_iosqes:4;    /* I/O Submission Queue Entry Size */
 100                 uint8_t cc_iocqes:4;    /* I/O Completion Queue Entry Size */
 101                 uint8_t cc_rsvd2;
 102         } b;
 103         uint32_t r;
 104 } nvme_reg_cc_t;
 105 
 106 /* CSTS -- Controller Status */
 107 #define NVME_CSTS_SHN_OCCURING  1       /* Shutdown Processing Occuring */
 108 #define NVME_CSTS_SHN_COMPLETE  2       /* Shutdown Processing Complete */
 109 
 110 typedef union {
 111         struct {
 112                 uint32_t csts_rdy:1;    /* Ready */
 113                 uint32_t csts_cfs:1;    /* Controller Fatal Status */
 114                 uint32_t csts_shst:2;   /* Shutdown Status */
 115                 uint32_t csts_nssro:1;  /* NVM Subsystem Reset Occured */
 116                 uint32_t csts_rsvd:27;
 117         } b;
 118         uint32_t r;
 119 } nvme_reg_csts_t;
 120 
 121 /* NSSR -- NVM Subsystem Reset */
 122 #define NVME_NSSR_NSSRC 0x4e564d65      /* NSSR magic value */
 123 typedef uint32_t nvme_reg_nssr_t;
 124 
 125 /* AQA -- Admin Queue Attributes */
 126 typedef union {
 127         struct {
 128                 uint16_t aqa_asqs:12;   /* Admin Submission Queue Size */
 129                 uint16_t aqa_rsvd1:4;
 130                 uint16_t aqa_acqs:12;   /* Admin Completion Queue Size */
 131                 uint16_t aqa_rsvd2:4;
 132         } b;
 133         uint32_t r;
 134 } nvme_reg_aqa_t;
 135 
 136 /*
 137  * The spec specifies the lower 12 bits of ASQ and ACQ as reserved, which is
 138  * probably a specification bug. The full 64bit regs are used as base address,
 139  * and the lower bits must be zero to ensure alignment on the page size
 140  * specified in CC.MPS.
 141  */
 142 /* ASQ -- Admin Submission Queue Base Address */
 143 typedef uint64_t nvme_reg_asq_t;        /* Admin Submission Queue Base */
 144 
 145 /* ACQ -- Admin Completion Queue Base Address */
 146 typedef uint64_t nvme_reg_acq_t;        /* Admin Completion Queue Base */
 147 
 148 /* SQyTDBL -- Submission Queue y Tail Doorbell */
 149 typedef union {
 150         struct {
 151                 uint16_t sqtdbl_sqt;    /* Submission Queue Tail */
 152                 uint16_t sqtdbl_rsvd;
 153         } b;
 154         uint32_t r;
 155 } nvme_reg_sqtdbl_t;
 156 
 157 /* CQyHDBL -- Completion Queue y Head Doorbell */
 158 typedef union {
 159         struct {
 160                 uint16_t cqhdbl_cqh;    /* Completion Queue Head */
 161                 uint16_t cqhdbl_rsvd;
 162         } b;
 163         uint32_t r;
 164 } nvme_reg_cqhdbl_t;
 165 
 166 /*
 167  * NVMe submission queue entries
 168  */
 169 
 170 /* NVMe scatter/gather list descriptor */
 171 typedef struct {
 172         uint64_t sgl_addr;              /* Address */
 173         uint32_t sgl_len;               /* Length */
 174         uint8_t sgl_rsvd[3];
 175         uint8_t sgl_zero:4;
 176         uint8_t sgl_type:4;             /* SGL descriptor type */
 177 } nvme_sgl_t;
 178 
 179 /* NVMe SGL descriptor type */
 180 #define NVME_SGL_DATA_BLOCK     0
 181 #define NVME_SGL_BIT_BUCKET     1
 182 #define NVME_SGL_SEGMENT        2
 183 #define NVME_SGL_LAST_SEGMENT   3
 184 #define NVME_SGL_VENDOR         0xf
 185 
 186 /* NVMe submission queue entry */
 187 typedef struct {
 188         uint8_t sqe_opc;                /* Opcode */
 189         uint8_t sqe_fuse:2;             /* Fused Operation */
 190         uint8_t sqe_rsvd:5;
 191         uint8_t sqe_psdt:1;             /* PRP or SGL for Data Transfer */
 192         uint16_t sqe_cid;               /* Command Identifier */
 193         uint32_t sqe_nsid;              /* Namespace Identifier */
 194         uint64_t sqe_rsvd1;
 195         union {
 196                 uint64_t m_ptr;         /* Metadata Pointer */
 197                 uint64_t m_sglp;        /* Metadata SGL Segment Pointer */
 198         } sqe_m;
 199         union {
 200                 uint64_t d_prp[2];      /* Physical Page Region Entries 1 & 2 */
 201                 nvme_sgl_t d_sgl;       /* SGL Entry 1 */
 202         } sqe_dptr;                     /* Data Pointer */
 203         uint32_t sqe_cdw10;             /* Number of Dwords in Data Transfer */
 204         uint32_t sqe_cdw11;             /* Number of Dwords in Metadata Xfer */
 205         uint32_t sqe_cdw12;
 206         uint32_t sqe_cdw13;
 207         uint32_t sqe_cdw14;
 208         uint32_t sqe_cdw15;
 209 } nvme_sqe_t;
 210 
 211 /* NVMe admin command opcodes */
 212 #define NVME_OPC_DELETE_SQUEUE  0x0
 213 #define NVME_OPC_CREATE_SQUEUE  0x1
 214 #define NVME_OPC_GET_LOG_PAGE   0x2
 215 #define NVME_OPC_DELETE_CQUEUE  0x4
 216 #define NVME_OPC_CREATE_CQUEUE  0x5
 217 #define NVME_OPC_IDENTIFY       0x6
 218 #define NVME_OPC_ABORT          0x8
 219 #define NVME_OPC_SET_FEATURES   0x9
 220 #define NVME_OPC_GET_FEATURES   0xa
 221 #define NVME_OPC_ASYNC_EVENT    0xc
 222 #define NVME_OPC_FW_ACTIVATE    0x10
 223 #define NVME_OPC_FW_IMAGE_LOAD  0x11
 224 
 225 /* NVMe NVM command set specific admin command opcodes */
 226 #define NVME_OPC_NVM_FORMAT     0x80
 227 #define NVME_OPC_NVM_SEC_SEND   0x81
 228 #define NVME_OPC_NVM_SEC_RECV   0x82
 229 
 230 /* NVMe NVM command opcodes */
 231 #define NVME_OPC_NVM_FLUSH      0x0
 232 #define NVME_OPC_NVM_WRITE      0x1
 233 #define NVME_OPC_NVM_READ       0x2
 234 #define NVME_OPC_NVM_WRITE_UNC  0x4
 235 #define NVME_OPC_NVM_COMPARE    0x5
 236 #define NVME_OPC_NVM_WRITE_ZERO 0x8
 237 #define NVME_OPC_NVM_DSET_MGMT  0x9
 238 #define NVME_OPC_NVM_RESV_REG   0xd
 239 #define NVME_OPC_NVM_RESV_REPRT 0xe
 240 #define NVME_OPC_NVM_RESV_ACQ   0x11
 241 #define NVME_OPC_NVM_RESV_REL   0x12
 242 
 243 /*
 244  * NVMe completion queue entry
 245  */
 246 typedef struct {
 247         uint32_t cqe_dw0;               /* Command Specific */
 248         uint32_t cqe_rsvd1;
 249         uint16_t cqe_sqhd;              /* SQ Head Pointer */
 250         uint16_t cqe_sqid;              /* SQ Identifier */
 251         uint16_t cqe_cid;               /* Command Identifier */
 252         nvme_cqe_sf_t cqe_sf;           /* Status Field */
 253 } nvme_cqe_t;
 254 
 255 /* NVMe completion status code type */
 256 #define NVME_CQE_SCT_GENERIC    0       /* Generic Command Status */
 257 #define NVME_CQE_SCT_SPECIFIC   1       /* Command Specific Status */
 258 #define NVME_CQE_SCT_INTEGRITY  2       /* Media and Data Integrity Errors */
 259 #define NVME_CQE_SCT_VENDOR     7       /* Vendor Specific */
 260 
 261 /* NVMe completion status code (generic) */
 262 #define NVME_CQE_SC_GEN_SUCCESS         0x0     /* Successful Completion */
 263 #define NVME_CQE_SC_GEN_INV_OPC         0x1     /* Invalid Command Opcode */
 264 #define NVME_CQE_SC_GEN_INV_FLD         0x2     /* Invalid Field in Command */
 265 #define NVME_CQE_SC_GEN_ID_CNFL         0x3     /* Command ID Conflict */
 266 #define NVME_CQE_SC_GEN_DATA_XFR_ERR    0x4     /* Data Transfer Error */
 267 #define NVME_CQE_SC_GEN_ABORT_PWRLOSS   0x5     /* Cmds Aborted / Pwr Loss */
 268 #define NVME_CQE_SC_GEN_INTERNAL_ERR    0x6     /* Internal Error */
 269 #define NVME_CQE_SC_GEN_ABORT_REQUEST   0x7     /* Command Abort Requested */
 270 #define NVME_CQE_SC_GEN_ABORT_SQ_DEL    0x8     /* Cmd Aborted / SQ deletion */
 271 #define NVME_CQE_SC_GEN_ABORT_FUSE_FAIL 0x9     /* Cmd Aborted / Failed Fused */
 272 #define NVME_CQE_SC_GEN_ABORT_FUSE_MISS 0xa     /* Cmd Aborted / Missing Fusd */
 273 #define NVME_CQE_SC_GEN_INV_NS          0xb     /* Inval Namespace or Format */
 274 #define NVME_CQE_SC_GEN_CMD_SEQ_ERR     0xc     /* Command Sequence Error */
 275 #define NVME_CQE_SC_GEN_INV_SGL_LAST    0xd     /* Inval SGL Last Seg Desc */
 276 #define NVME_CQE_SC_GEN_INV_SGL_NUM     0xe     /* Inval Number of SGL Desc */
 277 #define NVME_CQE_SC_GEN_INV_DSGL_LEN    0xf     /* Data SGL Length Invalid */
 278 #define NVME_CQE_SC_GEN_INV_MSGL_LEN    0x10    /* Metadata SGL Length Inval */
 279 #define NVME_CQE_SC_GEN_INV_SGL_DESC    0x11    /* SGL Descriptor Type Inval */
 280 
 281 /* NVMe completion status code (generic NVM commands) */
 282 #define NVME_CQE_SC_GEN_NVM_LBA_RANGE   0x80    /* LBA Out Of Range */
 283 #define NVME_CQE_SC_GEN_NVM_CAP_EXC     0x81    /* Capacity Exceeded */
 284 #define NVME_CQE_SC_GEN_NVM_NS_NOTRDY   0x82    /* Namespace Not Ready */
 285 #define NVME_CQE_SC_GEN_NVM_RSV_CNFLCT  0x83    /* Reservation Conflict */
 286 
 287 /* NVMe completion status code (command specific) */
 288 #define NVME_CQE_SC_SPC_INV_CQ          0x0     /* Completion Queue Invalid */
 289 #define NVME_CQE_SC_SPC_INV_QID         0x1     /* Invalid Queue Identifier */
 290 #define NVME_CQE_SC_SPC_MAX_QSZ_EXC     0x2     /* Max Queue Size Exceeded */
 291 #define NVME_CQE_SC_SPC_ABRT_CMD_EXC    0x3     /* Abort Cmd Limit Exceeded */
 292 #define NVME_CQE_SC_SPC_ASYNC_EVREQ_EXC 0x5     /* Async Event Request Limit */
 293 #define NVME_CQE_SC_SPC_INV_FW_SLOT     0x6     /* Invalid Firmware Slot */
 294 #define NVME_CQE_SC_SPC_INV_FW_IMG      0x7     /* Invalid Firmware Image */
 295 #define NVME_CQE_SC_SPC_INV_INT_VECT    0x8     /* Invalid Interrupt Vector */
 296 #define NVME_CQE_SC_SPC_INV_LOG_PAGE    0x9     /* Invalid Log Page */
 297 #define NVME_CQE_SC_SPC_INV_FORMAT      0xa     /* Invalid Format */
 298 #define NVME_CQE_SC_SPC_FW_RESET        0xb     /* FW Application Reset Reqd */
 299 #define NVME_CQE_SC_SPC_INV_Q_DEL       0xc     /* Invalid Queue Deletion */
 300 #define NVME_CQE_SC_SPC_FEAT_SAVE       0xd     /* Feature Id Not Saveable */
 301 #define NVME_CQE_SC_SPC_FEAT_CHG        0xe     /* Feature Not Changeable */
 302 #define NVME_CQE_SC_SPC_FEAT_NS_SPEC    0xf     /* Feature Not Namespace Spec */
 303 #define NVME_CQE_SC_SPC_FW_NSSR         0x10    /* FW Application NSSR Reqd */
 304 
 305 /* NVMe completion status code (NVM command specific */
 306 #define NVME_CQE_SC_SPC_NVM_CNFL_ATTR   0x80    /* Conflicting Attributes */
 307 #define NVME_CQE_SC_SPC_NVM_INV_PROT    0x81    /* Invalid Protection */
 308 #define NVME_CQE_SC_SPC_NVM_READONLY    0x82    /* Write to Read Only Range */
 309 
 310 /* NVMe completion status code (data / metadata integrity) */
 311 #define NVME_CQE_SC_INT_NVM_WRITE       0x80    /* Write Fault */
 312 #define NVME_CQE_SC_INT_NVM_READ        0x81    /* Unrecovered Read Error */
 313 #define NVME_CQE_SC_INT_NVM_GUARD       0x82    /* Guard Check Error */
 314 #define NVME_CQE_SC_INT_NVM_APPL_TAG    0x83    /* Application Tag Check Err */
 315 #define NVME_CQE_SC_INT_NVM_REF_TAG     0x84    /* Reference Tag Check Err */
 316 #define NVME_CQE_SC_INT_NVM_COMPARE     0x85    /* Compare Failure */
 317 #define NVME_CQE_SC_INT_NVM_ACCESS      0x86    /* Access Denied */
 318 
 319 /*
 320  * NVMe Asynchronous Event Request
 321  */
 322 #define NVME_ASYNC_TYPE_ERROR           0x0     /* Error Status */
 323 #define NVME_ASYNC_TYPE_HEALTH          0x1     /* SMART/Health Status */
 324 #define NVME_ASYNC_TYPE_VENDOR          0x7     /* vendor specific */
 325 
 326 #define NVME_ASYNC_ERROR_INV_SQ         0x0     /* Invalid Submission Queue */
 327 #define NVME_ASYNC_ERROR_INV_DBL        0x1     /* Invalid Doorbell Write */
 328 #define NVME_ASYNC_ERROR_DIAGFAIL       0x2     /* Diagnostic Failure */
 329 #define NVME_ASYNC_ERROR_PERSISTENT     0x3     /* Persistent Internal Error */
 330 #define NVME_ASYNC_ERROR_TRANSIENT      0x4     /* Transient Internal Error */
 331 #define NVME_ASYNC_ERROR_FW_LOAD        0x5     /* Firmware Image Load Error */
 332 
 333 #define NVME_ASYNC_HEALTH_RELIABILITY   0x0     /* Device Reliability */
 334 #define NVME_ASYNC_HEALTH_TEMPERATURE   0x1     /* Temp. Above Threshold */
 335 #define NVME_ASYNC_HEALTH_SPARE         0x2     /* Spare Below Threshold */
 336 
 337 typedef union {
 338         struct {
 339                 uint8_t ae_type:3;              /* Asynchronous Event Type */
 340                 uint8_t ae_rsvd1:5;
 341                 uint8_t ae_info;                /* Asynchronous Event Info */
 342                 uint8_t ae_logpage;             /* Associated Log Page */
 343                 uint8_t ae_rsvd2;
 344         } b;
 345         uint32_t r;
 346 } nvme_async_event_t;
 347 
 348 /*
 349  * NVMe Create Completion/Submission Queue
 350  */
 351 typedef union {
 352         struct {
 353                 uint16_t q_qid;                 /* Queue Identifier */
 354                 uint16_t q_qsize;               /* Queue Size */
 355         } b;
 356         uint32_t r;
 357 } nvme_create_queue_dw10_t;
 358 
 359 typedef union {
 360         struct {
 361                 uint16_t cq_pc:1;               /* Physically Contiguous */
 362                 uint16_t cq_ien:1;              /* Interrupts Enabled */
 363                 uint16_t cq_rsvd:14;
 364                 uint16_t cq_iv;                 /* Interrupt Vector */
 365         } b;
 366         uint32_t r;
 367 } nvme_create_cq_dw11_t;
 368 
 369 typedef union {
 370         struct {
 371                 uint16_t sq_pc:1;               /* Physically Contiguous */
 372                 uint16_t sq_qprio:2;            /* Queue Priority */
 373                 uint16_t sq_rsvd:13;
 374                 uint16_t sq_cqid;               /* Completion Queue ID */
 375         } b;
 376         uint32_t r;
 377 } nvme_create_sq_dw11_t;
 378 
 379 /*
 380  * NVMe Identify
 381  */
 382 
 383 /* NVMe Identify parameters (cdw10) */
 384 #define NVME_IDENTIFY_NSID      0x0     /* Identify Namespace */
 385 #define NVME_IDENTIFY_CTRL      0x1     /* Identify Controller */
 386 #define NVME_IDENTIFY_LIST      0x2     /* Identify List Namespaces */
 387 
 388 
 389 /*
 390  * NVMe Abort Command
 391  */
 392 typedef union {
 393         struct {
 394                 uint16_t ac_sqid;       /* Submission Queue ID */
 395                 uint16_t ac_cid;        /* Command ID */
 396         } b;
 397         uint32_t r;
 398 } nvme_abort_cmd_t;
 399 
 400 
 401 /*
 402  * NVMe Get Log Page
 403  */
 404 typedef union {
 405         struct {
 406                 uint8_t lp_lid;         /* Log Page Identifier */
 407                 uint8_t lp_rsvd1;
 408                 uint16_t lp_numd:12;    /* Number of Dwords */
 409                 uint16_t lp_rsvd2:4;
 410         } b;
 411         uint32_t r;
 412 } nvme_getlogpage_t;
 413 
 414 
 415 #ifdef __cplusplus
 416 }
 417 #endif
 418 
 419 #pragma pack() /* pack(1) */
 420 
 421 #endif /* _NVME_REG_H */