2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (C) 2012-2013 Intel Corporation
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/ioccom.h>
45 #include "nvmecontrol.h"
48 static struct options {
54 uint32_t metadata_len;
92 .show_command = false,
99 * Argument names and short names selected to match the nvme-cli program
100 * so vendor-siupplied formulas work out of the box on FreeBSD with a simple
101 * s/nvme/nvmecontrol/.
103 #define ARG(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc }
105 static struct opts opts[] = {
106 ARG("opcode", 'o', arg_uint8, opt, opcode,
107 "NVMe command opcode (required)"),
108 ARG("cdw2", '2', arg_uint32, opt, cdw2,
109 "Command dword 2 value"),
110 ARG("cdw3", '3', arg_uint32, opt, cdw3,
111 "Command dword 3 value"),
112 ARG("cdw10", '4', arg_uint32, opt, cdw10,
113 "Command dword 10 value"),
114 ARG("cdw11", '5', arg_uint32, opt, cdw11,
115 "Command dword 11 value"),
116 ARG("cdw12", '6', arg_uint32, opt, cdw12,
117 "Command dword 12 value"),
118 ARG("cdw13", '7', arg_uint32, opt, cdw13,
119 "Command dword 13 value"),
120 ARG("cdw14", '8', arg_uint32, opt, cdw14,
121 "Command dword 14 value"),
122 ARG("cdw15", '9', arg_uint32, opt, cdw15,
123 "Command dword 15 value"),
124 ARG("data-len", 'l', arg_uint32, opt, data_len,
125 "Length of data for I/O (bytes)"),
126 ARG("metadata-len", 'm', arg_uint32, opt, metadata_len,
127 "Length of metadata segment (bytes) (igored)"),
128 ARG("flags", 'f', arg_uint8, opt, flags,
129 "NVMe command flags"),
130 ARG("input-file", 'i', arg_path, opt, ifn,
131 "Input file to send (default stdin)"),
132 ARG("namespace-id", 'n', arg_uint32, opt, nsid,
133 "Namespace id (ignored on FreeBSD)"),
134 ARG("prefill", 'p', arg_uint8, opt, prefill,
135 "Value to prefill payload with"),
136 ARG("rsvd", 'R', arg_uint16, opt, rsvd,
137 "Reserved field value"),
138 ARG("timeout", 't', arg_uint32, opt, timeout,
139 "Command timeout (ms)"),
140 ARG("raw-binary", 'b', arg_none, opt, binary,
141 "Output in binary format"),
142 ARG("dry-run", 'd', arg_none, opt, dry_run,
143 "Don't actually execute the command"),
144 ARG("read", 'r', arg_none, opt, read,
145 "Command reads data from device"),
146 ARG("show-command", 's', arg_none, opt, show_command,
147 "Show all the command values on stdout"),
148 ARG("write", 'w', arg_none, opt, write,
149 "Command writes data to device"),
150 { NULL, 0, arg_none, NULL, NULL }
153 static const struct args args[] = {
154 { arg_string, &opt.dev, "controller-id|namespace-id" },
155 { arg_none, NULL, NULL },
159 passthru(const struct cmd *f, int argc, char *argv[])
161 int fd = -1, ifd = -1;
163 void *data = NULL, *metadata = NULL;
164 struct nvme_pt_command pt;
166 if (arg_parse(argc, argv, f))
168 open_dev(opt.dev, &fd, 1, 1);
170 if (opt.read && opt.write)
171 errx(EX_USAGE, "need exactly one of --read or --write");
172 if (opt.data_len != 0 && !opt.read && !opt.write)
173 errx(EX_USAGE, "need exactly one of --read or --write");
174 if (*opt.ifn && (ifd = open(opt.ifn, O_RDONLY)) == -1) {
175 warn("open %s", opt.ifn);
178 #if notyet /* No support in kernel for this */
179 if (opt.metadata_len != 0) {
180 if (posix_memalign(&metadata, getpagesize(), opt.metadata_len)) {
181 warn("can't allocate %d bytes for metadata", metadata_len);
186 if (opt.metadata_len != 0)
187 errx(EX_UNAVAILABLE, "metadata not supported on FreeBSD");
190 if (posix_memalign(&data, getpagesize(), opt.data_len)) {
191 warn("can't allocate %d bytes for data", opt.data_len);
194 memset(data, opt.prefill, opt.data_len);
196 (bytes_read = read(ifd, data, opt.data_len)) !=
198 warn("read %s; expected %u bytes; got %zd",
199 *opt.ifn ? opt.ifn : "stdin",
200 opt.data_len, bytes_read);
204 if (opt.show_command) {
205 fprintf(stderr, "opcode : %#02x\n", opt.opcode);
206 fprintf(stderr, "flags : %#02x\n", opt.flags);
207 fprintf(stderr, "rsvd1 : %#04x\n", opt.rsvd);
208 fprintf(stderr, "nsid : %#04x\n", opt.nsid);
209 fprintf(stderr, "cdw2 : %#08x\n", opt.cdw2);
210 fprintf(stderr, "cdw3 : %#08x\n", opt.cdw3);
211 fprintf(stderr, "data_len : %#08x\n", opt.data_len);
212 fprintf(stderr, "metadata_len : %#08x\n", opt.metadata_len);
213 fprintf(stderr, "data : %p\n", data);
214 fprintf(stderr, "metadata : %p\n", metadata);
215 fprintf(stderr, "cdw10 : %#08x\n", opt.cdw10);
216 fprintf(stderr, "cdw11 : %#08x\n", opt.cdw11);
217 fprintf(stderr, "cdw12 : %#08x\n", opt.cdw12);
218 fprintf(stderr, "cdw13 : %#08x\n", opt.cdw13);
219 fprintf(stderr, "cdw14 : %#08x\n", opt.cdw14);
220 fprintf(stderr, "cdw15 : %#08x\n", opt.cdw15);
221 fprintf(stderr, "timeout_ms : %d\n", opt.timeout);
225 warn("Doing a dry-run, no actual I/O");
229 memset(&pt, 0, sizeof(pt));
230 pt.cmd.opc = opt.opcode;
231 pt.cmd.fuse = opt.flags;
232 pt.cmd.cid = htole16(opt.rsvd);
233 pt.cmd.nsid = opt.nsid; /* XXX note: kernel overrides this */
234 pt.cmd.rsvd2 = htole32(opt.cdw2);
235 pt.cmd.rsvd3 = htole32(opt.cdw3);
236 pt.cmd.cdw10 = htole32(opt.cdw10);
237 pt.cmd.cdw11 = htole32(opt.cdw11);
238 pt.cmd.cdw12 = htole32(opt.cdw12);
239 pt.cmd.cdw13 = htole32(opt.cdw13);
240 pt.cmd.cdw14 = htole32(opt.cdw14);
241 pt.cmd.cdw15 = htole32(opt.cdw15);
243 pt.len = opt.data_len;
244 pt.is_read = opt.read;
247 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
248 err(EX_IOERR, "passthrough request failed");
249 /* XXX report status */
252 write(STDOUT_FILENO, data, opt.data_len);
254 /* print status here */
255 print_hex(data, opt.data_len);
268 admin_passthru(const struct cmd *nf, int argc, char *argv[])
271 passthru(nf, argc, argv);
275 io_passthru(const struct cmd *nf, int argc, char *argv[])
278 passthru(nf, argc, argv);
281 static struct cmd admin_pass_cmd = {
282 .name = "admin-passthru",
283 .fn = admin_passthru,
284 .ctx_size = sizeof(struct options),
287 .descr = "Send a pass through Admin command to the specified device",
290 static struct cmd io_pass_cmd = {
291 .name = "io-passthru",
293 .ctx_size = sizeof(struct options),
296 .descr = "Send a pass through I/O command to the specified device",
299 CMD_COMMAND(admin_pass_cmd);
300 CMD_COMMAND(io_pass_cmd);