• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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