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.
14 */
15
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <stropts.h>
21 #include <err.h>
22 #include <libdevinfo.h>
23 #include <sys/nvme.h>
24 #include <assert.h>
25
26 #include "nvmeadm.h"
27
28
29 static boolean_t
nvme_ioctl(int fd,int ioc,size_t * bufsize,void ** buf,uint64_t arg,uint64_t * res)30 nvme_ioctl(int fd, int ioc, size_t *bufsize, void **buf, uint64_t arg,
31 uint64_t *res)
32 {
33 nvme_ioctl_t nioc = { 0 };
34
35 if (buf != NULL)
36 *buf = NULL;
37
38 if (res != NULL)
39 *res = ~0ULL;
40
41 if (bufsize != NULL && *bufsize != 0) {
42 assert(buf != NULL);
43
44 if ((nioc.n_buf = (uintptr_t)calloc(*bufsize, 1)) == NULL)
45 err(-1, "nvme_ioctl()");
46
47 nioc.n_len = *bufsize;
48 }
49
50 nioc.n_arg = arg;
51
52 if (ioctl(fd, ioc, &nioc) != 0) {
53 if (debug)
54 warn("nvme_ioctl()");
55 if (nioc.n_buf != 0)
56 free((void *)nioc.n_buf);
57
58 return (B_FALSE);
59 }
60
61 if (res != NULL)
62 *res = nioc.n_arg;
63
64 if (bufsize != NULL)
65 *bufsize = nioc.n_len;
66
67 if (buf != NULL)
68 *buf = (void *)nioc.n_buf;
69
70 return (B_TRUE);
71 }
72
73 nvme_capabilities_t *
nvme_capabilities(int fd)74 nvme_capabilities(int fd)
75 {
76 void *cap = NULL;
77 size_t bufsize = sizeof (nvme_capabilities_t);
78
79 (void) nvme_ioctl(fd, NVME_IOC_CAPABILITIES, &bufsize, &cap, 0, NULL);
80
81 return (cap);
82 }
83
84 nvme_version_t *
nvme_version(int fd)85 nvme_version(int fd)
86 {
87 void *vs = NULL;
88 size_t bufsize = sizeof (nvme_version_t);
89
90 (void) nvme_ioctl(fd, NVME_IOC_VERSION, &bufsize, &vs, 0, NULL);
91
92 return (vs);
93 }
94
95 nvme_identify_ctrl_t *
nvme_identify_ctrl(int fd)96 nvme_identify_ctrl(int fd)
97 {
98 void *idctl = NULL;
99 size_t bufsize = NVME_IDENTIFY_BUFSIZE;
100
101 (void) nvme_ioctl(fd, NVME_IOC_IDENTIFY_CTRL, &bufsize, &idctl, 0,
102 NULL);
103
104 return (idctl);
105 }
106
107 nvme_identify_nsid_t *
nvme_identify_nsid(int fd)108 nvme_identify_nsid(int fd)
109 {
110 void *idns = NULL;
111 size_t bufsize = NVME_IDENTIFY_BUFSIZE;
112
113 (void) nvme_ioctl(fd, NVME_IOC_IDENTIFY_NSID, &bufsize, &idns, 0, NULL);
114
115 return (idns);
116 }
117
118 void *
nvme_get_logpage(int fd,uint8_t logpage,size_t * bufsize)119 nvme_get_logpage(int fd, uint8_t logpage, size_t *bufsize)
120 {
121 void *buf = NULL;
122
123 (void) nvme_ioctl(fd, NVME_IOC_GET_LOGPAGE, bufsize, &buf, logpage,
124 NULL);
125
126 return (buf);
127 }
128
129 boolean_t
nvme_get_feature(int fd,uint8_t feature,uint32_t arg,uint64_t * res,size_t * bufsize,void ** buf)130 nvme_get_feature(int fd, uint8_t feature, uint32_t arg, uint64_t *res,
131 size_t *bufsize, void **buf)
132 {
133 return (nvme_ioctl(fd, NVME_IOC_GET_FEATURES, bufsize, buf,
134 (uint64_t)feature << 32 | arg, res));
135 }
136
137 int
nvme_intr_cnt(int fd)138 nvme_intr_cnt(int fd)
139 {
140 uint64_t res = 0;
141
142 (void) nvme_ioctl(fd, NVME_IOC_INTR_CNT, NULL, NULL, 0, &res);
143 return ((int)res);
144 }
145
146 boolean_t
nvme_format_nvm(int fd,uint8_t lbaf,uint8_t ses)147 nvme_format_nvm(int fd, uint8_t lbaf, uint8_t ses)
148 {
149 nvme_format_nvm_t frmt = { 0 };
150
151 frmt.b.fm_lbaf = lbaf & 0xf;
152 frmt.b.fm_ses = ses & 0x7;
153
154 return (nvme_ioctl(fd, NVME_IOC_FORMAT, NULL, NULL, frmt.r, NULL));
155 }
156
157 boolean_t
nvme_detach(int fd)158 nvme_detach(int fd)
159 {
160 return (nvme_ioctl(fd, NVME_IOC_DETACH, NULL, NULL, 0, NULL));
161 }
162
163 boolean_t
nvme_attach(int fd)164 nvme_attach(int fd)
165 {
166 return (nvme_ioctl(fd, NVME_IOC_ATTACH, NULL, NULL, 0, NULL));
167 }
168
169 int
nvme_open(di_minor_t minor)170 nvme_open(di_minor_t minor)
171 {
172 char *devpath, *path;
173 int fd;
174
175 if ((devpath = di_devfs_minor_path(minor)) == NULL)
176 err(-1, "nvme_open()");
177
178 if (asprintf(&path, "/devices%s", devpath) < 0) {
179 di_devfs_path_free(devpath);
180 err(-1, "nvme_open()");
181 }
182
183 di_devfs_path_free(devpath);
184
185 fd = open(path, O_RDWR);
186 free(path);
187
188 if (fd < 0) {
189 if (debug)
190 warn("nvme_open(%s)", path);
191 return (-1);
192 }
193
194 return (fd);
195 }
196
197 void
nvme_close(int fd)198 nvme_close(int fd)
199 {
200 (void) close(fd);
201 }
202