diff --git a/sbin/nvmecontrol/identify.c b/sbin/nvmecontrol/identify.c index 0bf2540e126f..39f9d05542b0 100644 --- a/sbin/nvmecontrol/identify.c +++ b/sbin/nvmecontrol/identify.c @@ -48,13 +48,15 @@ static struct options { bool hex; bool verbose; const char *dev; + uint32_t nsid; } opt = { .hex = false, .verbose = false, .dev = NULL, + .nsid = 0, }; -static void +void print_namespace(struct nvme_namespace_data *nsdata) { uint32_t i; @@ -204,22 +206,24 @@ identify_ns(const struct cmd *f, int argc, char *argv[]) int fd, hexlength; uint32_t nsid; - /* - * 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(opt.dev, &fd, 1, 1); - close(fd); - - /* - * 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 substring and namespace ID. - */ - parse_ns_str(opt.dev, path, &nsid); - open_dev(path, &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); close(fd); @@ -248,10 +252,10 @@ identify(const struct cmd *f, int argc, char *argv[]) arg_parse(argc, argv, f); /* - * If device node contains "ns", we consider it a namespace, - * otherwise, consider it a controller. + * If device node contains "ns" or nsid is specified, we consider + * it a namespace request, otherwise, consider it a controller. */ - if (strstr(opt.dev, NVME_NS_PREFIX) == NULL) + if (strstr(opt.dev, NVME_NS_PREFIX) == NULL && opt.nsid == 0) identify_ctrlr(f, argc, argv); else identify_ns(f, argc, argv); @@ -263,6 +267,8 @@ static const struct opts identify_opts[] = { "Print identiy information in hex"), OPT("verbose", 'v', arg_none, opt, verbose, "More verbosity: print entire identify table"), + OPT("nsid", 'n', arg_uint32, opt, nsid, + "Namespace ID to use if not in device name"), { NULL, 0, arg_none, NULL, NULL } }; #undef OPT @@ -275,7 +281,7 @@ static const struct args identify_args[] = { static struct cmd identify_cmd = { .name = "identify", .fn = identify, - .descr = "Print a human-readable summary of the IDENTIFY information", + .descr = "Print summary of the IDENTIFY information", .ctx_size = sizeof(opt), .opts = identify_opts, .args = identify_args, diff --git a/sbin/nvmecontrol/identify_ext.c b/sbin/nvmecontrol/identify_ext.c index 0a7351311310..eeb64cc62d7d 100644 --- a/sbin/nvmecontrol/identify_ext.c +++ b/sbin/nvmecontrol/identify_ext.c @@ -121,7 +121,7 @@ nvme_print_controller(struct nvme_controller_data *cdata) printf("Unlimited\n"); else printf("%ld\n", PAGE_SIZE * (1L << cdata->mdts)); - printf("Controller ID: 0x%02x\n", cdata->ctrlr_id); + printf("Controller ID: 0x%04x\n", cdata->ctrlr_id); printf("Version: %d.%d.%d\n", (cdata->ver >> 16) & 0xffff, (cdata->ver >> 8) & 0xff, cdata->ver & 0xff); diff --git a/sbin/nvmecontrol/ns.c b/sbin/nvmecontrol/ns.c index 7f0b9b20b7fe..a531b655df1e 100644 --- a/sbin/nvmecontrol/ns.c +++ b/sbin/nvmecontrol/ns.c @@ -34,6 +34,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include #include #include #include @@ -44,10 +46,15 @@ __FBSDID("$FreeBSD$"); /* Tables for command line parsing */ static cmd_fn_t ns; +static cmd_fn_t nsactive; +static cmd_fn_t nsallocated; +static cmd_fn_t nscontrollers; static cmd_fn_t nscreate; static cmd_fn_t nsdelete; static cmd_fn_t nsattach; static cmd_fn_t nsdetach; +static cmd_fn_t nsattached; +static cmd_fn_t nsidentify; #define NONE 0xffffffffu #define NONE64 0xffffffffffffffffull @@ -55,11 +62,71 @@ static cmd_fn_t nsdetach; #define OPT_END { NULL, 0, arg_none, NULL, NULL } static struct cmd ns_cmd = { - .name = "ns", .fn = ns, .descr = "Namespace commands", .ctx_size = 0, .opts = NULL, .args = NULL, + .name = "ns", + .fn = ns, + .descr = "Namespace management commands", + .ctx_size = 0, + .opts = NULL, + .args = NULL, }; CMD_COMMAND(ns_cmd); +static struct active_options { + const char *dev; +} active_opt = { + .dev = NULL, +}; + +static const struct args active_args[] = { + { arg_string, &active_opt.dev, "controller-id" }, + { arg_none, NULL, NULL }, +}; + +static struct cmd active_cmd = { + .name = "active", + .fn = nsactive, + .descr = "List active (attached) namespaces", + .ctx_size = sizeof(active_opt), + .opts = NULL, + .args = active_args, +}; + +CMD_SUBCOMMAND(ns_cmd, active_cmd); + +static struct cmd allocated_cmd = { + .name = "allocated", + .fn = nsallocated, + .descr = "List allocated (created) namespaces", + .ctx_size = sizeof(active_opt), + .opts = NULL, + .args = active_args, +}; + +CMD_SUBCOMMAND(ns_cmd, allocated_cmd); + +static struct controllers_options { + const char *dev; +} controllers_opt = { + .dev = NULL, +}; + +static const struct args controllers_args[] = { + { arg_string, &controllers_opt.dev, "controller-id" }, + { arg_none, NULL, NULL }, +}; + +static struct cmd controllers_cmd = { + .name = "controllers", + .fn = nscontrollers, + .descr = "List all controllers in NVM subsystem", + .ctx_size = sizeof(controllers_opt), + .opts = NULL, + .args = controllers_args, +}; + +CMD_SUBCOMMAND(ns_cmd, controllers_cmd); + static struct create_options { uint64_t nsze; uint64_t cap; @@ -101,7 +168,7 @@ static const struct opts create_opts[] = { "PI field of FLBAS"), OPT("pil", 'l', arg_uint32, create_opt, pil, "PIL field of FLBAS"), - OPT("flbas", 'l', arg_uint32, create_opt, flbas, + OPT("flbas", 'L', arg_uint32, create_opt, flbas, "Namespace formatted logical block size setting"), OPT("dps", 'd', arg_uint32, create_opt, dps, "Data protection settings"), @@ -118,7 +185,7 @@ static const struct args create_args[] = { static struct cmd create_cmd = { .name = "create", .fn = nscreate, - .descr = "Create a new namespace", + .descr = "Create a namespace", .ctx_size = sizeof(create_opt), .opts = create_opts, .args = create_args, @@ -148,7 +215,7 @@ static const struct args delete_args[] = { static struct cmd delete_cmd = { .name = "delete", .fn = nsdelete, - .descr = "Delete a new namespace", + .descr = "Delete a namespace", .ctx_size = sizeof(delete_opt), .opts = delete_opts, .args = delete_args, @@ -169,7 +236,7 @@ static struct attach_options { static const struct opts attach_opts[] = { OPT("namespace-id", 'n', arg_uint32, attach_opt, nsid, "The namespace ID to attach"), - OPT("controller", 'c', arg_uint32, attach_opt, nsid, + OPT("controller", 'c', arg_uint32, attach_opt, ctrlrid, "The controller ID to attach"), OPT_END }; @@ -182,7 +249,7 @@ static const struct args attach_args[] = { static struct cmd attach_cmd = { .name = "attach", .fn = nsattach, - .descr = "Attach a new namespace", + .descr = "Attach a controller to a namespace", .ctx_size = sizeof(attach_opt), .opts = attach_opts, .args = attach_args, @@ -190,6 +257,36 @@ static struct cmd attach_cmd = { CMD_SUBCOMMAND(ns_cmd, attach_cmd); +static struct attached_options { + uint32_t nsid; + const char *dev; +} attached_opt = { + .nsid = NONE, + .dev = NULL, +}; + +static const struct opts attached_opts[] = { + OPT("namespace-id", 'n', arg_uint32, attached_opt, nsid, + "The namespace ID to request attached controllers"), + OPT_END +}; + +static const struct args attached_args[] = { + { arg_string, &attached_opt.dev, "controller-id" }, + { arg_none, NULL, NULL }, +}; + +static struct cmd attached_cmd = { + .name = "attached", + .fn = nsattached, + .descr = "List controllers attached to a namespace", + .ctx_size = sizeof(attached_opt), + .opts = attached_opts, + .args = attached_args, +}; + +CMD_SUBCOMMAND(ns_cmd, attached_cmd); + static struct detach_options { uint32_t nsid; uint32_t ctrlrid; @@ -203,7 +300,7 @@ static struct detach_options { static const struct opts detach_opts[] = { OPT("namespace-id", 'n', arg_uint32, detach_opt, nsid, "The namespace ID to detach"), - OPT("controller", 'c', arg_uint32, detach_opt, nsid, + OPT("controller", 'c', arg_uint32, detach_opt, ctrlrid, "The controller ID to detach"), OPT_END }; @@ -216,7 +313,7 @@ static const struct args detach_args[] = { static struct cmd detach_cmd = { .name = "detach", .fn = nsdetach, - .descr = "Detach a new namespace", + .descr = "Detach a controller from a namespace", .ctx_size = sizeof(detach_opt), .opts = detach_opts, .args = detach_args, @@ -224,8 +321,43 @@ static struct cmd detach_cmd = { CMD_SUBCOMMAND(ns_cmd, detach_cmd); -#define NS_USAGE \ - "ns (create|delete|attach|detach)\n" +static struct identify_options { + bool hex; + bool verbose; + const char *dev; + uint32_t nsid; +} identify_opt = { + .hex = false, + .verbose = false, + .dev = NULL, + .nsid = NONE, +}; + +static const struct opts identify_opts[] = { + OPT("hex", 'x', arg_none, identify_opt, hex, + "Print identiy information in hex"), + OPT("verbose", 'v', arg_none, identify_opt, verbose, + "More verbosity: print entire identify table"), + OPT("nsid", 'n', arg_uint32, identify_opt, nsid, + "The namespace ID to print IDENTIFY for"), + { NULL, 0, arg_none, NULL, NULL } +}; + +static const struct args identify_args[] = { + { arg_string, &identify_opt.dev, "controller-id" }, + { arg_none, NULL, NULL }, +}; + +static struct cmd identify_cmd = { + .name = "identify", + .fn = nsidentify, + .descr = "Print IDENTIFY for allocated namespace", + .ctx_size = sizeof(identify_opt), + .opts = identify_opts, + .args = identify_args, +}; + +CMD_SUBCOMMAND(ns_cmd, identify_cmd); /* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */ @@ -245,6 +377,8 @@ static struct ns_result_str ns_result[] = { { 0x1a, "Namespace is not attached"}, { 0x1b, "Thin provisioning not supported"}, { 0x1c, "Controller list invalid"}, + { 0x24, "ANA Group Identifier Invalid"}, + { 0x25, "ANA Attach Failed"}, { 0xFFFF, "Unknown"} }; @@ -261,6 +395,110 @@ get_res_str(uint16_t res) return t->str; } +static void +nsactive(const struct cmd *f, int argc, char *argv[]) +{ + struct nvme_pt_command pt; + int fd, i; + uint32_t list[1024]; + + if (arg_parse(argc, argv, f)) + return; + open_dev(active_opt.dev, &fd, 1, 1); + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = NVME_OPC_IDENTIFY; + pt.cmd.nsid = htole32(0); + pt.cmd.cdw10 = htole32(0x02); + pt.buf = list; + pt.len = sizeof(list); + pt.is_read = 1; + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(1, "identify request failed"); + if (nvme_completion_is_error(&pt.cpl)) + errx(1, "identify request returned error"); + + printf("Active namespaces:\n"); + for (i = 0; list[i] != 0; i++) + printf("%10d\n", le32toh(list[i])); + + exit(0); +} + +static void +nsallocated(const struct cmd *f, int argc, char *argv[]) +{ + struct nvme_pt_command pt; + struct nvme_controller_data cd; + int fd, i; + uint32_t list[1024]; + + if (arg_parse(argc, argv, f)) + return; + open_dev(active_opt.dev, &fd, 1, 1); + read_controller_data(fd, &cd); + + /* Check that controller can execute this command. */ + if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & + NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) + errx(1, "controller does not support namespace management"); + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = NVME_OPC_IDENTIFY; + pt.cmd.nsid = htole32(0); + pt.cmd.cdw10 = htole32(0x10); + pt.buf = list; + pt.len = sizeof(list); + pt.is_read = 1; + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(1, "identify request failed"); + if (nvme_completion_is_error(&pt.cpl)) + errx(1, "identify request returned error"); + + printf("Allocated namespaces:\n"); + for (i = 0; list[i] != 0; i++) + printf("%10d\n", le32toh(list[i])); + + exit(0); +} + +static void +nscontrollers(const struct cmd *f, int argc, char *argv[]) +{ + struct nvme_pt_command pt; + struct nvme_controller_data cd; + int fd, i, n; + uint16_t clist[2048]; + + if (arg_parse(argc, argv, f)) + return; + open_dev(controllers_opt.dev, &fd, 1, 1); + read_controller_data(fd, &cd); + + /* Check that controller can execute this command. */ + if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & + NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) + errx(1, "controller does not support namespace management"); + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = NVME_OPC_IDENTIFY; + pt.cmd.cdw10 = htole32(0x13); + pt.buf = clist; + pt.len = sizeof(clist); + pt.is_read = 1; + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(1, "identify request failed"); + if (nvme_completion_is_error(&pt.cpl)) + errx(1, "identify request returned error"); + + n = le16toh(clist[0]); + printf("NVM subsystem includes %d controller(s):\n", n); + for (i = 0; i < n; i++) + printf(" 0x%04x\n", le16toh(clist[i + 1])); + + exit(0); +} + /* * NS MGMT Command specific status values: * 0xa = Invalid Format @@ -323,8 +561,7 @@ nscreate(const struct cmd *f, int argc, char *argv[]) memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT; - - pt.cmd.cdw10 = 0; /* create */ + pt.cmd.cdw10 = htole32(0); /* create */ pt.buf = &nsdata; pt.len = sizeof(struct nvme_namespace_data); pt.is_read = 0; /* passthrough writes data to ctrlr */ @@ -366,7 +603,7 @@ nsdelete(const struct cmd *f, int argc, char *argv[]) memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT; - pt.cmd.cdw10 = 1; /* delete */ + pt.cmd.cdw10 = htole32(1); /* delete */ pt.buf = buf; pt.len = sizeof(buf); pt.is_read = 1; @@ -444,7 +681,7 @@ nsattach(const struct cmd *f, int argc, char *argv[]) memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT; - pt.cmd.cdw10 = 0; /* attach */ + pt.cmd.cdw10 = htole32(0); /* attach */ pt.cmd.nsid = attach_opt.nsid; pt.buf = &clist; pt.len = sizeof(clist); @@ -471,11 +708,11 @@ nsdetach(const struct cmd *f, int argc, char *argv[]) if (arg_parse(argc, argv, f)) return; - if (attach_opt.nsid == NONE) { + if (detach_opt.nsid == NONE) { fprintf(stderr, "No valid NSID specified\n"); arg_help(argc, argv, f); } - open_dev(attach_opt.dev, &fd, 1, 1); + open_dev(detach_opt.dev, &fd, 1, 1); read_controller_data(fd, &cd); /* Check that controller can execute this command. */ @@ -513,7 +750,7 @@ nsdetach(const struct cmd *f, int argc, char *argv[]) memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT; - pt.cmd.cdw10 = 1; /* detach */ + pt.cmd.cdw10 = htole32(1); /* detach */ pt.cmd.nsid = detach_opt.nsid; pt.buf = &clist; pt.len = sizeof(clist); @@ -530,6 +767,115 @@ nsdetach(const struct cmd *f, int argc, char *argv[]) exit(0); } +static void +nsattached(const struct cmd *f, int argc, char *argv[]) +{ + struct nvme_pt_command pt; + struct nvme_controller_data cd; + int fd, i, n; + uint16_t clist[2048]; + + if (arg_parse(argc, argv, f)) + return; + if (attached_opt.nsid == NONE) { + fprintf(stderr, "No valid NSID specified\n"); + arg_help(argc, argv, f); + } + open_dev(attached_opt.dev, &fd, 1, 1); + read_controller_data(fd, &cd); + + /* Check that controller can execute this command. */ + if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & + NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) + errx(1, "controller does not support namespace management"); + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = NVME_OPC_IDENTIFY; + pt.cmd.nsid = htole32(attached_opt.nsid); + pt.cmd.cdw10 = htole32(0x12); + pt.buf = clist; + pt.len = sizeof(clist); + pt.is_read = 1; + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(1, "identify request failed"); + if (nvme_completion_is_error(&pt.cpl)) + errx(1, "identify request returned error"); + + n = le16toh(clist[0]); + printf("Attached %d controller(s):\n", n); + for (i = 0; i < n; i++) + printf(" 0x%04x\n", le16toh(clist[i + 1])); + + exit(0); +} + +static void +nsidentify(const struct cmd *f, int argc, char *argv[]) +{ + struct nvme_pt_command pt; + struct nvme_controller_data cd; + struct nvme_namespace_data nsdata; + uint8_t *data; + int fd; + u_int i; + + if (arg_parse(argc, argv, f)) + return; + if (identify_opt.nsid == NONE) { + fprintf(stderr, "No valid NSID specified\n"); + arg_help(argc, argv, f); + } + open_dev(identify_opt.dev, &fd, 1, 1); + read_controller_data(fd, &cd); + + /* Check that controller can execute this command. */ + if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & + NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) + errx(1, "controller does not support namespace management"); + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = NVME_OPC_IDENTIFY; + pt.cmd.nsid = htole32(identify_opt.nsid); + pt.cmd.cdw10 = htole32(0x11); + pt.buf = &nsdata; + pt.len = sizeof(nsdata); + pt.is_read = 1; + + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(1, "identify request failed"); + + if (nvme_completion_is_error(&pt.cpl)) + errx(1, "identify request returned error"); + + close(fd); + + data = (uint8_t *)&nsdata; + for (i = 0; i < sizeof(nsdata); i++) { + if (data[i] != 0) + break; + } + if (i == sizeof(nsdata)) + errx(1, "namespace %d is not allocated", identify_opt.nsid); + + /* Convert data to host endian */ + nvme_namespace_data_swapbytes(&nsdata); + + if (identify_opt.hex) { + i = sizeof(struct nvme_namespace_data); + if (!identify_opt.verbose) { + for (; i > 384; i--) { + if (data[i - 1] != 0) + break; + } + } + print_hex(&nsdata, i); + exit(0); + } + + print_namespace(&nsdata); + exit(0); +} + static void ns(const struct cmd *nf __unused, int argc, char *argv[]) { diff --git a/sbin/nvmecontrol/nvmecontrol.8 b/sbin/nvmecontrol/nvmecontrol.8 index 214572ccd0ed..9fb174bc5d94 100644 --- a/sbin/nvmecontrol/nvmecontrol.8 +++ b/sbin/nvmecontrol/nvmecontrol.8 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 7, 2018 +.Dd July 31, 2019 .Dt NVMECONTROL 8 .Os .Sh NAME @@ -69,6 +69,51 @@ .Aq device id .Aq namespace id .Nm +.Ic ns active +.Aq device id +.Nm +.Ic ns allocated +.Aq device id +.Nm +.Ic ns attach +.Aq Fl n Ar nsid +.Aq Fl c Ar cntid +.Aq device id +.Nm +.Ic ns attached +.Aq Fl n Ar nsid +.Aq device id +.Nm +.Ic ns controllers +.Aq device id +.Nm +.Ic ns create +.Aq Fl s Ar nsze +.Op Fl c Ar ncap +.Op Fl f Ar lbaf +.Op Fl m Ar mset +.Op Fl n Ar nmic +.Op Fl p Ar pi +.Op Fl l Ar pil +.Op Fl L Ar flbas +.Op Fl d Ar dps +.Aq device id +.Nm +.Ic ns delete +.Aq Fl n Ar nsid +.Aq device id +.Nm +.Ic ns detach +.Aq Fl n Ar nsid +.Aq Fl c Ar cntid +.Aq device id +.Nm +.Ic ns identify +.Op Fl v +.Op Fl x +.Aq Fl n Ar nsid +.Aq device id +.Nm .Ic firmware .Op Fl s Ar slot .Op Fl f Ar path_to_firmware @@ -143,6 +188,10 @@ will list all valid vendors and pages. will print the page as hex. .Fl b will print the binary data for the page. +.Ss ns +Various namespace management commands. +If namespace management is supported by device, allow list, create and delete +namespaces, list, attach and detach controllers to namespaces. .Ss format Format either specified namespace, or all namespaces of specified controller, using specified parameters: diff --git a/sbin/nvmecontrol/nvmecontrol.c b/sbin/nvmecontrol/nvmecontrol.c index 7f8de5943eae..1c2ff18b17db 100644 --- a/sbin/nvmecontrol/nvmecontrol.c +++ b/sbin/nvmecontrol/nvmecontrol.c @@ -126,6 +126,7 @@ read_namespace_data(int fd, uint32_t nsid, struct nvme_namespace_data *nsdata) memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_IDENTIFY; pt.cmd.nsid = htole32(nsid); + pt.cmd.cdw10 = htole32(0); pt.buf = nsdata; pt.len = sizeof(*nsdata); pt.is_read = 1; diff --git a/sbin/nvmecontrol/nvmecontrol.h b/sbin/nvmecontrol/nvmecontrol.h index 4157ff595e91..27a20557773d 100644 --- a/sbin/nvmecontrol/nvmecontrol.h +++ b/sbin/nvmecontrol/nvmecontrol.h @@ -73,6 +73,7 @@ void parse_ns_str(const char *ns_str, char *ctrlr_str, uint32_t *nsid); 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 print_hex(void *data, uint32_t length); +void print_namespace(struct nvme_namespace_data *nsdata); void read_logpage(int fd, uint8_t log_page, uint32_t nsid, void *payload, uint32_t payload_size); void print_temp(uint16_t t);