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