1 | #include <machine/rtems-bsd-user-space.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD |
---|
5 | * |
---|
6 | * Copyright (C) 2019 Alexander Motin <mav@FreeBSD.org> |
---|
7 | * |
---|
8 | * Redistribution and use in source and binary forms, with or without |
---|
9 | * modification, are permitted provided that the following conditions |
---|
10 | * are met: |
---|
11 | * 1. Redistributions of source code must retain the above copyright |
---|
12 | * notice, this list of conditions and the following disclaimer, |
---|
13 | * without modification, immediately at the beginning of the file. |
---|
14 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
15 | * notice, this list of conditions and the following disclaimer in the |
---|
16 | * documentation and/or other materials provided with the distribution. |
---|
17 | * |
---|
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
---|
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
28 | */ |
---|
29 | |
---|
30 | #ifdef __rtems__ |
---|
31 | #include <machine/rtems-bsd-program.h> |
---|
32 | #endif /* __rtems__ */ |
---|
33 | #include <sys/cdefs.h> |
---|
34 | __FBSDID("$FreeBSD$"); |
---|
35 | |
---|
36 | #include <sys/param.h> |
---|
37 | #include <sys/ioccom.h> |
---|
38 | |
---|
39 | #include <err.h> |
---|
40 | #include <fcntl.h> |
---|
41 | #include <stdbool.h> |
---|
42 | #include <stddef.h> |
---|
43 | #include <stdio.h> |
---|
44 | #include <stdlib.h> |
---|
45 | #include <string.h> |
---|
46 | #include <unistd.h> |
---|
47 | |
---|
48 | #include "nvmecontrol.h" |
---|
49 | |
---|
50 | /* Tables for command line parsing */ |
---|
51 | |
---|
52 | static cmd_fn_t resv; |
---|
53 | static cmd_fn_t resvacquire; |
---|
54 | static cmd_fn_t resvregister; |
---|
55 | static cmd_fn_t resvrelease; |
---|
56 | static cmd_fn_t resvreport; |
---|
57 | |
---|
58 | #define NONE 0xffffffffu |
---|
59 | #define NONE64 0xffffffffffffffffull |
---|
60 | #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } |
---|
61 | #define OPT_END { NULL, 0, arg_none, NULL, NULL } |
---|
62 | |
---|
63 | static struct cmd resv_cmd = { |
---|
64 | .name = "resv", |
---|
65 | .fn = resv, |
---|
66 | .descr = "Reservation commands", |
---|
67 | .ctx_size = 0, |
---|
68 | .opts = NULL, |
---|
69 | .args = NULL, |
---|
70 | }; |
---|
71 | |
---|
72 | CMD_COMMAND(resv_cmd); |
---|
73 | |
---|
74 | static struct acquire_options { |
---|
75 | uint64_t crkey; |
---|
76 | uint64_t prkey; |
---|
77 | uint8_t rtype; |
---|
78 | uint8_t racqa; |
---|
79 | const char *dev; |
---|
80 | } acquire_opt = { |
---|
81 | .crkey = 0, |
---|
82 | .prkey = 0, |
---|
83 | .rtype = 0, |
---|
84 | .racqa = 0, |
---|
85 | .dev = NULL, |
---|
86 | }; |
---|
87 | |
---|
88 | static const struct opts acquire_opts[] = { |
---|
89 | OPT("crkey", 'c', arg_uint64, acquire_opt, crkey, |
---|
90 | "Current Reservation Key"), |
---|
91 | OPT("prkey", 'p', arg_uint64, acquire_opt, prkey, |
---|
92 | "Preempt Reservation Key"), |
---|
93 | OPT("rtype", 't', arg_uint8, acquire_opt, rtype, |
---|
94 | "Reservation Type"), |
---|
95 | OPT("racqa", 'a', arg_uint8, acquire_opt, racqa, |
---|
96 | "Acquire Action (0=acq, 1=pre, 2=pre+ab)"), |
---|
97 | { NULL, 0, arg_none, NULL, NULL } |
---|
98 | }; |
---|
99 | |
---|
100 | static const struct args acquire_args[] = { |
---|
101 | { arg_string, &acquire_opt.dev, "namespace-id" }, |
---|
102 | { arg_none, NULL, NULL }, |
---|
103 | }; |
---|
104 | |
---|
105 | static struct cmd acquire_cmd = { |
---|
106 | .name = "acquire", |
---|
107 | .fn = resvacquire, |
---|
108 | .descr = "Acquire/preempt reservation", |
---|
109 | .ctx_size = sizeof(acquire_opt), |
---|
110 | .opts = acquire_opts, |
---|
111 | .args = acquire_args, |
---|
112 | }; |
---|
113 | |
---|
114 | CMD_SUBCOMMAND(resv_cmd, acquire_cmd); |
---|
115 | |
---|
116 | static struct register_options { |
---|
117 | uint64_t crkey; |
---|
118 | uint64_t nrkey; |
---|
119 | uint8_t rrega; |
---|
120 | bool iekey; |
---|
121 | uint8_t cptpl; |
---|
122 | const char *dev; |
---|
123 | } register_opt = { |
---|
124 | .crkey = 0, |
---|
125 | .nrkey = 0, |
---|
126 | .rrega = 0, |
---|
127 | .iekey = false, |
---|
128 | .cptpl = 0, |
---|
129 | .dev = NULL, |
---|
130 | }; |
---|
131 | |
---|
132 | static const struct opts register_opts[] = { |
---|
133 | OPT("crkey", 'c', arg_uint64, register_opt, crkey, |
---|
134 | "Current Reservation Key"), |
---|
135 | OPT("nrkey", 'k', arg_uint64, register_opt, nrkey, |
---|
136 | "New Reservation Key"), |
---|
137 | OPT("rrega", 'r', arg_uint8, register_opt, rrega, |
---|
138 | "Register Action (0=reg, 1=unreg, 2=replace)"), |
---|
139 | OPT("iekey", 'i', arg_none, register_opt, iekey, |
---|
140 | "Ignore Existing Key"), |
---|
141 | OPT("cptpl", 'p', arg_uint8, register_opt, cptpl, |
---|
142 | "Change Persist Through Power Loss State"), |
---|
143 | { NULL, 0, arg_none, NULL, NULL } |
---|
144 | }; |
---|
145 | |
---|
146 | static const struct args register_args[] = { |
---|
147 | { arg_string, ®ister_opt.dev, "namespace-id" }, |
---|
148 | { arg_none, NULL, NULL }, |
---|
149 | }; |
---|
150 | |
---|
151 | static struct cmd register_cmd = { |
---|
152 | .name = "register", |
---|
153 | .fn = resvregister, |
---|
154 | .descr = "Register/unregister reservation", |
---|
155 | .ctx_size = sizeof(register_opt), |
---|
156 | .opts = register_opts, |
---|
157 | .args = register_args, |
---|
158 | }; |
---|
159 | |
---|
160 | CMD_SUBCOMMAND(resv_cmd, register_cmd); |
---|
161 | |
---|
162 | static struct release_options { |
---|
163 | uint64_t crkey; |
---|
164 | uint8_t rtype; |
---|
165 | uint8_t rrela; |
---|
166 | const char *dev; |
---|
167 | } release_opt = { |
---|
168 | .crkey = 0, |
---|
169 | .rtype = 0, |
---|
170 | .rrela = 0, |
---|
171 | .dev = NULL, |
---|
172 | }; |
---|
173 | |
---|
174 | static const struct opts release_opts[] = { |
---|
175 | OPT("crkey", 'c', arg_uint64, release_opt, crkey, |
---|
176 | "Current Reservation Key"), |
---|
177 | OPT("rtype", 't', arg_uint8, release_opt, rtype, |
---|
178 | "Reservation Type"), |
---|
179 | OPT("rrela", 'a', arg_uint8, release_opt, rrela, |
---|
180 | "Release Action (0=release, 1=clear)"), |
---|
181 | { NULL, 0, arg_none, NULL, NULL } |
---|
182 | }; |
---|
183 | |
---|
184 | static const struct args release_args[] = { |
---|
185 | { arg_string, &release_opt.dev, "namespace-id" }, |
---|
186 | { arg_none, NULL, NULL }, |
---|
187 | }; |
---|
188 | |
---|
189 | static struct cmd release_cmd = { |
---|
190 | .name = "release", |
---|
191 | .fn = resvrelease, |
---|
192 | .descr = "Release/clear reservation", |
---|
193 | .ctx_size = sizeof(release_opt), |
---|
194 | .opts = release_opts, |
---|
195 | .args = release_args, |
---|
196 | }; |
---|
197 | |
---|
198 | CMD_SUBCOMMAND(resv_cmd, release_cmd); |
---|
199 | |
---|
200 | static struct report_options { |
---|
201 | bool hex; |
---|
202 | bool verbose; |
---|
203 | bool eds; |
---|
204 | const char *dev; |
---|
205 | } report_opt = { |
---|
206 | .hex = false, |
---|
207 | .verbose = false, |
---|
208 | .eds = false, |
---|
209 | .dev = NULL, |
---|
210 | }; |
---|
211 | |
---|
212 | static const struct opts report_opts[] = { |
---|
213 | OPT("hex", 'x', arg_none, report_opt, hex, |
---|
214 | "Print reservation status in hex"), |
---|
215 | OPT("verbose", 'v', arg_none, report_opt, verbose, |
---|
216 | "More verbosity"), |
---|
217 | OPT("eds", 'e', arg_none, report_opt, eds, |
---|
218 | "Extended Data Structure"), |
---|
219 | { NULL, 0, arg_none, NULL, NULL } |
---|
220 | }; |
---|
221 | |
---|
222 | static const struct args report_args[] = { |
---|
223 | { arg_string, &report_opt.dev, "namespace-id" }, |
---|
224 | { arg_none, NULL, NULL }, |
---|
225 | }; |
---|
226 | |
---|
227 | static struct cmd report_cmd = { |
---|
228 | .name = "report", |
---|
229 | .fn = resvreport, |
---|
230 | .descr = "Print reservation status", |
---|
231 | .ctx_size = sizeof(report_opt), |
---|
232 | .opts = report_opts, |
---|
233 | .args = report_args, |
---|
234 | }; |
---|
235 | |
---|
236 | CMD_SUBCOMMAND(resv_cmd, report_cmd); |
---|
237 | |
---|
238 | /* handles NVME_OPC_RESERVATION_* NVM commands */ |
---|
239 | |
---|
240 | static void |
---|
241 | resvacquire(const struct cmd *f, int argc, char *argv[]) |
---|
242 | { |
---|
243 | struct nvme_pt_command pt; |
---|
244 | uint64_t data[2]; |
---|
245 | int fd; |
---|
246 | uint32_t nsid; |
---|
247 | |
---|
248 | if (arg_parse(argc, argv, f)) |
---|
249 | return; |
---|
250 | open_dev(acquire_opt.dev, &fd, 1, 1); |
---|
251 | get_nsid(fd, NULL, &nsid); |
---|
252 | if (nsid == 0) { |
---|
253 | fprintf(stderr, "This command require namespace-id\n"); |
---|
254 | arg_help(argc, argv, f); |
---|
255 | } |
---|
256 | |
---|
257 | data[0] = htole64(acquire_opt.crkey); |
---|
258 | data[1] = htole64(acquire_opt.prkey); |
---|
259 | |
---|
260 | memset(&pt, 0, sizeof(pt)); |
---|
261 | pt.cmd.opc = NVME_OPC_RESERVATION_ACQUIRE; |
---|
262 | pt.cmd.cdw10 = htole32((acquire_opt.racqa & 7) | |
---|
263 | (acquire_opt.rtype << 8)); |
---|
264 | pt.buf = &data; |
---|
265 | pt.len = sizeof(data); |
---|
266 | pt.is_read = 0; |
---|
267 | |
---|
268 | if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) |
---|
269 | err(1, "acquire request failed"); |
---|
270 | |
---|
271 | if (nvme_completion_is_error(&pt.cpl)) |
---|
272 | errx(1, "acquire request returned error"); |
---|
273 | |
---|
274 | close(fd); |
---|
275 | exit(0); |
---|
276 | } |
---|
277 | |
---|
278 | static void |
---|
279 | resvregister(const struct cmd *f, int argc, char *argv[]) |
---|
280 | { |
---|
281 | struct nvme_pt_command pt; |
---|
282 | uint64_t data[2]; |
---|
283 | int fd; |
---|
284 | uint32_t nsid; |
---|
285 | |
---|
286 | if (arg_parse(argc, argv, f)) |
---|
287 | return; |
---|
288 | open_dev(register_opt.dev, &fd, 1, 1); |
---|
289 | get_nsid(fd, NULL, &nsid); |
---|
290 | if (nsid == 0) { |
---|
291 | fprintf(stderr, "This command require namespace-id\n"); |
---|
292 | arg_help(argc, argv, f); |
---|
293 | } |
---|
294 | |
---|
295 | data[0] = htole64(register_opt.crkey); |
---|
296 | data[1] = htole64(register_opt.nrkey); |
---|
297 | |
---|
298 | memset(&pt, 0, sizeof(pt)); |
---|
299 | pt.cmd.opc = NVME_OPC_RESERVATION_REGISTER; |
---|
300 | pt.cmd.cdw10 = htole32((register_opt.rrega & 7) | |
---|
301 | (register_opt.iekey << 3) | (register_opt.cptpl << 30)); |
---|
302 | pt.buf = &data; |
---|
303 | pt.len = sizeof(data); |
---|
304 | pt.is_read = 0; |
---|
305 | |
---|
306 | if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) |
---|
307 | err(1, "register request failed"); |
---|
308 | |
---|
309 | if (nvme_completion_is_error(&pt.cpl)) |
---|
310 | errx(1, "register request returned error"); |
---|
311 | |
---|
312 | close(fd); |
---|
313 | exit(0); |
---|
314 | } |
---|
315 | |
---|
316 | static void |
---|
317 | resvrelease(const struct cmd *f, int argc, char *argv[]) |
---|
318 | { |
---|
319 | struct nvme_pt_command pt; |
---|
320 | uint64_t data[1]; |
---|
321 | int fd; |
---|
322 | uint32_t nsid; |
---|
323 | |
---|
324 | if (arg_parse(argc, argv, f)) |
---|
325 | return; |
---|
326 | open_dev(release_opt.dev, &fd, 1, 1); |
---|
327 | get_nsid(fd, NULL, &nsid); |
---|
328 | if (nsid == 0) { |
---|
329 | fprintf(stderr, "This command require namespace-id\n"); |
---|
330 | arg_help(argc, argv, f); |
---|
331 | } |
---|
332 | |
---|
333 | data[0] = htole64(release_opt.crkey); |
---|
334 | |
---|
335 | memset(&pt, 0, sizeof(pt)); |
---|
336 | pt.cmd.opc = NVME_OPC_RESERVATION_RELEASE; |
---|
337 | pt.cmd.cdw10 = htole32((release_opt.rrela & 7) | |
---|
338 | (release_opt.rtype << 8)); |
---|
339 | pt.buf = &data; |
---|
340 | pt.len = sizeof(data); |
---|
341 | pt.is_read = 0; |
---|
342 | |
---|
343 | if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) |
---|
344 | err(1, "release request failed"); |
---|
345 | |
---|
346 | if (nvme_completion_is_error(&pt.cpl)) |
---|
347 | errx(1, "release request returned error"); |
---|
348 | |
---|
349 | close(fd); |
---|
350 | exit(0); |
---|
351 | } |
---|
352 | |
---|
353 | static void |
---|
354 | resvreport(const struct cmd *f, int argc, char *argv[]) |
---|
355 | { |
---|
356 | struct nvme_pt_command pt; |
---|
357 | struct nvme_resv_status *s; |
---|
358 | struct nvme_resv_status_ext *e; |
---|
359 | uint8_t data[4096] __aligned(4); |
---|
360 | int fd; |
---|
361 | u_int i, n; |
---|
362 | uint32_t nsid; |
---|
363 | |
---|
364 | if (arg_parse(argc, argv, f)) |
---|
365 | return; |
---|
366 | open_dev(report_opt.dev, &fd, 1, 1); |
---|
367 | get_nsid(fd, NULL, &nsid); |
---|
368 | if (nsid == 0) { |
---|
369 | fprintf(stderr, "This command require namespace-id\n"); |
---|
370 | arg_help(argc, argv, f); |
---|
371 | } |
---|
372 | |
---|
373 | bzero(data, sizeof(data)); |
---|
374 | memset(&pt, 0, sizeof(pt)); |
---|
375 | pt.cmd.opc = NVME_OPC_RESERVATION_REPORT; |
---|
376 | pt.cmd.cdw10 = htole32(sizeof(data) / 4 - 1); |
---|
377 | pt.cmd.cdw11 = htole32(report_opt.eds); /* EDS */ |
---|
378 | pt.buf = &data; |
---|
379 | pt.len = sizeof(data); |
---|
380 | pt.is_read = 1; |
---|
381 | |
---|
382 | if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) |
---|
383 | err(1, "report request failed"); |
---|
384 | |
---|
385 | if (nvme_completion_is_error(&pt.cpl)) |
---|
386 | errx(1, "report request returned error"); |
---|
387 | |
---|
388 | close(fd); |
---|
389 | |
---|
390 | if (report_opt.eds) |
---|
391 | nvme_resv_status_ext_swapbytes((void *)data, sizeof(data)); |
---|
392 | else |
---|
393 | nvme_resv_status_swapbytes((void *)data, sizeof(data)); |
---|
394 | |
---|
395 | if (report_opt.hex) { |
---|
396 | i = sizeof(data); |
---|
397 | if (!report_opt.verbose) { |
---|
398 | for (; i > 64; i--) { |
---|
399 | if (data[i - 1] != 0) |
---|
400 | break; |
---|
401 | } |
---|
402 | } |
---|
403 | print_hex(&data, i); |
---|
404 | exit(0); |
---|
405 | } |
---|
406 | |
---|
407 | s = (struct nvme_resv_status *)data; |
---|
408 | n = (s->regctl[1] << 8) | s->regctl[0]; |
---|
409 | printf("Generation: %u\n", s->gen); |
---|
410 | printf("Reservation Type: %u\n", s->rtype); |
---|
411 | printf("Number of Registered Controllers: %u\n", n); |
---|
412 | printf("Persist Through Power Loss State: %u\n", s->ptpls); |
---|
413 | if (report_opt.eds) { |
---|
414 | e = (struct nvme_resv_status_ext *)data; |
---|
415 | n = MIN(n, (sizeof(data) - sizeof(e)) / sizeof(e->ctrlr[0])); |
---|
416 | for (i = 0; i < n; i++) { |
---|
417 | printf("Controller ID: 0x%04x\n", |
---|
418 | e->ctrlr[i].ctrlr_id); |
---|
419 | printf(" Reservation Status: %u\n", |
---|
420 | e->ctrlr[i].rcsts); |
---|
421 | printf(" Reservation Key: 0x%08jx\n", |
---|
422 | e->ctrlr[i].rkey); |
---|
423 | printf(" Host Identifier: 0x%08jx%08jx\n", |
---|
424 | e->ctrlr[i].hostid[0], e->ctrlr[i].hostid[1]); |
---|
425 | } |
---|
426 | } else { |
---|
427 | n = MIN(n, (sizeof(data) - sizeof(s)) / sizeof(s->ctrlr[0])); |
---|
428 | for (i = 0; i < n; i++) { |
---|
429 | printf("Controller ID: 0x%04x\n", |
---|
430 | s->ctrlr[i].ctrlr_id); |
---|
431 | printf(" Reservation Status: %u\n", |
---|
432 | s->ctrlr[i].rcsts); |
---|
433 | printf(" Host Identifier: 0x%08jx\n", |
---|
434 | s->ctrlr[i].hostid); |
---|
435 | printf(" Reservation Key: 0x%08jx\n", |
---|
436 | s->ctrlr[i].rkey); |
---|
437 | } |
---|
438 | } |
---|
439 | exit(0); |
---|
440 | } |
---|
441 | |
---|
442 | static void |
---|
443 | resv(const struct cmd *nf __unused, int argc, char *argv[]) |
---|
444 | { |
---|
445 | |
---|
446 | cmd_dispatch(argc, argv, &resv_cmd); |
---|
447 | } |
---|