Home | History | Annotate | Download | only in include
      1 #ifndef SG_PT_NVME_H
      2 #define SG_PT_NVME_H
      3 
      4 /*
      5  * Copyright (c) 2017-2018 Douglas Gilbert.
      6  * All rights reserved.
      7  * Use of this source code is governed by a BSD-style
      8  * license that can be found in the BSD_LICENSE file.
      9  */
     10 
     11 #include <stdint.h>
     12 #include <stdbool.h>
     13 
     14 #ifdef __cplusplus
     15 extern "C" {
     16 #endif
     17 
     18 /* structures copied and slightly modified from <linux/nvme_ioctl.h> which
     19  * is Copyright (c) 2011-2014, Intel Corporation.  */
     20 
     21 
     22 /* Note that the command input structure is in (packed) "cpu" format. That
     23  * means, for example, if the CPU is little endian (most are) then so is the
     24  * structure. However what comes out in the data-in buffer (e.g. for the
     25  * Admin Identify command response) is almost all little endian following ATA
     26  * (but no SCSI and IP which are big endian) and Intel's preference. There
     27  * are exceptions, for example the EUI-64 identifiers in the Admin Identify
     28  * response are big endian.
     29  *
     30  * Code online (e.g. nvme-cli at github.com) seems to like packed strcutures,
     31  * the author prefers byte offset plus a range of unaligned integer builders
     32  * such as those in sg_unaligned.h .
     33  */
     34 
     35 #ifdef __GNUC__
     36 #ifndef __clang__
     37   struct __attribute__((__packed__)) sg_nvme_user_io
     38 #else
     39   struct sg_nvme_user_io
     40 #endif
     41 #else
     42 struct sg_nvme_user_io
     43 #endif
     44 {
     45         uint8_t opcode;
     46         uint8_t flags;
     47         uint16_t control;
     48         uint16_t nblocks;
     49         uint16_t rsvd;
     50         uint64_t metadata;
     51         uint64_t addr;
     52         uint64_t slba;
     53         uint32_t dsmgmt;
     54         uint32_t reftag;
     55         uint16_t apptag;
     56         uint16_t appmask;
     57 }
     58 #ifdef SG_LIB_FREEBSD
     59 __packed;
     60 #else
     61 ;
     62 #endif
     63 
     64 /* Using byte offsets and unaligned be/le copies safer than packed
     65  * structures. These are for sg_nvme_user_io . */
     66 #define SG_NVME_IO_OPCODE 0
     67 #define SG_NVME_IO_FLAGS 1
     68 #define SG_NVME_IO_CONTROL 2
     69 #define SG_NVME_IO_NBLOCKS 4
     70 #define SG_NVME_IO_RSVD 6
     71 #define SG_NVME_IO_METADATA 8
     72 #define SG_NVME_IO_ADDR 16
     73 #define SG_NVME_IO_SLBA 24
     74 #define SG_NVME_IO_DSMGMT 32
     75 #define SG_NVME_IO_REFTAG 36
     76 #define SG_NVME_IO_APPTAG 40
     77 #define SG_NVME_IO_APPMASK 42
     78 
     79 #ifdef __GNUC__
     80 #ifndef __clang__
     81   struct __attribute__((__packed__)) sg_nvme_passthru_cmd
     82 #else
     83   struct sg_nvme_passthru_cmd
     84 #endif
     85 #else
     86 struct sg_nvme_passthru_cmd
     87 #endif
     88 {
     89         uint8_t opcode;
     90         uint8_t flags;
     91         uint16_t rsvd1;
     92         uint32_t nsid;
     93         uint32_t cdw2;
     94         uint32_t cdw3;
     95         uint64_t metadata;
     96         uint64_t addr;
     97         uint32_t metadata_len;
     98         uint32_t data_len;
     99         uint32_t cdw10;
    100         uint32_t cdw11;
    101         uint32_t cdw12;
    102         uint32_t cdw13;
    103         uint32_t cdw14;
    104         uint32_t cdw15;
    105 #ifdef SG_LIB_LINUX
    106         uint32_t timeout_ms;
    107         uint32_t result;        /* out: DWord(0) from completion queue */
    108 #endif
    109 }
    110 #ifdef SG_LIB_FREEBSD
    111 __packed;
    112 #else
    113 ;
    114 #endif
    115 
    116 
    117 /* Using byte offsets and unaligned be/le copies safer than packed
    118  * structures. These are for sg_nvme_passthru_cmd . */
    119 #define SG_NVME_PT_OPCODE 0             /* length: 1 byte */
    120 #define SG_NVME_PT_FLAGS 1              /* length: 1 byte */
    121 #define SG_NVME_PT_RSVD1 2              /* length: 2 bytes */
    122 #define SG_NVME_PT_NSID 4               /* length: 4 bytes */
    123 #define SG_NVME_PT_CDW2 8               /* length: 4 bytes */
    124 #define SG_NVME_PT_CDW3 12              /* length: 4 bytes */
    125 #define SG_NVME_PT_METADATA 16          /* length: 8 bytes */
    126 #define SG_NVME_PT_ADDR 24              /* length: 8 bytes */
    127 #define SG_NVME_PT_METADATA_LEN 32      /* length: 4 bytes */
    128 #define SG_NVME_PT_DATA_LEN 36          /* length: 4 bytes */
    129 #define SG_NVME_PT_CDW10 40             /* length: 4 bytes */
    130 #define SG_NVME_PT_CDW11 44             /* length: 4 bytes */
    131 #define SG_NVME_PT_CDW12 48             /* length: 4 bytes */
    132 #define SG_NVME_PT_CDW13 52             /* length: 4 bytes */
    133 #define SG_NVME_PT_CDW14 56             /* length: 4 bytes */
    134 #define SG_NVME_PT_CDW15 60             /* length: 4 bytes */
    135 
    136 #ifdef SG_LIB_LINUX
    137 /* General references state that "all NVMe commands are 64 bytes long". If
    138  * so then the following are add-ons by Linux, go to the OS and not the
    139  * the NVMe device. */
    140 #define SG_NVME_PT_TIMEOUT_MS 64        /* length: 4 bytes */
    141 #define SG_NVME_PT_RESULT 68            /* length: 4 bytes */
    142 #endif
    143 
    144 /* Byte offset of Result and Status (plus phase bit) in CQ */
    145 #define SG_NVME_PT_CQ_RESULT 0          /* CDW0, length: 4 bytes */
    146 #define SG_NVME_PT_CQ_DW0 0             /* CDW0, length: 4 bytes */
    147 #define SG_NVME_PT_CQ_DW1 4             /* CDW1, length: 4 bytes */
    148 #define SG_NVME_PT_CQ_DW2 8             /* CDW2, length: 4 bytes */
    149 #define SG_NVME_PT_CQ_DW3 12            /* CDW3, length: 4 bytes */
    150 #define SG_NVME_PT_CQ_STATUS_P 14       /* CDW3 31:16, length: 2 bytes */
    151 
    152 
    153 /* Valid namespace IDs (nsid_s) range from 1 to 0xfffffffe, leaving: */
    154 #define SG_NVME_BROADCAST_NSID 0xffffffff       /* all namespaces */
    155 #define SG_NVME_CTL_NSID 0x0            /* the "controller's" namespace */
    156 
    157 /* Given the NVMe Identify Controller response and optionally the NVMe
    158  * Identify Namespace response (NULL otherwise), generate the SCSI VPD
    159  * page 0x83 (device identification) descriptor(s) in dop. Return the
    160  * number of bytes written which will not exceed max_do_len. Probably use
    161  * Peripheral Device Type (pdt) of 0 (disk) for don't know. Transport
    162  * protocol (tproto) should be -1 if not known, else SCSI value.
    163  * N.B. Does not write total VPD page length into dop[2:3] . */
    164 int sg_make_vpd_devid_for_nvme(const uint8_t * nvme_id_ctl_p,
    165                                const uint8_t * nvme_id_ns_p, int pdt,
    166                                int tproto, uint8_t * dop, int max_do_len);
    167 
    168 #ifdef __cplusplus
    169 }
    170 #endif
    171 
    172 #endif          /* SG_PT_NVME_H */
    173