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