1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: Helpers for NVMe uring passthrough commands
4 */
5 #ifndef LIBURING_NVME_H
6 #define LIBURING_NVME_H
7
8 #ifdef __cplusplus
9 extern "C" {
10 #endif
11
12 #include <sys/ioctl.h>
13 #include <linux/nvme_ioctl.h>
14
15 /*
16 * If the uapi headers installed on the system lacks nvme uring command
17 * support, use the local version to prevent compilation issues.
18 */
19 #ifndef CONFIG_HAVE_NVME_URING
20 struct nvme_uring_cmd {
21 __u8 opcode;
22 __u8 flags;
23 __u16 rsvd1;
24 __u32 nsid;
25 __u32 cdw2;
26 __u32 cdw3;
27 __u64 metadata;
28 __u64 addr;
29 __u32 metadata_len;
30 __u32 data_len;
31 __u32 cdw10;
32 __u32 cdw11;
33 __u32 cdw12;
34 __u32 cdw13;
35 __u32 cdw14;
36 __u32 cdw15;
37 __u32 timeout_ms;
38 __u32 rsvd2;
39 };
40
41 #define NVME_URING_CMD_IO _IOWR('N', 0x80, struct nvme_uring_cmd)
42 #define NVME_URING_CMD_IO_VEC _IOWR('N', 0x81, struct nvme_uring_cmd)
43 #endif /* CONFIG_HAVE_NVME_URING */
44
45 #define NVME_DEFAULT_IOCTL_TIMEOUT 0
46 #define NVME_IDENTIFY_DATA_SIZE 4096
47 #define NVME_IDENTIFY_CSI_SHIFT 24
48 #define NVME_IDENTIFY_CNS_NS 0
49 #define NVME_CSI_NVM 0
50
51 enum nvme_admin_opcode {
52 nvme_admin_identify = 0x06,
53 };
54
55 enum nvme_io_opcode {
56 nvme_cmd_write = 0x01,
57 nvme_cmd_read = 0x02,
58 };
59
60 static int nsid;
61 static __u32 lba_shift;
62
63 struct nvme_lbaf {
64 __le16 ms;
65 __u8 ds;
66 __u8 rp;
67 };
68
69 struct nvme_id_ns {
70 __le64 nsze;
71 __le64 ncap;
72 __le64 nuse;
73 __u8 nsfeat;
74 __u8 nlbaf;
75 __u8 flbas;
76 __u8 mc;
77 __u8 dpc;
78 __u8 dps;
79 __u8 nmic;
80 __u8 rescap;
81 __u8 fpi;
82 __u8 dlfeat;
83 __le16 nawun;
84 __le16 nawupf;
85 __le16 nacwu;
86 __le16 nabsn;
87 __le16 nabo;
88 __le16 nabspf;
89 __le16 noiob;
90 __u8 nvmcap[16];
91 __le16 npwg;
92 __le16 npwa;
93 __le16 npdg;
94 __le16 npda;
95 __le16 nows;
96 __le16 mssrl;
97 __le32 mcl;
98 __u8 msrc;
99 __u8 rsvd81[11];
100 __le32 anagrpid;
101 __u8 rsvd96[3];
102 __u8 nsattr;
103 __le16 nvmsetid;
104 __le16 endgid;
105 __u8 nguid[16];
106 __u8 eui64[8];
107 struct nvme_lbaf lbaf[16];
108 __u8 rsvd192[192];
109 __u8 vs[3712];
110 };
111
ilog2(uint32_t i)112 static inline int ilog2(uint32_t i)
113 {
114 int log = -1;
115
116 while (i) {
117 i >>= 1;
118 log++;
119 }
120 return log;
121 }
122
123 __attribute__((__unused__))
nvme_get_info(const char * file)124 static int nvme_get_info(const char *file)
125 {
126 struct nvme_id_ns ns;
127 int fd, err;
128 __u32 lba_size;
129
130 fd = open(file, O_RDONLY);
131 if (fd < 0) {
132 perror("file open");
133 return -errno;
134 }
135
136 nsid = ioctl(fd, NVME_IOCTL_ID);
137 if (nsid < 0) {
138 close(fd);
139 return -errno;
140 }
141
142 struct nvme_passthru_cmd cmd = {
143 .opcode = nvme_admin_identify,
144 .nsid = nsid,
145 .addr = (__u64)(uintptr_t)&ns,
146 .data_len = NVME_IDENTIFY_DATA_SIZE,
147 .cdw10 = NVME_IDENTIFY_CNS_NS,
148 .cdw11 = NVME_CSI_NVM << NVME_IDENTIFY_CSI_SHIFT,
149 .timeout_ms = NVME_DEFAULT_IOCTL_TIMEOUT,
150 };
151
152 err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
153 if (err) {
154 close(fd);
155 return err;
156 }
157
158 lba_size = 1 << ns.lbaf[(ns.flbas & 0x0f)].ds;
159 lba_shift = ilog2(lba_size);
160
161 close(fd);
162 return 0;
163 }
164
165 #ifdef __cplusplus
166 }
167 #endif
168
169 #endif
170