nvmectl.c revision 1.5 1 1.5 jdolecek /* $NetBSD: nvmectl.c,v 1.5 2018/03/17 11:07:26 jdolecek Exp $ */
2 1.1 nonaka
3 1.1 nonaka /*-
4 1.1 nonaka * Copyright (C) 2012-2013 Intel Corporation
5 1.1 nonaka * All rights reserved.
6 1.1 nonaka *
7 1.1 nonaka * Redistribution and use in source and binary forms, with or without
8 1.1 nonaka * modification, are permitted provided that the following conditions
9 1.1 nonaka * are met:
10 1.1 nonaka * 1. Redistributions of source code must retain the above copyright
11 1.1 nonaka * notice, this list of conditions and the following disclaimer.
12 1.1 nonaka * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 nonaka * notice, this list of conditions and the following disclaimer in the
14 1.1 nonaka * documentation and/or other materials provided with the distribution.
15 1.1 nonaka *
16 1.1 nonaka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 1.1 nonaka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1 nonaka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1 nonaka * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 1.1 nonaka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 1.1 nonaka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 1.1 nonaka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1 nonaka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 1.1 nonaka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 nonaka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 nonaka * SUCH DAMAGE.
27 1.1 nonaka */
28 1.1 nonaka
29 1.1 nonaka #include <sys/cdefs.h>
30 1.1 nonaka #ifndef lint
31 1.5 jdolecek __RCSID("$NetBSD: nvmectl.c,v 1.5 2018/03/17 11:07:26 jdolecek Exp $");
32 1.1 nonaka #if 0
33 1.3 nonaka __FBSDID("$FreeBSD: head/sbin/nvmecontrol/nvmecontrol.c 314229 2017-02-25 00:09:12Z imp $");
34 1.1 nonaka #endif
35 1.1 nonaka #endif
36 1.1 nonaka
37 1.1 nonaka #include <sys/param.h>
38 1.1 nonaka #include <sys/ioccom.h>
39 1.1 nonaka #include <sys/stat.h>
40 1.1 nonaka
41 1.1 nonaka #include <ctype.h>
42 1.1 nonaka #include <err.h>
43 1.1 nonaka #include <errno.h>
44 1.1 nonaka #include <fcntl.h>
45 1.1 nonaka #include <paths.h>
46 1.1 nonaka #include <stdbool.h>
47 1.1 nonaka #include <stddef.h>
48 1.1 nonaka #include <stdio.h>
49 1.1 nonaka #include <stdlib.h>
50 1.1 nonaka #include <string.h>
51 1.1 nonaka #include <unistd.h>
52 1.1 nonaka
53 1.1 nonaka #include "nvmectl.h"
54 1.1 nonaka
55 1.5 jdolecek static const struct nvme_function funcs[] = {
56 1.1 nonaka {"devlist", devlist, DEVLIST_USAGE},
57 1.1 nonaka {"identify", identify, IDENTIFY_USAGE},
58 1.1 nonaka #ifdef PERFTEST_USAGE
59 1.1 nonaka {"perftest", perftest, PERFTEST_USAGE},
60 1.1 nonaka #endif
61 1.1 nonaka #ifdef RESET_USAGE
62 1.1 nonaka {"reset", reset, RESET_USAGE},
63 1.1 nonaka #endif
64 1.1 nonaka {"logpage", logpage, LOGPAGE_USAGE},
65 1.1 nonaka #ifdef FIRMWARE_USAGE
66 1.1 nonaka {"firmware", firmware, FIRMWARE_USAGE},
67 1.1 nonaka #endif
68 1.1 nonaka {"power", power, POWER_USAGE},
69 1.3 nonaka {"wdc", wdc, WDC_USAGE},
70 1.1 nonaka {NULL, NULL, NULL},
71 1.1 nonaka };
72 1.1 nonaka
73 1.4 christos static __dead void
74 1.5 jdolecek gen_usage(const struct nvme_function *f)
75 1.1 nonaka {
76 1.1 nonaka
77 1.1 nonaka fprintf(stderr, "usage:\n");
78 1.1 nonaka while (f->name != NULL) {
79 1.5 jdolecek fprintf(stderr, "\t%s %s", getprogname(), f->usage);
80 1.1 nonaka f++;
81 1.1 nonaka }
82 1.1 nonaka exit(1);
83 1.1 nonaka }
84 1.1 nonaka
85 1.4 christos __dead void
86 1.5 jdolecek dispatch(int argc, char *argv[], const struct nvme_function *tbl)
87 1.3 nonaka {
88 1.5 jdolecek const struct nvme_function *f = tbl;
89 1.3 nonaka
90 1.4 christos if (argv[1] == NULL)
91 1.3 nonaka gen_usage(tbl);
92 1.3 nonaka
93 1.3 nonaka while (f->name != NULL) {
94 1.3 nonaka if (strcmp(argv[1], f->name) == 0)
95 1.3 nonaka f->fn(argc-1, &argv[1]);
96 1.3 nonaka f++;
97 1.3 nonaka }
98 1.3 nonaka
99 1.3 nonaka fprintf(stderr, "Unknown command: %s\n", argv[1]);
100 1.3 nonaka gen_usage(tbl);
101 1.3 nonaka }
102 1.3 nonaka
103 1.1 nonaka static void
104 1.1 nonaka print_bytes(void *data, uint32_t length)
105 1.1 nonaka {
106 1.1 nonaka uint32_t i, j;
107 1.1 nonaka uint8_t *p, *end;
108 1.1 nonaka
109 1.1 nonaka end = (uint8_t *)data + length;
110 1.1 nonaka
111 1.1 nonaka for (i = 0; i < length; i++) {
112 1.1 nonaka p = (uint8_t *)data + (i*16);
113 1.1 nonaka printf("%03x: ", i*16);
114 1.1 nonaka for (j = 0; j < 16 && p < end; j++)
115 1.1 nonaka printf("%02x ", *p++);
116 1.1 nonaka if (p >= end)
117 1.1 nonaka break;
118 1.1 nonaka printf("\n");
119 1.1 nonaka }
120 1.1 nonaka printf("\n");
121 1.1 nonaka }
122 1.1 nonaka
123 1.1 nonaka static void
124 1.1 nonaka print_dwords(void *data, uint32_t length)
125 1.1 nonaka {
126 1.1 nonaka uint32_t *p;
127 1.1 nonaka uint32_t i, j;
128 1.1 nonaka
129 1.1 nonaka p = (uint32_t *)data;
130 1.1 nonaka length /= sizeof(uint32_t);
131 1.1 nonaka
132 1.1 nonaka for (i = 0; i < length; i+=8) {
133 1.1 nonaka printf("%03x: ", i*4);
134 1.1 nonaka for (j = 0; j < 8; j++)
135 1.1 nonaka printf("%08x ", p[i+j]);
136 1.1 nonaka printf("\n");
137 1.1 nonaka }
138 1.1 nonaka
139 1.1 nonaka printf("\n");
140 1.1 nonaka }
141 1.1 nonaka
142 1.1 nonaka void
143 1.1 nonaka print_hex(void *data, uint32_t length)
144 1.1 nonaka {
145 1.1 nonaka if (length >= sizeof(uint32_t) || length % sizeof(uint32_t) == 0)
146 1.1 nonaka print_dwords(data, length);
147 1.1 nonaka else
148 1.1 nonaka print_bytes(data, length);
149 1.1 nonaka }
150 1.1 nonaka
151 1.1 nonaka void
152 1.1 nonaka read_controller_data(int fd, struct nvm_identify_controller *cdata)
153 1.1 nonaka {
154 1.1 nonaka struct nvme_pt_command pt;
155 1.1 nonaka
156 1.1 nonaka memset(&pt, 0, sizeof(pt));
157 1.1 nonaka pt.cmd.opcode = NVM_ADMIN_IDENTIFY;
158 1.1 nonaka pt.cmd.cdw10 = 1;
159 1.1 nonaka pt.buf = cdata;
160 1.1 nonaka pt.len = sizeof(*cdata);
161 1.1 nonaka pt.is_read = 1;
162 1.1 nonaka
163 1.1 nonaka if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
164 1.1 nonaka err(1, "identify request failed");
165 1.1 nonaka
166 1.1 nonaka if (nvme_completion_is_error(&pt.cpl))
167 1.1 nonaka errx(1, "identify request returned error");
168 1.1 nonaka }
169 1.1 nonaka
170 1.1 nonaka void
171 1.1 nonaka read_namespace_data(int fd, int nsid, struct nvm_identify_namespace *nsdata)
172 1.1 nonaka {
173 1.1 nonaka struct nvme_pt_command pt;
174 1.1 nonaka
175 1.1 nonaka memset(&pt, 0, sizeof(pt));
176 1.1 nonaka pt.cmd.opcode = NVM_ADMIN_IDENTIFY;
177 1.1 nonaka pt.cmd.nsid = nsid;
178 1.1 nonaka pt.buf = nsdata;
179 1.1 nonaka pt.len = sizeof(*nsdata);
180 1.1 nonaka pt.is_read = 1;
181 1.1 nonaka
182 1.1 nonaka if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
183 1.1 nonaka err(1, "identify request failed");
184 1.1 nonaka
185 1.1 nonaka if (nvme_completion_is_error(&pt.cpl))
186 1.1 nonaka errx(1, "identify request returned error");
187 1.1 nonaka }
188 1.1 nonaka
189 1.1 nonaka int
190 1.1 nonaka open_dev(const char *str, int *fd, int show_error, int exit_on_error)
191 1.1 nonaka {
192 1.1 nonaka char full_path[64];
193 1.1 nonaka
194 1.1 nonaka if (!strnstr(str, NVME_CTRLR_PREFIX, strlen(NVME_CTRLR_PREFIX))) {
195 1.1 nonaka if (show_error)
196 1.1 nonaka warnx("controller/namespace ids must begin with '%s'",
197 1.1 nonaka NVME_CTRLR_PREFIX);
198 1.1 nonaka if (exit_on_error)
199 1.1 nonaka exit(1);
200 1.1 nonaka else
201 1.1 nonaka return (EINVAL);
202 1.1 nonaka }
203 1.1 nonaka
204 1.1 nonaka snprintf(full_path, sizeof(full_path), _PATH_DEV"%s", str);
205 1.1 nonaka *fd = open(full_path, O_RDWR);
206 1.1 nonaka if (*fd < 0) {
207 1.1 nonaka if (show_error)
208 1.1 nonaka warn("could not open %s", full_path);
209 1.1 nonaka if (exit_on_error)
210 1.1 nonaka exit(1);
211 1.1 nonaka else
212 1.1 nonaka return (errno);
213 1.1 nonaka }
214 1.1 nonaka
215 1.1 nonaka return (0);
216 1.1 nonaka }
217 1.1 nonaka
218 1.1 nonaka void
219 1.1 nonaka parse_ns_str(const char *ns_str, char *ctrlr_str, int *nsid)
220 1.1 nonaka {
221 1.1 nonaka char *nsloc;
222 1.1 nonaka
223 1.1 nonaka /*
224 1.1 nonaka * Pull the namespace id from the string. +2 skips past the "ns" part
225 1.1 nonaka * of the string. Don't search past 10 characters into the string,
226 1.1 nonaka * otherwise we know it is malformed.
227 1.1 nonaka */
228 1.1 nonaka nsloc = strnstr(ns_str, NVME_NS_PREFIX, 10);
229 1.1 nonaka if (nsloc != NULL)
230 1.1 nonaka *nsid = strtol(nsloc + 2, NULL, 10);
231 1.1 nonaka if (nsloc == NULL || (*nsid == 0 && errno != 0))
232 1.1 nonaka errx(1, "invalid namespace ID '%s'", ns_str);
233 1.1 nonaka
234 1.1 nonaka /*
235 1.1 nonaka * The controller string will include only the nvmX part of the
236 1.1 nonaka * nvmeXnsY string.
237 1.1 nonaka */
238 1.1 nonaka snprintf(ctrlr_str, nsloc - ns_str + 1, "%s", ns_str);
239 1.1 nonaka }
240 1.1 nonaka
241 1.1 nonaka void
242 1.1 nonaka nvme_strvis(u_char *dst, int dlen, const u_char *src, int slen)
243 1.1 nonaka {
244 1.1 nonaka #define STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377')
245 1.1 nonaka /* Trim leading and trailing blanks and NULs. */
246 1.1 nonaka while (slen > 0 && STRVIS_ISWHITE(src[0]))
247 1.1 nonaka ++src, --slen;
248 1.1 nonaka while (slen > 0 && STRVIS_ISWHITE(src[slen - 1]))
249 1.1 nonaka --slen;
250 1.1 nonaka
251 1.1 nonaka while (slen > 0) {
252 1.1 nonaka if (*src < 0x20 || *src >= 0x80) {
253 1.1 nonaka /* non-printable characters */
254 1.1 nonaka dlen -= 4;
255 1.1 nonaka if (dlen < 1)
256 1.1 nonaka break;
257 1.1 nonaka *dst++ = '\\';
258 1.1 nonaka *dst++ = ((*src & 0300) >> 6) + '0';
259 1.1 nonaka *dst++ = ((*src & 0070) >> 3) + '0';
260 1.1 nonaka *dst++ = ((*src & 0007) >> 0) + '0';
261 1.1 nonaka } else if (*src == '\\') {
262 1.1 nonaka /* quote characters */
263 1.1 nonaka dlen -= 2;
264 1.1 nonaka if (dlen < 1)
265 1.1 nonaka break;
266 1.1 nonaka *dst++ = '\\';
267 1.1 nonaka *dst++ = '\\';
268 1.1 nonaka } else {
269 1.1 nonaka /* normal characters */
270 1.1 nonaka if (--dlen < 1)
271 1.1 nonaka break;
272 1.1 nonaka *dst++ = *src;
273 1.1 nonaka }
274 1.1 nonaka ++src, --slen;
275 1.1 nonaka }
276 1.1 nonaka
277 1.1 nonaka *dst++ = 0;
278 1.1 nonaka }
279 1.1 nonaka
280 1.1 nonaka int
281 1.1 nonaka main(int argc, char *argv[])
282 1.1 nonaka {
283 1.5 jdolecek setprogname(argv[0]);
284 1.1 nonaka
285 1.1 nonaka if (argc < 2)
286 1.3 nonaka gen_usage(funcs);
287 1.1 nonaka
288 1.3 nonaka dispatch(argc, argv, funcs);
289 1.1 nonaka
290 1.1 nonaka return (0);
291 1.1 nonaka }
292