Index: head/sbin/nvmecontrol/passthru.c =================================================================== --- head/sbin/nvmecontrol/passthru.c (nonexistent) +++ head/sbin/nvmecontrol/passthru.c (revision 350058) @@ -0,0 +1,273 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (C) 2012-2013 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nvmecontrol.h" +#include "comnd.h" + +static struct options { + uint8_t opcode; + uint8_t flags; + uint16_t rsvd; + uint32_t nsid; + uint32_t data_len; + uint32_t metadata_len; + uint32_t timeout; + uint32_t cdw2; + uint32_t cdw3; + uint32_t cdw10; + uint32_t cdw11; + uint32_t cdw12; + uint32_t cdw13; + uint32_t cdw14; + uint32_t cdw15; + const char *ifn; + bool binary; + bool show_command; + bool dry_run; + bool read; + bool write; + uint8_t prefill; + const char *dev; +} opt = { + .binary = false, + .cdw10 = 0, + .cdw11 = 0, + .cdw12 = 0, + .cdw13 = 0, + .cdw14 = 0, + .cdw15 = 0, + .cdw2 = 0, + .cdw3 = 0, + .data_len = 0, + .dry_run = false, + .flags = 0, + .ifn = "", + .metadata_len = 0, + .nsid = 0, + .opcode = 0, + .prefill = 0, + .read = false, + .rsvd = 0, + .show_command = false, + .timeout = 0, + .write = false, + .dev = NULL, +}; + +/* + * Argument names and short names selected to match the nvme-cli program + * so vendor-siupplied formulas work out of the box on FreeBSD with a simple + * s/nvme/nvmecontrol/. + */ +#define ARG(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } + +static const struct opts opts[] = { + ARG("opcode", 'o', arg_uint8, opt, opcode, + "NVMe command opcode (required)"), + ARG("cdw2", '2', arg_uint32, opt, cdw2, + "Command dword 2 value"), + ARG("cdw3", '3', arg_uint32, opt, cdw3, + "Command dword 3 value"), + ARG("cdw10", '4', arg_uint32, opt, cdw10, + "Command dword 10 value"), + ARG("cdw11", '5', arg_uint32, opt, cdw11, + "Command dword 11 value"), + ARG("cdw12", '6', arg_uint32, opt, cdw12, + "Command dword 12 value"), + ARG("cdw13", '7', arg_uint32, opt, cdw13, + "Command dword 13 value"), + ARG("cdw14", '8', arg_uint32, opt, cdw14, + "Command dword 14 value"), + ARG("cdw15", '9', arg_uint32, opt, cdw15, + "Command dword 15 value"), + ARG("data-len", 'l', arg_uint32, opt, data_len, + "Length of data for I/O (bytes)"), + ARG("metadata-len", 'm', arg_uint32, opt, metadata_len, + "Length of metadata segment (bytes) (igored)"), + ARG("flags", 'f', arg_uint8, opt, flags, + "NVMe command flags"), + ARG("input-file", 'i', arg_path, opt, ifn, + "Input file to send (default stdin)"), + ARG("namespace-id", 'n', arg_uint32, opt, nsid, + "Namespace id (ignored on FreeBSD)"), + ARG("prefill", 'p', arg_uint8, opt, prefill, + "Value to prefill payload with"), + ARG("rsvd", 'R', arg_uint16, opt, rsvd, + "Reserved field value"), + ARG("timeout", 't', arg_uint32, opt, timeout, + "Command timeout (ms)"), + ARG("raw-binary", 'b', arg_none, opt, binary, + "Output in binary format"), + ARG("dry-run", 'd', arg_none, opt, dry_run, + "Don't actually execute the command"), + ARG("read", 'r', arg_none, opt, read, + "Command reads data from device"), + ARG("show-command", 's', arg_none, opt, show_command, + "Show all the command values on stdout"), + ARG("write", 'w', arg_none, opt, write, + "Command writes data to device"), + { NULL, 0, arg_none, NULL, NULL } +}; + +static const struct args args[] = { + { arg_string, &opt.dev, "controller-id|namespace-id" }, + { arg_none, NULL, NULL }, +}; + +static void +passthru(const struct cmd *f, int argc, char *argv[]) +{ + int fd = -1, ifd = -1; + void *data = NULL, *metadata = NULL; + struct nvme_pt_command pt; + + arg_parse(argc, argv, f); + open_dev(argv[optind], &fd, 1, 1); + + if (opt.read && opt.write) + errx(1, "need exactly one of --read or --write"); + if (opt.data_len != 0 && !opt.read && !opt.write) + errx(1, "need exactly one of --read or --write"); + if (*opt.ifn && (ifd = open(opt.ifn, O_RDONLY)) == -1) { + warn("open %s", opt.ifn); + goto cleanup; + } +#if notyet /* No support in kernel for this */ + if (opt.metadata_len != 0) { + if (posix_memalign(&metadata, getpagesize(), opt.metadata_len)) { + warn("can't allocate %d bytes for metadata", metadata_len); + goto cleanup; + } + } +#else + if (opt.metadata_len != 0) + errx(1, "metadata not supported on FreeBSD"); +#endif + if (opt.data_len) { + if (posix_memalign(&data, getpagesize(), opt.data_len)) { + warn("can't allocate %d bytes for data", opt.data_len); + goto cleanup; + } + memset(data, opt.prefill, opt.data_len); + if (opt.write && read(ifd, data, opt.data_len) < 0) { + warn("read %s", *opt.ifn ? opt.ifn : "stdin"); + goto cleanup; + } + } + if (opt.show_command) { + fprintf(stderr, "opcode : %#02x\n", opt.opcode); + fprintf(stderr, "flags : %#02x\n", opt.flags); + fprintf(stderr, "rsvd1 : %#04x\n", opt.rsvd); + fprintf(stderr, "nsid : %#04x\n", opt.nsid); + fprintf(stderr, "cdw2 : %#08x\n", opt.cdw2); + fprintf(stderr, "cdw3 : %#08x\n", opt.cdw3); + fprintf(stderr, "data_len : %#08x\n", opt.data_len); + fprintf(stderr, "metadata_len : %#08x\n", opt.metadata_len); + fprintf(stderr, "data : %p\n", data); + fprintf(stderr, "metadata : %p\n", metadata); + fprintf(stderr, "cdw10 : %#08x\n", opt.cdw10); + fprintf(stderr, "cdw11 : %#08x\n", opt.cdw11); + fprintf(stderr, "cdw12 : %#08x\n", opt.cdw12); + fprintf(stderr, "cdw13 : %#08x\n", opt.cdw13); + fprintf(stderr, "cdw14 : %#08x\n", opt.cdw14); + fprintf(stderr, "cdw15 : %#08x\n", opt.cdw15); + fprintf(stderr, "timeout_ms : %d\n", opt.timeout); + } + if (opt.dry_run) { + errno = 0; + warn("Doing a dry-run, no actual I/O"); + goto cleanup; + } + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = opt.opcode; + pt.cmd.fuse = opt.flags; + pt.cmd.cid = htole16(opt.rsvd); + pt.cmd.nsid = opt.nsid; /* XXX note: kernel overrides this */ + pt.cmd.rsvd2 = htole32(opt.cdw2); + pt.cmd.rsvd3 = htole32(opt.cdw3); + pt.cmd.cdw10 = htole32(opt.cdw10); + pt.cmd.cdw11 = htole32(opt.cdw11); + pt.cmd.cdw12 = htole32(opt.cdw12); + pt.cmd.cdw13 = htole32(opt.cdw13); + pt.cmd.cdw14 = htole32(opt.cdw14); + pt.cmd.cdw15 = htole32(opt.cdw15); + pt.buf = data; + pt.len = opt.data_len; + pt.is_read = opt.read; + + errno = 0; + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(1, "passthrough request failed"); + /* XXX report status */ + if (opt.read) { + if (opt.binary) + write(STDOUT_FILENO, data, opt.data_len); + else { + /* print status here */ + print_hex(data, opt.data_len); + } + } +cleanup: + if (errno) + exit(1); +} + +static void +admin_passthru(const struct cmd *nf, int argc, char *argv[]) +{ + + passthru(nf, argc, argv); +} + +static void +io_passthru(const struct cmd *nf, int argc, char *argv[]) +{ + + passthru(nf, argc, argv); +} + +CMD_COMMAND(top, admin-passthru, admin_passthru, sizeof(struct options), opts, args, + "Send a pass through Admin command to the specified device"); +CMD_COMMAND(top, io-passthru, io_passthru, sizeof(struct options), opts, args, + "Send a pass through I/O command to the specified device"); Property changes on: head/sbin/nvmecontrol/passthru.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property