Add IOCTL to translate nvdX into nvmeY and NSID.
While very useful by itself, it also makes `nvmecontrol` not depend on hardcoded device names parsing, that in its turn makes simple to take nvdX (and potentially any other) device names as arguments. Also added IOCTL bypass from nvdX to respective nvmeYnsZ makes them interchangeable for management purposes. MFC after: 2 weeks Sponsored by: iXsystems, Inc.
This commit is contained in:
parent
9a01cf0376
commit
397bc7f075
@ -3,7 +3,8 @@
|
|||||||
PACKAGE=runtime
|
PACKAGE=runtime
|
||||||
PROG= nvmecontrol
|
PROG= nvmecontrol
|
||||||
SRCS= comnd.c nvmecontrol.c
|
SRCS= comnd.c nvmecontrol.c
|
||||||
SRCS+= devlist.c firmware.c format.c identify.c logpage.c ns.c perftest.c power.c reset.c
|
SRCS+= devlist.c firmware.c format.c identify.c logpage.c ns.c nsid.c
|
||||||
|
SRCS+= perftest.c power.c reset.c
|
||||||
#SRCS+= passthru.c
|
#SRCS+= passthru.c
|
||||||
SRCS+= identify_ext.c nvme_util.c nc_util.c
|
SRCS+= identify_ext.c nvme_util.c nc_util.c
|
||||||
MAN= nvmecontrol.8
|
MAN= nvmecontrol.8
|
||||||
|
@ -107,11 +107,11 @@ devlist(const struct cmd *f, int argc, char *argv[])
|
|||||||
printf("%6s: %s\n", name, mn);
|
printf("%6s: %s\n", name, mn);
|
||||||
|
|
||||||
for (i = 0; i < cdata.nn; i++) {
|
for (i = 0; i < cdata.nn; i++) {
|
||||||
sprintf(name, "%s%d%s%d", NVME_CTRLR_PREFIX, ctrlr,
|
|
||||||
NVME_NS_PREFIX, i+1);
|
|
||||||
read_namespace_data(fd, i + 1, &nsdata);
|
read_namespace_data(fd, i + 1, &nsdata);
|
||||||
if (nsdata.nsze == 0)
|
if (nsdata.nsze == 0)
|
||||||
continue;
|
continue;
|
||||||
|
sprintf(name, "%s%d%s%d", NVME_CTRLR_PREFIX, ctrlr,
|
||||||
|
NVME_NS_PREFIX, i + 1);
|
||||||
printf(" %10s (%lldMB)\n",
|
printf(" %10s (%lldMB)\n",
|
||||||
name,
|
name,
|
||||||
nsdata.nsze *
|
nsdata.nsze *
|
||||||
|
@ -224,7 +224,7 @@ firmware(const struct cmd *f, int argc, char *argv[])
|
|||||||
int activate_action, reboot_required;
|
int activate_action, reboot_required;
|
||||||
char prompt[64];
|
char prompt[64];
|
||||||
void *buf = NULL;
|
void *buf = NULL;
|
||||||
int32_t size = 0;
|
int32_t size = 0, nsid;
|
||||||
uint16_t oacs_fw;
|
uint16_t oacs_fw;
|
||||||
uint8_t fw_slot1_ro, fw_num_slots;
|
uint8_t fw_slot1_ro, fw_num_slots;
|
||||||
struct nvme_controller_data cdata;
|
struct nvme_controller_data cdata;
|
||||||
@ -253,10 +253,6 @@ firmware(const struct cmd *f, int argc, char *argv[])
|
|||||||
arg_help(argc, argv, f);
|
arg_help(argc, argv, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that a controller (and not a namespace) was specified. */
|
|
||||||
if (strstr(opt.dev, NVME_NS_PREFIX) != NULL)
|
|
||||||
arg_help(argc, argv, f);
|
|
||||||
|
|
||||||
if (opt.activate && opt.fw_img == NULL && opt.slot == 0) {
|
if (opt.activate && opt.fw_img == NULL && opt.slot == 0) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Slot number to activate not specified.\n");
|
"Slot number to activate not specified.\n");
|
||||||
@ -264,6 +260,14 @@ firmware(const struct cmd *f, int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
open_dev(opt.dev, &fd, 1, 1);
|
open_dev(opt.dev, &fd, 1, 1);
|
||||||
|
|
||||||
|
/* Check that a controller (and not a namespace) was specified. */
|
||||||
|
get_nsid(fd, NULL, &nsid);
|
||||||
|
if (nsid != 0) {
|
||||||
|
close(fd);
|
||||||
|
arg_help(argc, argv, f);
|
||||||
|
}
|
||||||
|
|
||||||
read_controller_data(fd, &cdata);
|
read_controller_data(fd, &cdata);
|
||||||
|
|
||||||
oacs_fw = (cdata.oacs >> NVME_CTRLR_DATA_OACS_FIRMWARE_SHIFT) &
|
oacs_fw = (cdata.oacs >> NVME_CTRLR_DATA_OACS_FIRMWARE_SHIFT) &
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
/*-
|
/*-
|
||||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Alexander Motin <mav@FreeBSD.org>
|
* Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org>
|
||||||
* All rights reserved.
|
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -117,7 +116,7 @@ format(const struct cmd *f, int argc, char *argv[])
|
|||||||
struct nvme_controller_data cd;
|
struct nvme_controller_data cd;
|
||||||
struct nvme_namespace_data nsd;
|
struct nvme_namespace_data nsd;
|
||||||
struct nvme_pt_command pt;
|
struct nvme_pt_command pt;
|
||||||
char path[64];
|
char *path;
|
||||||
const char *target;
|
const char *target;
|
||||||
uint32_t nsid;
|
uint32_t nsid;
|
||||||
int lbaf, ms, pi, pil, ses, fd;
|
int lbaf, ms, pi, pil, ses, fd;
|
||||||
@ -143,18 +142,9 @@ format(const struct cmd *f, int argc, char *argv[])
|
|||||||
else
|
else
|
||||||
ses = opt.ses;
|
ses = opt.ses;
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if the specified device node exists before continuing.
|
|
||||||
* This is a cleaner check for cases where the correct controller
|
|
||||||
* is specified, but an invalid namespace on that controller.
|
|
||||||
*/
|
|
||||||
open_dev(target, &fd, 1, 1);
|
open_dev(target, &fd, 1, 1);
|
||||||
|
get_nsid(fd, &path, &nsid);
|
||||||
/*
|
if (nsid == 0) {
|
||||||
* If device node contains "ns", we consider it a namespace,
|
|
||||||
* otherwise, consider it a controller.
|
|
||||||
*/
|
|
||||||
if (strstr(target, NVME_NS_PREFIX) == NULL) {
|
|
||||||
nsid = NVME_GLOBAL_NAMESPACE_TAG;
|
nsid = NVME_GLOBAL_NAMESPACE_TAG;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
@ -164,9 +154,9 @@ format(const struct cmd *f, int argc, char *argv[])
|
|||||||
* string to get the controller substring and namespace ID.
|
* string to get the controller substring and namespace ID.
|
||||||
*/
|
*/
|
||||||
close(fd);
|
close(fd);
|
||||||
parse_ns_str(target, path, &nsid);
|
|
||||||
open_dev(path, &fd, 1, 1);
|
open_dev(path, &fd, 1, 1);
|
||||||
}
|
}
|
||||||
|
free(path);
|
||||||
|
|
||||||
/* Check that controller can execute this command. */
|
/* Check that controller can execute this command. */
|
||||||
read_controller_data(fd, &cd);
|
read_controller_data(fd, &cd);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) 2012-2013 Intel Corporation
|
* Copyright (C) 2012-2013 Intel Corporation
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
* Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -44,6 +45,8 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include "nvmecontrol.h"
|
#include "nvmecontrol.h"
|
||||||
#include "nvmecontrol_ext.h"
|
#include "nvmecontrol_ext.h"
|
||||||
|
|
||||||
|
#define NONE 0xfffffffeu
|
||||||
|
|
||||||
static struct options {
|
static struct options {
|
||||||
bool hex;
|
bool hex;
|
||||||
bool verbose;
|
bool verbose;
|
||||||
@ -53,7 +56,7 @@ static struct options {
|
|||||||
.hex = false,
|
.hex = false,
|
||||||
.verbose = false,
|
.verbose = false,
|
||||||
.dev = NULL,
|
.dev = NULL,
|
||||||
.nsid = 0,
|
.nsid = NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -170,12 +173,11 @@ print_namespace(struct nvme_namespace_data *nsdata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
identify_ctrlr(const struct cmd *f, int argc, char *argv[])
|
identify_ctrlr(int fd)
|
||||||
{
|
{
|
||||||
struct nvme_controller_data cdata;
|
struct nvme_controller_data cdata;
|
||||||
int fd, hexlength;
|
int hexlength;
|
||||||
|
|
||||||
open_dev(opt.dev, &fd, 1, 1);
|
|
||||||
read_controller_data(fd, &cdata);
|
read_controller_data(fd, &cdata);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
@ -189,41 +191,16 @@ identify_ctrlr(const struct cmd *f, int argc, char *argv[])
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt.verbose) {
|
|
||||||
fprintf(stderr, "-v not currently supported without -x\n");
|
|
||||||
arg_help(argc, argv, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
nvme_print_controller(&cdata);
|
nvme_print_controller(&cdata);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
identify_ns(const struct cmd *f, int argc, char *argv[])
|
identify_ns(int fd, uint32_t nsid)
|
||||||
{
|
{
|
||||||
struct nvme_namespace_data nsdata;
|
struct nvme_namespace_data nsdata;
|
||||||
char path[64];
|
int hexlength;
|
||||||
int fd, hexlength;
|
|
||||||
uint32_t nsid;
|
|
||||||
|
|
||||||
open_dev(opt.dev, &fd, 1, 1);
|
|
||||||
if (strstr(opt.dev, NVME_NS_PREFIX) != NULL) {
|
|
||||||
/*
|
|
||||||
* Now we know that provided device name is valid, that is
|
|
||||||
* good for error reporting if specified controller name is
|
|
||||||
* valid, but namespace ID is not. But we send IDENTIFY
|
|
||||||
* commands to the controller, not the namespace, since it
|
|
||||||
* is an admin cmd. The namespace ID will be specified in
|
|
||||||
* the IDENTIFY command itself. So parse the namespace's
|
|
||||||
* device node string to get the controller device substring
|
|
||||||
* and namespace ID.
|
|
||||||
*/
|
|
||||||
close(fd);
|
|
||||||
parse_ns_str(opt.dev, path, &nsid);
|
|
||||||
open_dev(path, &fd, 1, 1);
|
|
||||||
} else {
|
|
||||||
nsid = opt.nsid;
|
|
||||||
}
|
|
||||||
read_namespace_data(fd, nsid, &nsdata);
|
read_namespace_data(fd, nsid, &nsdata);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
@ -237,11 +214,6 @@ identify_ns(const struct cmd *f, int argc, char *argv[])
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt.verbose) {
|
|
||||||
fprintf(stderr, "-v not currently supported without -x\n");
|
|
||||||
arg_help(argc, argv, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
print_namespace(&nsdata);
|
print_namespace(&nsdata);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
@ -249,16 +221,32 @@ identify_ns(const struct cmd *f, int argc, char *argv[])
|
|||||||
static void
|
static void
|
||||||
identify(const struct cmd *f, int argc, char *argv[])
|
identify(const struct cmd *f, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
char *path;
|
||||||
|
int fd;
|
||||||
|
uint32_t nsid;
|
||||||
|
|
||||||
arg_parse(argc, argv, f);
|
arg_parse(argc, argv, f);
|
||||||
|
|
||||||
|
open_dev(opt.dev, &fd, 1, 1);
|
||||||
|
get_nsid(fd, &path, &nsid);
|
||||||
|
if (nsid != 0) {
|
||||||
/*
|
/*
|
||||||
* If device node contains "ns" or nsid is specified, we consider
|
* We got namespace device, but we need to send IDENTIFY
|
||||||
* it a namespace request, otherwise, consider it a controller.
|
* commands to the controller, not the namespace, since it
|
||||||
|
* is an admin cmd. The namespace ID will be specified in
|
||||||
|
* the IDENTIFY command itself.
|
||||||
*/
|
*/
|
||||||
if (strstr(opt.dev, NVME_NS_PREFIX) == NULL && opt.nsid == 0)
|
close(fd);
|
||||||
identify_ctrlr(f, argc, argv);
|
open_dev(path, &fd, 1, 1);
|
||||||
|
}
|
||||||
|
free(path);
|
||||||
|
if (opt.nsid != NONE)
|
||||||
|
nsid = opt.nsid;
|
||||||
|
|
||||||
|
if (nsid == 0)
|
||||||
|
identify_ctrlr(fd);
|
||||||
else
|
else
|
||||||
identify_ns(f, argc, argv);
|
identify_ns(fd, nsid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct opts identify_opts[] = {
|
static const struct opts identify_opts[] = {
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) 2012-2013 Intel Corporation
|
* Copyright (C) 2012-2013 Intel Corporation
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
* Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
|
@ -399,8 +399,7 @@ static void
|
|||||||
logpage(const struct cmd *f, int argc, char *argv[])
|
logpage(const struct cmd *f, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
bool ns_specified;
|
char *path;
|
||||||
char cname[64];
|
|
||||||
uint32_t nsid, size;
|
uint32_t nsid, size;
|
||||||
void *buf;
|
void *buf;
|
||||||
const struct logpage_function *lpf;
|
const struct logpage_function *lpf;
|
||||||
@ -421,15 +420,15 @@ logpage(const struct cmd *f, int argc, char *argv[])
|
|||||||
fprintf(stderr, "Missing page_id (-p).\n");
|
fprintf(stderr, "Missing page_id (-p).\n");
|
||||||
arg_help(argc, argv, f);
|
arg_help(argc, argv, f);
|
||||||
}
|
}
|
||||||
if (strstr(opt.dev, NVME_NS_PREFIX) != NULL) {
|
|
||||||
ns_specified = true;
|
|
||||||
parse_ns_str(opt.dev, cname, &nsid);
|
|
||||||
open_dev(cname, &fd, 1, 1);
|
|
||||||
} else {
|
|
||||||
ns_specified = false;
|
|
||||||
nsid = NVME_GLOBAL_NAMESPACE_TAG;
|
|
||||||
open_dev(opt.dev, &fd, 1, 1);
|
open_dev(opt.dev, &fd, 1, 1);
|
||||||
|
get_nsid(fd, &path, &nsid);
|
||||||
|
if (nsid == 0) {
|
||||||
|
nsid = NVME_GLOBAL_NAMESPACE_TAG;
|
||||||
|
} else {
|
||||||
|
close(fd);
|
||||||
|
open_dev(path, &fd, 1, 1);
|
||||||
}
|
}
|
||||||
|
free(path);
|
||||||
|
|
||||||
read_controller_data(fd, &cdata);
|
read_controller_data(fd, &cdata);
|
||||||
|
|
||||||
@ -441,7 +440,7 @@ logpage(const struct cmd *f, int argc, char *argv[])
|
|||||||
* supports the SMART/Health information log page on a per
|
* supports the SMART/Health information log page on a per
|
||||||
* namespace basis.
|
* namespace basis.
|
||||||
*/
|
*/
|
||||||
if (ns_specified) {
|
if (nsid != NVME_GLOBAL_NAMESPACE_TAG) {
|
||||||
if (opt.page != NVME_LOG_HEALTH_INFORMATION)
|
if (opt.page != NVME_LOG_HEALTH_INFORMATION)
|
||||||
errx(1, "log page %d valid only at controller level",
|
errx(1, "log page %d valid only at controller level",
|
||||||
opt.page);
|
opt.page);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017 Netflix, Inc.
|
* Copyright (c) 2017 Netflix, Inc.
|
||||||
* Copyright (C) 2018 Alexander Motin <mav@FreeBSD.org>
|
* Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
|
80
sbin/nvmecontrol/nsid.c
Normal file
80
sbin/nvmecontrol/nsid.c
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*-
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Alexander Motin <mav@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* 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 <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "nvmecontrol.h"
|
||||||
|
#include "comnd.h"
|
||||||
|
|
||||||
|
/* Tables for command line parsing */
|
||||||
|
|
||||||
|
static cmd_fn_t nsid;
|
||||||
|
|
||||||
|
static struct nsid_options {
|
||||||
|
const char *dev;
|
||||||
|
} nsid_opt = {
|
||||||
|
.dev = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct args nsid_args[] = {
|
||||||
|
{ arg_string, &nsid_opt.dev, "namespace-id" },
|
||||||
|
{ arg_none, NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct cmd nsid_cmd = {
|
||||||
|
.name = "nsid",
|
||||||
|
.fn = nsid,
|
||||||
|
.descr = "Get controller and NSID for namespace",
|
||||||
|
.ctx_size = sizeof(nsid_opt),
|
||||||
|
.opts = NULL,
|
||||||
|
.args = nsid_args,
|
||||||
|
};
|
||||||
|
|
||||||
|
CMD_COMMAND(nsid_cmd);
|
||||||
|
|
||||||
|
static void
|
||||||
|
nsid(const struct cmd *f, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
int fd;
|
||||||
|
uint32_t nsid;
|
||||||
|
|
||||||
|
arg_parse(argc, argv, f);
|
||||||
|
|
||||||
|
open_dev(nsid_opt.dev, &fd, 1, 1);
|
||||||
|
get_nsid(fd, &path, &nsid);
|
||||||
|
close(fd);
|
||||||
|
printf("%s\t%u\n", path, nsid);
|
||||||
|
free(path);
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2018 Alexander Motin <mav@FreeBSD.org>
|
.\" Copyright (c) 2018-2019 Alexander Motin <mav@FreeBSD.org>
|
||||||
.\" Copyright (c) 2012 Intel Corporation
|
.\" Copyright (c) 2012 Intel Corporation
|
||||||
.\" All rights reserved.
|
.\" All rights reserved.
|
||||||
.\"
|
.\"
|
||||||
@ -34,7 +34,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd July 31, 2019
|
.Dd August 1, 2019
|
||||||
.Dt NVMECONTROL 8
|
.Dt NVMECONTROL 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -114,6 +114,10 @@
|
|||||||
.Aq Fl n Ar nsid
|
.Aq Fl n Ar nsid
|
||||||
.Aq device id
|
.Aq device id
|
||||||
.Nm
|
.Nm
|
||||||
|
.Ic nsid
|
||||||
|
.Aq device id
|
||||||
|
.Aq namespace id
|
||||||
|
.Nm
|
||||||
.Ic firmware
|
.Ic firmware
|
||||||
.Op Fl s Ar slot
|
.Op Fl s Ar slot
|
||||||
.Op Fl f Ar path_to_firmware
|
.Op Fl f Ar path_to_firmware
|
||||||
|
@ -146,16 +146,6 @@ open_dev(const char *str, int *fd, int show_error, int exit_on_error)
|
|||||||
{
|
{
|
||||||
char full_path[64];
|
char full_path[64];
|
||||||
|
|
||||||
if (!strnstr(str, NVME_CTRLR_PREFIX, strlen(NVME_CTRLR_PREFIX))) {
|
|
||||||
if (show_error)
|
|
||||||
warnx("controller/namespace ids must begin with '%s'",
|
|
||||||
NVME_CTRLR_PREFIX);
|
|
||||||
if (exit_on_error)
|
|
||||||
exit(1);
|
|
||||||
else
|
|
||||||
return (EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(full_path, sizeof(full_path), _PATH_DEV"%s", str);
|
snprintf(full_path, sizeof(full_path), _PATH_DEV"%s", str);
|
||||||
*fd = open(full_path, O_RDWR);
|
*fd = open(full_path, O_RDWR);
|
||||||
if (*fd < 0) {
|
if (*fd < 0) {
|
||||||
@ -171,26 +161,16 @@ open_dev(const char *str, int *fd, int show_error, int exit_on_error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
parse_ns_str(const char *ns_str, char *ctrlr_str, uint32_t *nsid)
|
get_nsid(int fd, char **ctrlr_str, uint32_t *nsid)
|
||||||
{
|
{
|
||||||
char *nsloc;
|
struct nvme_get_nsid gnsid;
|
||||||
|
|
||||||
/*
|
if (ioctl(fd, NVME_GET_NSID, &gnsid) < 0)
|
||||||
* Pull the namespace id from the string. +2 skips past the "ns" part
|
err(1, "NVME_GET_NSID ioctl failed");
|
||||||
* of the string. Don't search past 10 characters into the string,
|
if (ctrlr_str != NULL)
|
||||||
* otherwise we know it is malformed.
|
*ctrlr_str = strndup(gnsid.cdev, sizeof(gnsid.cdev));
|
||||||
*/
|
if (nsid != NULL)
|
||||||
nsloc = strnstr(ns_str, NVME_NS_PREFIX, 10);
|
*nsid = gnsid.nsid;
|
||||||
if (nsloc != NULL)
|
|
||||||
*nsid = strtol(nsloc + 2, NULL, 10);
|
|
||||||
if (nsloc == NULL || (*nsid == 0 && errno != 0))
|
|
||||||
errx(1, "invalid namespace ID '%s'", ns_str);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The controller string will include only the nvmX part of the
|
|
||||||
* nvmeXnsY string.
|
|
||||||
*/
|
|
||||||
snprintf(ctrlr_str, nsloc - ns_str + 1, "%s", ns_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -69,7 +69,7 @@ void logpage_register(struct logpage_function *p);
|
|||||||
#define NVME_NS_PREFIX "ns"
|
#define NVME_NS_PREFIX "ns"
|
||||||
|
|
||||||
int open_dev(const char *str, int *fd, int show_error, int exit_on_error);
|
int open_dev(const char *str, int *fd, int show_error, int exit_on_error);
|
||||||
void parse_ns_str(const char *ns_str, char *ctrlr_str, uint32_t *nsid);
|
void get_nsid(int fd, char **ctrlr_str, uint32_t *nsid);
|
||||||
void read_controller_data(int fd, struct nvme_controller_data *cdata);
|
void read_controller_data(int fd, struct nvme_controller_data *cdata);
|
||||||
void read_namespace_data(int fd, uint32_t nsid, struct nvme_namespace_data *nsdata);
|
void read_namespace_data(int fd, uint32_t nsid, struct nvme_namespace_data *nsdata);
|
||||||
void print_hex(void *data, uint32_t length);
|
void print_hex(void *data, uint32_t length);
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
#define NVME_PASSTHROUGH_CMD _IOWR('n', 0, struct nvme_pt_command)
|
#define NVME_PASSTHROUGH_CMD _IOWR('n', 0, struct nvme_pt_command)
|
||||||
#define NVME_RESET_CONTROLLER _IO('n', 1)
|
#define NVME_RESET_CONTROLLER _IO('n', 1)
|
||||||
|
#define NVME_GET_NSID _IOR('n', 2, struct nvme_get_nsid)
|
||||||
|
|
||||||
#define NVME_IO_TEST _IOWR('n', 100, struct nvme_io_test)
|
#define NVME_IO_TEST _IOWR('n', 100, struct nvme_io_test)
|
||||||
#define NVME_BIO_TEST _IOWR('n', 101, struct nvme_io_test)
|
#define NVME_BIO_TEST _IOWR('n', 101, struct nvme_io_test)
|
||||||
@ -1332,6 +1333,11 @@ struct nvme_pt_command {
|
|||||||
struct mtx * driver_lock;
|
struct mtx * driver_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nvme_get_nsid {
|
||||||
|
char cdev[SPECNAMELEN + 1];
|
||||||
|
uint32_t nsid;
|
||||||
|
};
|
||||||
|
|
||||||
#define nvme_completion_is_error(cpl) \
|
#define nvme_completion_is_error(cpl) \
|
||||||
(NVME_STATUS_GET_SC((cpl)->status) != 0 || NVME_STATUS_GET_SCT((cpl)->status) != 0)
|
(NVME_STATUS_GET_SC((cpl)->status) != 0 || NVME_STATUS_GET_SCT((cpl)->status) != 0)
|
||||||
|
|
||||||
@ -1340,6 +1346,7 @@ void nvme_strvis(uint8_t *dst, const uint8_t *src, int dstlen, int srclen);
|
|||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
|
|
||||||
struct bio;
|
struct bio;
|
||||||
|
struct thread;
|
||||||
|
|
||||||
struct nvme_namespace;
|
struct nvme_namespace;
|
||||||
struct nvme_controller;
|
struct nvme_controller;
|
||||||
@ -1429,6 +1436,8 @@ uint32_t nvme_ns_get_stripesize(struct nvme_namespace *ns);
|
|||||||
|
|
||||||
int nvme_ns_bio_process(struct nvme_namespace *ns, struct bio *bp,
|
int nvme_ns_bio_process(struct nvme_namespace *ns, struct bio *bp,
|
||||||
nvme_cb_fn_t cb_fn);
|
nvme_cb_fn_t cb_fn);
|
||||||
|
int nvme_ns_ioctl_process(struct nvme_namespace *ns, u_long cmd,
|
||||||
|
caddr_t arg, int flag, struct thread *td);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Command building helper functions -- shared with CAM
|
* Command building helper functions -- shared with CAM
|
||||||
|
@ -1126,6 +1126,14 @@ nvme_ctrlr_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int flag,
|
|||||||
pt = (struct nvme_pt_command *)arg;
|
pt = (struct nvme_pt_command *)arg;
|
||||||
return (nvme_ctrlr_passthrough_cmd(ctrlr, pt, le32toh(pt->cmd.nsid),
|
return (nvme_ctrlr_passthrough_cmd(ctrlr, pt, le32toh(pt->cmd.nsid),
|
||||||
1 /* is_user_buffer */, 1 /* is_admin_cmd */));
|
1 /* is_user_buffer */, 1 /* is_admin_cmd */));
|
||||||
|
case NVME_GET_NSID:
|
||||||
|
{
|
||||||
|
struct nvme_get_nsid *gnsid = (struct nvme_get_nsid *)arg;
|
||||||
|
strncpy(gnsid->cdev, device_get_nameunit(ctrlr->dev),
|
||||||
|
sizeof(gnsid->cdev));
|
||||||
|
gnsid->nsid = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return (ENOTTY);
|
return (ENOTTY);
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,14 @@ nvme_ns_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int flag,
|
|||||||
pt = (struct nvme_pt_command *)arg;
|
pt = (struct nvme_pt_command *)arg;
|
||||||
return (nvme_ctrlr_passthrough_cmd(ctrlr, pt, ns->id,
|
return (nvme_ctrlr_passthrough_cmd(ctrlr, pt, ns->id,
|
||||||
1 /* is_user_buffer */, 0 /* is_admin_cmd */));
|
1 /* is_user_buffer */, 0 /* is_admin_cmd */));
|
||||||
|
case NVME_GET_NSID:
|
||||||
|
{
|
||||||
|
struct nvme_get_nsid *gnsid = (struct nvme_get_nsid *)arg;
|
||||||
|
strncpy(gnsid->cdev, device_get_nameunit(ctrlr->dev),
|
||||||
|
sizeof(gnsid->cdev));
|
||||||
|
gnsid->nsid = ns->id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DIOCGMEDIASIZE:
|
case DIOCGMEDIASIZE:
|
||||||
*(off_t *)arg = (off_t)nvme_ns_get_size(ns);
|
*(off_t *)arg = (off_t)nvme_ns_get_size(ns);
|
||||||
break;
|
break;
|
||||||
@ -483,6 +491,13 @@ nvme_ns_bio_process(struct nvme_namespace *ns, struct bio *bp,
|
|||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nvme_ns_ioctl_process(struct nvme_namespace *ns, u_long cmd, caddr_t arg,
|
||||||
|
int flag, struct thread *td)
|
||||||
|
{
|
||||||
|
return (nvme_ns_ioctl(ns->cdev, cmd, arg, flag, td));
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
nvme_ns_construct(struct nvme_namespace *ns, uint32_t id,
|
nvme_ns_construct(struct nvme_namespace *ns, uint32_t id,
|
||||||
struct nvme_controller *ctrlr)
|
struct nvme_controller *ctrlr)
|
||||||
|
Loading…
Reference in New Issue
Block a user