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