xref: /dflybsd-src/sbin/nvmectl/nvmectl.c (revision 1cdf60d569383248aa03275555a7474f9e2b9f42)
17aa4eb96SMatthew Dillon /*
27aa4eb96SMatthew Dillon  * Copyright (c) 2016 The DragonFly Project.  All rights reserved.
37aa4eb96SMatthew Dillon  *
47aa4eb96SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
57aa4eb96SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
67aa4eb96SMatthew Dillon  *
77aa4eb96SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
87aa4eb96SMatthew Dillon  * modification, are permitted provided that the following conditions
97aa4eb96SMatthew Dillon  * are met:
107aa4eb96SMatthew Dillon  *
117aa4eb96SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
127aa4eb96SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
137aa4eb96SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
147aa4eb96SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
157aa4eb96SMatthew Dillon  *    the documentation and/or other materials provided with the
167aa4eb96SMatthew Dillon  *    distribution.
177aa4eb96SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
187aa4eb96SMatthew Dillon  *    contributors may be used to endorse or promote products derived
197aa4eb96SMatthew Dillon  *    from this software without specific, prior written permission.
207aa4eb96SMatthew Dillon  *
217aa4eb96SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
227aa4eb96SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
237aa4eb96SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
247aa4eb96SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
257aa4eb96SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
267aa4eb96SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
277aa4eb96SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
287aa4eb96SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
297aa4eb96SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
307aa4eb96SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
317aa4eb96SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
327aa4eb96SMatthew Dillon  * SUCH DAMAGE.
337aa4eb96SMatthew Dillon  */
347aa4eb96SMatthew Dillon 
357aa4eb96SMatthew Dillon #include "nvmectl.h"
367aa4eb96SMatthew Dillon 
377aa4eb96SMatthew Dillon typedef int (*cmd_t)(int ac, char **av, const char *id, int fd);
387aa4eb96SMatthew Dillon 
397aa4eb96SMatthew Dillon static cmd_t parsecmd(int ac, char **av, int *globokp);
407aa4eb96SMatthew Dillon static int cmd_info(int ac, char **av, const char *id, int fd);
41*1cdf60d5SMatthew Dillon static int cmd_errors(int ac, char **av, const char *id, int fd);
427aa4eb96SMatthew Dillon static void usage(int rc);
437aa4eb96SMatthew Dillon 
447aa4eb96SMatthew Dillon int VerboseOpt;
457aa4eb96SMatthew Dillon 
467aa4eb96SMatthew Dillon int
main(int ac,char ** av)477aa4eb96SMatthew Dillon main(int ac, char **av)
487aa4eb96SMatthew Dillon {
497aa4eb96SMatthew Dillon 	int rc = 0;
507aa4eb96SMatthew Dillon 	int ch;
517aa4eb96SMatthew Dillon 	int nvmei;
527aa4eb96SMatthew Dillon 	int globok;
537aa4eb96SMatthew Dillon 	int i;
547aa4eb96SMatthew Dillon 	cmd_t cmd;
557aa4eb96SMatthew Dillon 
567aa4eb96SMatthew Dillon 	while ((ch = getopt(ac, av, "v")) != -1) {
577aa4eb96SMatthew Dillon 		switch(ch) {
587aa4eb96SMatthew Dillon 		case 'v':
597aa4eb96SMatthew Dillon 			++VerboseOpt;
607aa4eb96SMatthew Dillon 			break;
617aa4eb96SMatthew Dillon 		default:
627aa4eb96SMatthew Dillon 			usage(1);
637aa4eb96SMatthew Dillon 			break;
647aa4eb96SMatthew Dillon 		}
657aa4eb96SMatthew Dillon 	}
667aa4eb96SMatthew Dillon 
677aa4eb96SMatthew Dillon 	ac -= optind;
687aa4eb96SMatthew Dillon 	av += optind;
697aa4eb96SMatthew Dillon 
707aa4eb96SMatthew Dillon 	for (nvmei = ac; nvmei > 0; --nvmei) {
717aa4eb96SMatthew Dillon 		if (strncmp(av[nvmei - 1], "nvme", 4) != 0)
727aa4eb96SMatthew Dillon 			break;
737aa4eb96SMatthew Dillon 	}
747aa4eb96SMatthew Dillon 	if (nvmei == 0)
757aa4eb96SMatthew Dillon 		usage(1);
767aa4eb96SMatthew Dillon 
777aa4eb96SMatthew Dillon 	globok = 0;
787aa4eb96SMatthew Dillon 	cmd = parsecmd(nvmei, av, &globok);
797aa4eb96SMatthew Dillon 
807aa4eb96SMatthew Dillon 	if (nvmei == ac && globok) {
817aa4eb96SMatthew Dillon 		i = 0;
827aa4eb96SMatthew Dillon 		for (;;) {
837aa4eb96SMatthew Dillon 			char *path;
847aa4eb96SMatthew Dillon 			int fd;
857aa4eb96SMatthew Dillon 
867aa4eb96SMatthew Dillon 			if (i)
877aa4eb96SMatthew Dillon 				printf("\n");
887aa4eb96SMatthew Dillon 			asprintf(&path, "/dev/nvme%d", i);
897aa4eb96SMatthew Dillon 			fd = open(path, O_RDWR);
907aa4eb96SMatthew Dillon 			free(path);
917aa4eb96SMatthew Dillon 			if (fd < 0)
927aa4eb96SMatthew Dillon 				break;
937aa4eb96SMatthew Dillon 			rc += cmd(nvmei, av, path + 5, fd);
947aa4eb96SMatthew Dillon 			close(fd);
957aa4eb96SMatthew Dillon 			++i;
967aa4eb96SMatthew Dillon 		}
977aa4eb96SMatthew Dillon 	} else if (nvmei == ac && !globok) {
987aa4eb96SMatthew Dillon 		fprintf(stderr, "must specify nvmeX device for command\n");
997aa4eb96SMatthew Dillon 	} else {
1007aa4eb96SMatthew Dillon 		for (i = nvmei; i < ac; ++i) {
1017aa4eb96SMatthew Dillon 			char *path;
1027aa4eb96SMatthew Dillon 			int fd;
1037aa4eb96SMatthew Dillon 
1047aa4eb96SMatthew Dillon 			if (i != nvmei)
1057aa4eb96SMatthew Dillon 				printf("\n");
1067aa4eb96SMatthew Dillon 
1077aa4eb96SMatthew Dillon 			asprintf(&path, "/dev/%s", av[i]);
1087aa4eb96SMatthew Dillon 			fd = open(path, O_RDWR);
1097aa4eb96SMatthew Dillon 			if (fd < 0) {
1107aa4eb96SMatthew Dillon 				fprintf(stderr, "open \"%s\": %s\n",
1117aa4eb96SMatthew Dillon 					path,
1127aa4eb96SMatthew Dillon 					strerror(errno));
1137aa4eb96SMatthew Dillon 			} else {
1147aa4eb96SMatthew Dillon 				rc += cmd(nvmei, av, path + 5, fd);
1157aa4eb96SMatthew Dillon 				close(fd);
1167aa4eb96SMatthew Dillon 			}
1177aa4eb96SMatthew Dillon 			free(path);
1187aa4eb96SMatthew Dillon 		}
1197aa4eb96SMatthew Dillon 	}
1207aa4eb96SMatthew Dillon 	return (rc ? 1 : 0);
1217aa4eb96SMatthew Dillon }
1227aa4eb96SMatthew Dillon 
1237aa4eb96SMatthew Dillon static
1247aa4eb96SMatthew Dillon cmd_t
parsecmd(int ac,char ** av,int * globokp)1257aa4eb96SMatthew Dillon parsecmd(int ac, char **av, int *globokp)
1267aa4eb96SMatthew Dillon {
1277aa4eb96SMatthew Dillon 	if (ac == 0)
1287aa4eb96SMatthew Dillon 		usage(1);
1297aa4eb96SMatthew Dillon 	if (strcmp(av[0], "info") == 0) {
1307aa4eb96SMatthew Dillon 		*globokp = 1;
1317aa4eb96SMatthew Dillon 		return cmd_info;
1327aa4eb96SMatthew Dillon 	}
133*1cdf60d5SMatthew Dillon 	if (strcmp(av[0], "errors") == 0) {
134*1cdf60d5SMatthew Dillon 		*globokp = 1;
135*1cdf60d5SMatthew Dillon 		return cmd_errors;
136*1cdf60d5SMatthew Dillon 	}
1377aa4eb96SMatthew Dillon 	fprintf(stderr, "Command %s not recognized\n", av[0]);
1387aa4eb96SMatthew Dillon 
1397aa4eb96SMatthew Dillon 	usage(1);
1407aa4eb96SMatthew Dillon 	return NULL;	/* NOT REACHED */
1417aa4eb96SMatthew Dillon }
1427aa4eb96SMatthew Dillon 
1437aa4eb96SMatthew Dillon static
1447aa4eb96SMatthew Dillon int
cmd_info(int ac __unused,char ** av __unused,const char * id,int fd)1457aa4eb96SMatthew Dillon cmd_info(int ac __unused, char **av __unused, const char *id, int fd)
1467aa4eb96SMatthew Dillon {
1477aa4eb96SMatthew Dillon 	nvme_getlog_ioctl_t ioc;
1487aa4eb96SMatthew Dillon 	nvme_log_smart_data_t *smart;
1497aa4eb96SMatthew Dillon 	int count;
1507aa4eb96SMatthew Dillon 	int i;
1517aa4eb96SMatthew Dillon 
1527aa4eb96SMatthew Dillon 	bzero(&ioc, sizeof(ioc));
1537aa4eb96SMatthew Dillon 	ioc.lid = NVME_LID_SMART;
1547aa4eb96SMatthew Dillon 	ioc.ret_size = sizeof(ioc.info.logsmart);
1557aa4eb96SMatthew Dillon 
1567aa4eb96SMatthew Dillon 	if (ioctl(fd, NVMEIOCGETLOG, &ioc) < 0) {
1577aa4eb96SMatthew Dillon 		fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
1587aa4eb96SMatthew Dillon 		return 1;
1597aa4eb96SMatthew Dillon 	}
1607aa4eb96SMatthew Dillon 	if (NVME_COMQ_STATUS_CODE_GET(ioc.status)) {
1617aa4eb96SMatthew Dillon 		fprintf(stderr, "%s: type %d code 0x%02x\n",
1627aa4eb96SMatthew Dillon 			id,
1637aa4eb96SMatthew Dillon 			NVME_COMQ_STATUS_TYPE_GET(ioc.status),
1647aa4eb96SMatthew Dillon 			NVME_COMQ_STATUS_CODE_GET(ioc.status));
1657aa4eb96SMatthew Dillon 		return 1;
1667aa4eb96SMatthew Dillon 	}
1677aa4eb96SMatthew Dillon 	printf("%s:\n", id);
1687aa4eb96SMatthew Dillon 	smart = &ioc.info.logsmart;
1697aa4eb96SMatthew Dillon 
1707aa4eb96SMatthew Dillon 	printf("\tcrit_flags:\t");
1717aa4eb96SMatthew Dillon 	if (smart->crit_flags) {
1727aa4eb96SMatthew Dillon 		if (smart->crit_flags & NVME_SMART_CRF_RES80)
1737aa4eb96SMatthew Dillon 			printf(" 80");
1747aa4eb96SMatthew Dillon 		if (smart->crit_flags & NVME_SMART_CRF_RES40)
1757aa4eb96SMatthew Dillon 			printf(" 40");
1767aa4eb96SMatthew Dillon 		if (smart->crit_flags & NVME_SMART_CRF_RES20)
1777aa4eb96SMatthew Dillon 			printf(" 20");
1787aa4eb96SMatthew Dillon 		if (smart->crit_flags & NVME_SMART_CRF_VOLTL_BKUP_FAIL)
1797aa4eb96SMatthew Dillon 			printf(" MEM_BACKUP_FAILED");
1807aa4eb96SMatthew Dillon 		if (smart->crit_flags & NVME_SMART_CRF_MEDIA_RO)
1817aa4eb96SMatthew Dillon 			printf(" MEDIA_RDONLY");
1827aa4eb96SMatthew Dillon 		if (smart->crit_flags & NVME_SMART_CRF_UNRELIABLE)
1837aa4eb96SMatthew Dillon 			printf(" MEDIA_UNRELIABLE");
1847aa4eb96SMatthew Dillon 		if (smart->crit_flags & NVME_SMART_CRF_ABOVE_THRESH)
1857aa4eb96SMatthew Dillon 			printf(" TOO_HOT");
1867aa4eb96SMatthew Dillon 		if (smart->crit_flags & NVME_SMART_CRF_BELOW_THRESH)
1877aa4eb96SMatthew Dillon 			printf(" TOO_COLD");
1887aa4eb96SMatthew Dillon 	} else {
1897aa4eb96SMatthew Dillon 		printf("none\n");
1907aa4eb96SMatthew Dillon 	}
191*1cdf60d5SMatthew Dillon 	printf("\tcomp_temp:\t%dC\n",
192*1cdf60d5SMatthew Dillon 		(int)(smart->comp_temp1 + (smart->comp_temp2 << 8)) - 273);
1937aa4eb96SMatthew Dillon 	printf("\tLIFE_LEFT:\t%d%% (%d%% used)\n",
1947aa4eb96SMatthew Dillon 		100 - (int)smart->rated_life,
1957aa4eb96SMatthew Dillon 		(int)smart->rated_life);
1967aa4eb96SMatthew Dillon 
1977aa4eb96SMatthew Dillon 	printf("\tread_bytes:\t%s\n",
1987aa4eb96SMatthew Dillon 	       format_number(smart->read_count[0] * 512000));
1997aa4eb96SMatthew Dillon 	printf("\twrite_bytes:\t%s\n",
2007aa4eb96SMatthew Dillon 	       format_number(smart->write_count[0] * 512000));
2017aa4eb96SMatthew Dillon 	printf("\tread_cmds:\t%s\n",
2027aa4eb96SMatthew Dillon 	       format_number(smart->read_cmds[0]));
2037aa4eb96SMatthew Dillon 	printf("\twrite_cmds:\t%s\n",
2047aa4eb96SMatthew Dillon 	       format_number(smart->write_cmds[0]));
2057aa4eb96SMatthew Dillon 	printf("\tbusy_time:\t%ld min (%1.2f hrs)\n",
2067aa4eb96SMatthew Dillon 		smart->busy_time[0],
2077aa4eb96SMatthew Dillon 		(double)smart->busy_time[0] / 60.0);
2087aa4eb96SMatthew Dillon 	printf("\tpowon_hours:\t%ld\n", smart->powon_hours[0]);
2097aa4eb96SMatthew Dillon 	printf("\tpower_cyc:\t%ld\n", smart->power_cycles[0]);
2107aa4eb96SMatthew Dillon 	printf("\tunsafe_shut:\t%ld\n", smart->unsafe_shutdowns[0]);
2117aa4eb96SMatthew Dillon 
2127aa4eb96SMatthew Dillon 	printf("\tUNRECOV_ERR:\t%ld", smart->unrecoverable_errors[0]);
2137aa4eb96SMatthew Dillon 	if (smart->unrecoverable_errors[0])
2147aa4eb96SMatthew Dillon 		printf("\t*******WARNING*******");
2157aa4eb96SMatthew Dillon 	printf("\n");
2167aa4eb96SMatthew Dillon 
2177aa4eb96SMatthew Dillon 	printf("\terr_log_ent:\t%ld\n", smart->error_log_entries[0]);
2187aa4eb96SMatthew Dillon 	printf("\twarn_temp_time:\t%d min (%1.2f hrs)\n",
2197aa4eb96SMatthew Dillon 		smart->warn_comp_temp_time,
2207aa4eb96SMatthew Dillon 		(double)smart->warn_comp_temp_time / 60.0);
2217aa4eb96SMatthew Dillon 	printf("\tcrit_temp_time:\t%d min (%1.2f hrs)\n",
2227aa4eb96SMatthew Dillon 		smart->crit_comp_temp_time,
2237aa4eb96SMatthew Dillon 		(double)smart->crit_comp_temp_time / 60.0);
2247aa4eb96SMatthew Dillon 
2257aa4eb96SMatthew Dillon 	printf("\ttemp_sensors:\t");
2267aa4eb96SMatthew Dillon 	for (i = count = 0; i < 8; ++i) {
2277aa4eb96SMatthew Dillon 		if (smart->temp_sensors[i]) {
2287aa4eb96SMatthew Dillon 			if (count)
2297aa4eb96SMatthew Dillon 				printf(" ");
2307aa4eb96SMatthew Dillon 			printf("%dC", smart->temp_sensors[i] - 273);
2317aa4eb96SMatthew Dillon 			++count;
2327aa4eb96SMatthew Dillon 		}
2337aa4eb96SMatthew Dillon 	}
2347aa4eb96SMatthew Dillon 	if (count == 0)
2357aa4eb96SMatthew Dillon 		printf("none");
2367aa4eb96SMatthew Dillon 	printf("\n");
2377aa4eb96SMatthew Dillon 
2387aa4eb96SMatthew Dillon 	return 0;
2397aa4eb96SMatthew Dillon }
2407aa4eb96SMatthew Dillon 
2417aa4eb96SMatthew Dillon static
242*1cdf60d5SMatthew Dillon int
cmd_errors(int ac __unused,char ** av __unused,const char * id,int fd)243*1cdf60d5SMatthew Dillon cmd_errors(int ac __unused, char **av __unused, const char *id, int fd)
244*1cdf60d5SMatthew Dillon {
245*1cdf60d5SMatthew Dillon 	nvme_getlog_ioctl_t ioc;
246*1cdf60d5SMatthew Dillon 	nvme_log_error_data_t *errs;
247*1cdf60d5SMatthew Dillon 	int i;
248*1cdf60d5SMatthew Dillon 
249*1cdf60d5SMatthew Dillon 	bzero(&ioc, sizeof(ioc));
250*1cdf60d5SMatthew Dillon 	ioc.lid = NVME_LID_ERROR;
251*1cdf60d5SMatthew Dillon 	ioc.ret_size = sizeof(ioc.info.logsmart);
252*1cdf60d5SMatthew Dillon 
253*1cdf60d5SMatthew Dillon 	if (ioctl(fd, NVMEIOCGETLOG, &ioc) < 0) {
254*1cdf60d5SMatthew Dillon 		fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
255*1cdf60d5SMatthew Dillon 		return 1;
256*1cdf60d5SMatthew Dillon 	}
257*1cdf60d5SMatthew Dillon 	if (NVME_COMQ_STATUS_CODE_GET(ioc.status)) {
258*1cdf60d5SMatthew Dillon 		fprintf(stderr, "%s: type %d code 0x%02x\n",
259*1cdf60d5SMatthew Dillon 			id,
260*1cdf60d5SMatthew Dillon 			NVME_COMQ_STATUS_TYPE_GET(ioc.status),
261*1cdf60d5SMatthew Dillon 			NVME_COMQ_STATUS_CODE_GET(ioc.status));
262*1cdf60d5SMatthew Dillon 		return 1;
263*1cdf60d5SMatthew Dillon 	}
264*1cdf60d5SMatthew Dillon 	printf("%s:\n", id);
265*1cdf60d5SMatthew Dillon 	errs = &ioc.info.logerr[0];
266*1cdf60d5SMatthew Dillon 
267*1cdf60d5SMatthew Dillon 	for (i = 0; i < 64; ++i) {
268*1cdf60d5SMatthew Dillon 		if (errs->error_count == 0 && errs->subq_id == 0 &&
269*1cdf60d5SMatthew Dillon 		    errs->cmd_id == 0 && errs->status == 0 &&
270*1cdf60d5SMatthew Dillon 		    errs->param == 0 && errs->nsid == 0 &&
271*1cdf60d5SMatthew Dillon 		    errs->vendor == 0 && errs->csi == 0 && errs->lba == 0)
272*1cdf60d5SMatthew Dillon 			continue;
273*1cdf60d5SMatthew Dillon 
274*1cdf60d5SMatthew Dillon 		if (errs->param || errs->vendor || errs->csi) {
275*1cdf60d5SMatthew Dillon 			printf("\t%2d cnt=%-3ld subq=%-2d cmdi=%-3d "
276*1cdf60d5SMatthew Dillon 			       "status=%d,0x%02x parm=%04x nsid=%-3d vend=%d "
277*1cdf60d5SMatthew Dillon 			       "csi=0x%lx lba=%ld",
278*1cdf60d5SMatthew Dillon 			       i, errs->error_count,
279*1cdf60d5SMatthew Dillon 			       (int16_t)errs->subq_id,
280*1cdf60d5SMatthew Dillon 			       (int16_t)errs->cmd_id,
281*1cdf60d5SMatthew Dillon 			       NVME_COMQ_STATUS_TYPE_GET(errs->status),
282*1cdf60d5SMatthew Dillon 			       NVME_COMQ_STATUS_CODE_GET(errs->status),
283*1cdf60d5SMatthew Dillon 			       errs->param, errs->nsid,
284*1cdf60d5SMatthew Dillon 			       errs->vendor,
285*1cdf60d5SMatthew Dillon 			       errs->csi, errs->lba);
286*1cdf60d5SMatthew Dillon 		} else {
287*1cdf60d5SMatthew Dillon 			printf("\t%2d cnt=%-3ld subq=%-2d cmdi=%-3d "
288*1cdf60d5SMatthew Dillon 			       "status=%d,0x%02x nsid=%-3d lba=%ld",
289*1cdf60d5SMatthew Dillon 			       i, errs->error_count,
290*1cdf60d5SMatthew Dillon 			       (int16_t)errs->subq_id,
291*1cdf60d5SMatthew Dillon 			       (int16_t)errs->cmd_id,
292*1cdf60d5SMatthew Dillon 			       NVME_COMQ_STATUS_TYPE_GET(errs->status),
293*1cdf60d5SMatthew Dillon 			       NVME_COMQ_STATUS_CODE_GET(errs->status),
294*1cdf60d5SMatthew Dillon 			       errs->nsid,
295*1cdf60d5SMatthew Dillon 			       errs->lba);
296*1cdf60d5SMatthew Dillon 		}
297*1cdf60d5SMatthew Dillon 		if (errs->status & NVME_COMQ_STATUS_DNR)
298*1cdf60d5SMatthew Dillon 			printf(" DNR");
299*1cdf60d5SMatthew Dillon 		printf(" %s\n", status_to_str(errs->status));
300*1cdf60d5SMatthew Dillon 		++errs;
301*1cdf60d5SMatthew Dillon 	}
302*1cdf60d5SMatthew Dillon 
303*1cdf60d5SMatthew Dillon 	return 0;
304*1cdf60d5SMatthew Dillon }
305*1cdf60d5SMatthew Dillon 
306*1cdf60d5SMatthew Dillon static
3077aa4eb96SMatthew Dillon void
usage(int rc)3087aa4eb96SMatthew Dillon usage(int rc)
3097aa4eb96SMatthew Dillon {
3107aa4eb96SMatthew Dillon 	fprintf(stderr,
3117aa4eb96SMatthew Dillon 		"nvmectl [-v] cmd [nvme0,1,2...]\n"
3127aa4eb96SMatthew Dillon 		"\tinfo\n"
313*1cdf60d5SMatthew Dillon 		"\terrors\n"
3147aa4eb96SMatthew Dillon 	);
3157aa4eb96SMatthew Dillon 	exit(rc);
3167aa4eb96SMatthew Dillon }
317