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