diff options
Diffstat (limited to 'sbin/nvmecontrol')
-rw-r--r-- | sbin/nvmecontrol/Makefile | 2 | ||||
-rw-r--r-- | sbin/nvmecontrol/identify.c | 321 | ||||
-rw-r--r-- | sbin/nvmecontrol/nvmecontrol.c | 279 | ||||
-rw-r--r-- | sbin/nvmecontrol/nvmecontrol.h | 1 |
4 files changed, 323 insertions, 280 deletions
diff --git a/sbin/nvmecontrol/Makefile b/sbin/nvmecontrol/Makefile index 4440c6f..e710942 100644 --- a/sbin/nvmecontrol/Makefile +++ b/sbin/nvmecontrol/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ PROG= nvmecontrol -SRCS= nvmecontrol.c devlist.c +SRCS= nvmecontrol.c devlist.c identify.c MAN= nvmecontrol.8 .include <bsd.prog.mk> diff --git a/sbin/nvmecontrol/identify.c b/sbin/nvmecontrol/identify.c new file mode 100644 index 0000000..6dcbebd --- /dev/null +++ b/sbin/nvmecontrol/identify.c @@ -0,0 +1,321 @@ +/*- + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> + +#include "nvmecontrol.h" + +static void +print_controller_hex(struct nvme_controller_data *cdata, uint32_t length) +{ + uint32_t *p; + uint32_t i, j; + + p = (uint32_t *)cdata; + length /= sizeof(uint32_t); + + for (i = 0; i < length; i+=8) { + printf("%03x: ", i*4); + for (j = 0; j < 8; j++) + printf("%08x ", p[i+j]); + printf("\n"); + } + + printf("\n"); +} + +static void +print_controller(struct nvme_controller_data *cdata) +{ + printf("Controller Capabilities/Features\n"); + printf("================================\n"); + printf("Vendor ID: %04x\n", cdata->vid); + printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); + printf("Serial Number: %s\n", cdata->sn); + printf("Model Number: %s\n", cdata->mn); + printf("Firmware Version: %s\n", cdata->fr); + printf("Recommended Arb Burst: %d\n", cdata->rab); + printf("IEEE OUI Identifier: %02x %02x %02x\n", + cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); + printf("Multi-Interface Cap: %02x\n", cdata->mic); + /* TODO: Use CAP.MPSMIN to determine true memory page size. */ + printf("Max Data Transfer Size: "); + if (cdata->mdts == 0) + printf("Unlimited\n"); + else + printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); + printf("\n"); + + printf("Admin Command Set Attributes\n"); + printf("============================\n"); + printf("Security Send/Receive: %s\n", + cdata->oacs.security ? "Supported" : "Not Supported"); + printf("Format NVM: %s\n", + cdata->oacs.format ? "Supported" : "Not Supported"); + printf("Firmware Activate/Download: %s\n", + cdata->oacs.firmware ? "Supported" : "Not Supported"); + printf("Abort Command Limit: %d\n", cdata->acl+1); + printf("Async Event Request Limit: %d\n", cdata->aerl+1); + printf("Number of Firmware Slots: "); + if (cdata->oacs.firmware != 0) + printf("%d\n", cdata->frmw.num_slots); + else + printf("N/A\n"); + printf("Firmware Slot 1 Read-Only: "); + if (cdata->oacs.firmware != 0) + printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No"); + else + printf("N/A\n"); + printf("Per-Namespace SMART Log: %s\n", + cdata->lpa.ns_smart ? "Yes" : "No"); + printf("Error Log Page Entries: %d\n", cdata->elpe+1); + printf("Number of Power States: %d\n", cdata->npss+1); + printf("\n"); + + printf("NVM Command Set Attributes\n"); + printf("==========================\n"); + printf("Submission Queue Entry Size\n"); + printf(" Max: %d\n", 1 << cdata->sqes.max); + printf(" Min: %d\n", 1 << cdata->sqes.min); + printf("Completion Queue Entry Size\n"); + printf(" Max: %d\n", 1 << cdata->cqes.max); + printf(" Min: %d\n", 1 << cdata->cqes.min); + printf("Number of Namespaces: %d\n", cdata->nn); + printf("Compare Command: %s\n", + cdata->oncs.compare ? "Supported" : "Not Supported"); + printf("Write Uncorrectable Command: %s\n", + cdata->oncs.write_unc ? "Supported" : "Not Supported"); + printf("Dataset Management Command: %s\n", + cdata->oncs.dsm ? "Supported" : "Not Supported"); + printf("Volatile Write Cache: %s\n", + cdata->vwc.present ? "Present" : "Not Present"); +} + +static void +print_namespace_hex(struct nvme_namespace_data *nsdata, uint32_t length) +{ + uint32_t *p; + uint32_t i, j; + + p = (uint32_t *)nsdata; + length /= sizeof(uint32_t); + + for (i = 0; i < length; i+=8) { + printf("%03x: ", i*4); + for (j = 0; j < 8; j++) + printf("%08x ", p[i+j]); + printf("\n"); + } + + printf("\n"); +} + +static void +print_namespace(struct nvme_namespace_data *nsdata) +{ + uint32_t i; + + printf("Size (in LBAs): %lld (%lldM)\n", + (long long)nsdata->nsze, + (long long)nsdata->nsze / 1024 / 1024); + printf("Capacity (in LBAs): %lld (%lldM)\n", + (long long)nsdata->ncap, + (long long)nsdata->ncap / 1024 / 1024); + printf("Utilization (in LBAs): %lld (%lldM)\n", + (long long)nsdata->nuse, + (long long)nsdata->nuse / 1024 / 1024); + printf("Thin Provisioning: %s\n", + nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported"); + printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); + printf("Current LBA Format: LBA Format #%d\n", + nsdata->flbas.format); + for (i = 0; i <= nsdata->nlbaf; i++) { + printf("LBA Format #%d:\n", i); + printf(" LBA Data Size: %d\n", + 1 << nsdata->lbaf[i].lbads); + } +} + +static void +identify_usage(void) +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, IDENTIFY_USAGE); + exit(EX_USAGE); +} + +static void +identify_ctrlr(int argc, char *argv[]) +{ + struct nvme_controller_data cdata; + int ch, fd, hexflag = 0, hexlength; + int verboseflag = 0; + + while ((ch = getopt(argc, argv, "vx")) != -1) { + switch ((char)ch) { + case 'v': + verboseflag = 1; + break; + case 'x': + hexflag = 1; + break; + default: + identify_usage(); + } + } + + open_dev(argv[optind], &fd, 1, 1); + read_controller_data(fd, &cdata); + close(fd); + + if (hexflag == 1) { + if (verboseflag == 1) + hexlength = sizeof(struct nvme_controller_data); + else + hexlength = offsetof(struct nvme_controller_data, + reserved5); + print_controller_hex(&cdata, hexlength); + exit(EX_OK); + } + + if (verboseflag == 1) { + printf("-v not currently supported without -x.\n"); + identify_usage(); + } + + print_controller(&cdata); + exit(EX_OK); +} + +static void +identify_ns(int argc, char *argv[]) +{ + struct nvme_namespace_data nsdata; + char path[64]; + char *nsloc; + int ch, fd, hexflag = 0, hexlength, nsid; + int verboseflag = 0; + + while ((ch = getopt(argc, argv, "vx")) != -1) { + switch ((char)ch) { + case 'v': + verboseflag = 1; + break; + case 'x': + hexflag = 1; + break; + default: + identify_usage(); + } + } + + /* + * 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(argv[optind], &fd, 1, 1); + close(fd); + + /* + * Pull the namespace id from the string. +2 skips past the "ns" part + * of the string. Don't search past 10 characters into the string, + * otherwise we know it is malformed. + */ + nsloc = strnstr(argv[optind], "ns", 10); + if (nsloc != NULL) + nsid = strtol(nsloc + 2, NULL, 10); + if (nsloc == NULL || (nsid == 0 && errno != 0)) { + printf("Invalid namespace ID %s.\n", argv[optind]); + exit(EX_IOERR); + } + + /* + * We send IDENTIFY commands to the controller, not the namespace, + * since it is an admin cmd. So the path should only include the + * nvmeX part of the nvmeXnsY string. + */ + snprintf(path, nsloc - argv[optind] + 1, "%s", argv[optind]); + open_dev(path, &fd, 1, 1); + read_namespace_data(fd, nsid, &nsdata); + close(fd); + + if (hexflag == 1) { + if (verboseflag == 1) + hexlength = sizeof(struct nvme_namespace_data); + else + hexlength = offsetof(struct nvme_namespace_data, + reserved6); + print_namespace_hex(&nsdata, hexlength); + exit(EX_OK); + } + + if (verboseflag == 1) { + printf("-v not currently supported without -x.\n"); + identify_usage(); + } + + print_namespace(&nsdata); + exit(EX_OK); +} + +void +identify(int argc, char *argv[]) +{ + char *target; + + if (argc < 2) + identify_usage(); + + while (getopt(argc, argv, "vx") != -1) ; + + target = argv[optind]; + + optreset = 1; + optind = 1; + + /* + * If device node contains "ns", we consider it a namespace, + * otherwise, consider it a controller. + */ + if (strstr(target, "ns") == NULL) + identify_ctrlr(argc, argv); + else + identify_ns(argc, argv); +} diff --git a/sbin/nvmecontrol/nvmecontrol.c b/sbin/nvmecontrol/nvmecontrol.c index a3286c1..18cd9e9 100644 --- a/sbin/nvmecontrol/nvmecontrol.c +++ b/sbin/nvmecontrol/nvmecontrol.c @@ -57,137 +57,6 @@ usage(void) exit(EX_USAGE); } -static void -print_controller_hex(struct nvme_controller_data *cdata, uint32_t length) -{ - uint32_t *p; - uint32_t i, j; - - p = (uint32_t *)cdata; - length /= sizeof(uint32_t); - - for (i = 0; i < length; i+=8) { - printf("%03x: ", i*4); - for (j = 0; j < 8; j++) - printf("%08x ", p[i+j]); - printf("\n"); - } - - printf("\n"); -} - -static void -print_controller(struct nvme_controller_data *cdata) -{ - printf("Controller Capabilities/Features\n"); - printf("================================\n"); - printf("Vendor ID: %04x\n", cdata->vid); - printf("Subsystem Vendor ID: %04x\n", cdata->ssvid); - printf("Serial Number: %s\n", cdata->sn); - printf("Model Number: %s\n", cdata->mn); - printf("Firmware Version: %s\n", cdata->fr); - printf("Recommended Arb Burst: %d\n", cdata->rab); - printf("IEEE OUI Identifier: %02x %02x %02x\n", - cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]); - printf("Multi-Interface Cap: %02x\n", cdata->mic); - /* TODO: Use CAP.MPSMIN to determine true memory page size. */ - printf("Max Data Transfer Size: "); - if (cdata->mdts == 0) - printf("Unlimited\n"); - else - printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); - printf("\n"); - - printf("Admin Command Set Attributes\n"); - printf("============================\n"); - printf("Security Send/Receive: %s\n", - cdata->oacs.security ? "Supported" : "Not Supported"); - printf("Format NVM: %s\n", - cdata->oacs.format ? "Supported" : "Not Supported"); - printf("Firmware Activate/Download: %s\n", - cdata->oacs.firmware ? "Supported" : "Not Supported"); - printf("Abort Command Limit: %d\n", cdata->acl+1); - printf("Async Event Request Limit: %d\n", cdata->aerl+1); - printf("Number of Firmware Slots: "); - if (cdata->oacs.firmware != 0) - printf("%d\n", cdata->frmw.num_slots); - else - printf("N/A\n"); - printf("Firmware Slot 1 Read-Only: "); - if (cdata->oacs.firmware != 0) - printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No"); - else - printf("N/A\n"); - printf("Per-Namespace SMART Log: %s\n", - cdata->lpa.ns_smart ? "Yes" : "No"); - printf("Error Log Page Entries: %d\n", cdata->elpe+1); - printf("Number of Power States: %d\n", cdata->npss+1); - printf("\n"); - - printf("NVM Command Set Attributes\n"); - printf("==========================\n"); - printf("Submission Queue Entry Size\n"); - printf(" Max: %d\n", 1 << cdata->sqes.max); - printf(" Min: %d\n", 1 << cdata->sqes.min); - printf("Completion Queue Entry Size\n"); - printf(" Max: %d\n", 1 << cdata->cqes.max); - printf(" Min: %d\n", 1 << cdata->cqes.min); - printf("Number of Namespaces: %d\n", cdata->nn); - printf("Compare Command: %s\n", - cdata->oncs.compare ? "Supported" : "Not Supported"); - printf("Write Uncorrectable Command: %s\n", - cdata->oncs.write_unc ? "Supported" : "Not Supported"); - printf("Dataset Management Command: %s\n", - cdata->oncs.dsm ? "Supported" : "Not Supported"); - printf("Volatile Write Cache: %s\n", - cdata->vwc.present ? "Present" : "Not Present"); -} - -static void -print_namespace_hex(struct nvme_namespace_data *nsdata, uint32_t length) -{ - uint32_t *p; - uint32_t i, j; - - p = (uint32_t *)nsdata; - length /= sizeof(uint32_t); - - for (i = 0; i < length; i+=8) { - printf("%03x: ", i*4); - for (j = 0; j < 8; j++) - printf("%08x ", p[i+j]); - printf("\n"); - } - - printf("\n"); -} - -static void -print_namespace(struct nvme_namespace_data *nsdata) -{ - uint32_t i; - - printf("Size (in LBAs): %lld (%lldM)\n", - (long long)nsdata->nsze, - (long long)nsdata->nsze / 1024 / 1024); - printf("Capacity (in LBAs): %lld (%lldM)\n", - (long long)nsdata->ncap, - (long long)nsdata->ncap / 1024 / 1024); - printf("Utilization (in LBAs): %lld (%lldM)\n", - (long long)nsdata->nuse, - (long long)nsdata->nuse / 1024 / 1024); - printf("Thin Provisioning: %s\n", - nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported"); - printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); - printf("Current LBA Format: LBA Format #%d\n", - nsdata->flbas.format); - for (i = 0; i <= nsdata->nlbaf; i++) { - printf("LBA Format #%d:\n", i); - printf(" LBA Data Size: %d\n", - 1 << nsdata->lbaf[i].lbads); - } -} - void read_controller_data(int fd, struct nvme_controller_data *cdata) { @@ -267,154 +136,6 @@ open_dev(const char *str, int *fd, int show_error, int exit_on_error) } static void -identify_usage(void) -{ - fprintf(stderr, "usage:\n"); - fprintf(stderr, IDENTIFY_USAGE); - exit(EX_USAGE); -} - -static void -identify_ctrlr(int argc, char *argv[]) -{ - struct nvme_controller_data cdata; - int ch, fd, hexflag = 0, hexlength; - int verboseflag = 0; - - while ((ch = getopt(argc, argv, "vx")) != -1) { - switch ((char)ch) { - case 'v': - verboseflag = 1; - break; - case 'x': - hexflag = 1; - break; - default: - identify_usage(); - } - } - - open_dev(argv[optind], &fd, 1, 1); - read_controller_data(fd, &cdata); - close(fd); - - if (hexflag == 1) { - if (verboseflag == 1) - hexlength = sizeof(struct nvme_controller_data); - else - hexlength = offsetof(struct nvme_controller_data, - reserved5); - print_controller_hex(&cdata, hexlength); - exit(EX_OK); - } - - if (verboseflag == 1) { - printf("-v not currently supported without -x.\n"); - identify_usage(); - } - - print_controller(&cdata); - exit(EX_OK); -} - -static void -identify_ns(int argc, char *argv[]) -{ - struct nvme_namespace_data nsdata; - char path[64]; - char *nsloc; - int ch, fd, hexflag = 0, hexlength, nsid; - int verboseflag = 0; - - while ((ch = getopt(argc, argv, "vx")) != -1) { - switch ((char)ch) { - case 'v': - verboseflag = 1; - break; - case 'x': - hexflag = 1; - break; - default: - identify_usage(); - } - } - - /* - * 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(argv[optind], &fd, 1, 1); - close(fd); - - /* - * Pull the namespace id from the string. +2 skips past the "ns" part - * of the string. Don't search past 10 characters into the string, - * otherwise we know it is malformed. - */ - nsloc = strnstr(argv[optind], "ns", 10); - if (nsloc != NULL) - nsid = strtol(nsloc + 2, NULL, 10); - if (nsloc == NULL || (nsid == 0 && errno != 0)) { - printf("Invalid namespace ID %s.\n", argv[optind]); - exit(EX_IOERR); - } - - /* - * We send IDENTIFY commands to the controller, not the namespace, - * since it is an admin cmd. So the path should only include the - * nvmeX part of the nvmeXnsY string. - */ - snprintf(path, nsloc - argv[optind] + 1, "%s", argv[optind]); - open_dev(path, &fd, 1, 1); - read_namespace_data(fd, nsid, &nsdata); - close(fd); - - if (hexflag == 1) { - if (verboseflag == 1) - hexlength = sizeof(struct nvme_namespace_data); - else - hexlength = offsetof(struct nvme_namespace_data, - reserved6); - print_namespace_hex(&nsdata, hexlength); - exit(EX_OK); - } - - if (verboseflag == 1) { - printf("-v not currently supported without -x.\n"); - identify_usage(); - } - - print_namespace(&nsdata); - exit(EX_OK); -} - -static void -identify(int argc, char *argv[]) -{ - char *target; - - if (argc < 2) - identify_usage(); - - while (getopt(argc, argv, "vx") != -1) ; - - target = argv[optind]; - - optreset = 1; - optind = 1; - - /* - * If device node contains "ns", we consider it a namespace, - * otherwise, consider it a controller. - */ - if (strstr(target, "ns") == NULL) - identify_ctrlr(argc, argv); - else - identify_ns(argc, argv); -} - -static void print_perftest(struct nvme_io_test *io_test, bool perthread) { uint32_t i, io_completed = 0, iops, mbps; diff --git a/sbin/nvmecontrol/nvmecontrol.h b/sbin/nvmecontrol/nvmecontrol.h index a026ced..40e048e 100644 --- a/sbin/nvmecontrol/nvmecontrol.h +++ b/sbin/nvmecontrol/nvmecontrol.h @@ -51,6 +51,7 @@ void read_controller_data(int fd, struct nvme_controller_data *cdata); void read_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata); void devlist(int argc, char *argv[]); +void identify(int argc, char *argv[]); #endif |