From 2528d6a326efc9bd8b8f139f3cc765233464d57f Mon Sep 17 00:00:00 2001 From: Jim Harris Date: Tue, 9 Jul 2013 21:31:21 +0000 Subject: [PATCH] Send per-namespace logpage commands to the controller devnode, so they are processed as admin commands, not I/O commands. As part of this change, pull out the code for parsing a namespace node string into a separate function, since it is used for both identify and logpage commands. Sponsored by: Intel MFC after: 3 days --- sbin/nvmecontrol/identify.c | 20 +++-------- sbin/nvmecontrol/logpage.c | 65 +++++++++++++--------------------- sbin/nvmecontrol/nvmecontrol.c | 24 +++++++++++++ sbin/nvmecontrol/nvmecontrol.h | 1 + 4 files changed, 53 insertions(+), 57 deletions(-) diff --git a/sbin/nvmecontrol/identify.c b/sbin/nvmecontrol/identify.c index 1fe2a3495a4c..189f164310e0 100644 --- a/sbin/nvmecontrol/identify.c +++ b/sbin/nvmecontrol/identify.c @@ -31,7 +31,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include #include @@ -194,7 +193,6 @@ 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; @@ -223,23 +221,13 @@ identify_ns(int argc, char *argv[]) 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], NVME_NS_PREFIX, 10); - if (nsloc != NULL) - nsid = strtol(nsloc + 2, NULL, 10); - if (nsloc == NULL || (nsid == 0 && errno != 0)) - errx(1, "invalid namespace ID '%s'", argv[optind]); - /* * 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. + * 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. */ - snprintf(path, nsloc - argv[optind] + 1, "%s", argv[optind]); + parse_ns_str(argv[optind], path, &nsid); open_dev(path, &fd, 1, 1); read_namespace_data(fd, nsid, &nsdata); close(fd); diff --git a/sbin/nvmecontrol/logpage.c b/sbin/nvmecontrol/logpage.c index a26ce045999a..e3309885e39f 100644 --- a/sbin/nvmecontrol/logpage.c +++ b/sbin/nvmecontrol/logpage.c @@ -35,7 +35,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include #include @@ -242,12 +241,11 @@ logpage_usage(void) void logpage(int argc, char *argv[]) { - int fd, nsid, len; + int fd, nsid; int log_page = 0, pageflag = false; - int hexflag = false; - int allow_ns = false; - char ch, *p, *nsloc = NULL; - char *cname = NULL; + int hexflag = false, ns_specified; + char ch, *p; + char cname[64]; uint32_t size; void *buf; struct logpage_function *f; @@ -290,46 +288,31 @@ logpage(int argc, char *argv[]) if (optind >= argc) logpage_usage(); + if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) { + ns_specified = true; + parse_ns_str(argv[optind], cname, &nsid); + open_dev(cname, &fd, 1, 1); + } else { + ns_specified = false; + nsid = NVME_GLOBAL_NAMESPACE_TAG; + open_dev(argv[optind], &fd, 1, 1); + } + /* * The log page attribtues indicate whether or not the controller * supports the SMART/Health information log page on a per * namespace basis. */ - cname = malloc(strlen(NVME_CTRLR_PREFIX) + 2); - len = strlen(NVME_CTRLR_PREFIX) + 1; - cname = strncpy(cname, argv[optind], len); - open_dev(cname, &fd, 1, 1); - read_controller_data(fd, &cdata); - - if (log_page == NVME_LOG_HEALTH_INFORMATION && cdata.lpa.ns_smart != 0) - allow_ns = true; - - /* If a namespace id was specified, validate it's use */ - if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) { - if (!allow_ns) { - if (log_page != NVME_LOG_HEALTH_INFORMATION) - errx(1, - "log page %d valid only at controller level", - log_page); - else if (cdata.lpa.ns_smart == 0) - errx(1, - "controller does not support per " - "namespace smart/health information"); - } - nsloc = strnstr(argv[optind], NVME_NS_PREFIX, 10); - if (nsloc != NULL) - nsid = strtol(nsloc + 2, NULL, 10); - if (nsloc == NULL || (nsid == 0 && errno != 0)) - errx(1, "invalid namespace id '%s'", argv[optind]); - - /* - * User is asking for per namespace log page information - * so close the controller and open up the namespace. - */ - close(fd); - open_dev(argv[optind], &fd, 1, 1); - } else - nsid = NVME_GLOBAL_NAMESPACE_TAG; + if (ns_specified) { + if (log_page != NVME_LOG_HEALTH_INFORMATION) + errx(1, "log page %d valid only at controller level", + log_page); + read_controller_data(fd, &cdata); + if (cdata.lpa.ns_smart == 0) + errx(1, + "controller does not support per namespace " + "smart/health information"); + } print_fn = print_hex; if (!hexflag) { diff --git a/sbin/nvmecontrol/nvmecontrol.c b/sbin/nvmecontrol/nvmecontrol.c index c566bb3e6a39..63cec3ce82cb 100644 --- a/sbin/nvmecontrol/nvmecontrol.c +++ b/sbin/nvmecontrol/nvmecontrol.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -198,6 +199,29 @@ open_dev(const char *str, int *fd, int show_error, int exit_on_error) return (0); } +void +parse_ns_str(const char *ns_str, char *ctrlr_str, int *nsid) +{ + char *nsloc; + + /* + * 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(ns_str, NVME_NS_PREFIX, 10); + 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 main(int argc, char *argv[]) { diff --git a/sbin/nvmecontrol/nvmecontrol.h b/sbin/nvmecontrol/nvmecontrol.h index f7a35b4f1e23..99075f62e58c 100644 --- a/sbin/nvmecontrol/nvmecontrol.h +++ b/sbin/nvmecontrol/nvmecontrol.h @@ -63,6 +63,7 @@ void logpage(int argc, char *argv[]); void firmware(int argc, char *argv[]); 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, int *nsid); 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 print_hex(void *data, uint32_t length);