nvmecontrol.c revision 252670
1184251Smarcel/*-
2184251Smarcel * Copyright (C) 2012-2013 Intel Corporation
3184251Smarcel * All rights reserved.
4184251Smarcel *
5184251Smarcel * Redistribution and use in source and binary forms, with or without
6184251Smarcel * modification, are permitted provided that the following conditions
7184251Smarcel * are met:
8184251Smarcel * 1. Redistributions of source code must retain the above copyright
9184251Smarcel *    notice, this list of conditions and the following disclaimer.
10184251Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11184251Smarcel *    notice, this list of conditions and the following disclaimer in the
12184251Smarcel *    documentation and/or other materials provided with the distribution.
13184251Smarcel *
14184251Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15184251Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16184251Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17184251Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18184251Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19184251Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20184251Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21184251Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22184251Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23184251Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24184251Smarcel * SUCH DAMAGE.
25184251Smarcel */
26184251Smarcel
27184251Smarcel#include <sys/cdefs.h>
28184251Smarcel__FBSDID("$FreeBSD: stable/9/sbin/nvmecontrol/nvmecontrol.c 252670 2013-07-04 00:06:11Z jimharris $");
29184251Smarcel
30184251Smarcel#include <sys/param.h>
31184251Smarcel#include <sys/ioccom.h>
32184251Smarcel#include <sys/stat.h>
33188156Ssam
34188156Ssam#include <ctype.h>
35184251Smarcel#include <errno.h>
36184251Smarcel#include <fcntl.h>
37184251Smarcel#include <stdbool.h>
38184251Smarcel#include <stddef.h>
39184251Smarcel#include <stdio.h>
40184251Smarcel#include <stdlib.h>
41184251Smarcel#include <string.h>
42184251Smarcel#include <sysexits.h>
43184251Smarcel#include <unistd.h>
44184251Smarcel
45184251Smarcel#include "nvmecontrol.h"
46184251Smarcel
47184251Smarceltypedef void (*nvme_fn_t)(int argc, char *argv[]);
48184251Smarcel
49184251Smarcelstatic struct nvme_function {
50184251Smarcel	const char	*name;
51184251Smarcel	nvme_fn_t	fn;
52184251Smarcel	const char	*usage;
53184251Smarcel} funcs[] = {
54189606Ssam	{"devlist",	devlist,	DEVLIST_USAGE},
55184251Smarcel	{"identify",	identify,	IDENTIFY_USAGE},
56184251Smarcel	{"perftest",	perftest,	PERFTEST_USAGE},
57184251Smarcel	{"reset",	reset,		RESET_USAGE},
58184251Smarcel	{"logpage",	logpage,	LOGPAGE_USAGE},
59184251Smarcel	{NULL,		NULL,		NULL},
60184251Smarcel};
61184251Smarcel
62184251Smarcelstatic void
63184251Smarcelusage(void)
64184251Smarcel{
65184251Smarcel	struct nvme_function *f;
66184251Smarcel
67184251Smarcel	f = funcs;
68184251Smarcel	fprintf(stderr, "usage:\n");
69184251Smarcel	while (f->name != NULL) {
70184251Smarcel		fprintf(stderr, "%s", f->usage);
71184251Smarcel		f++;
72184251Smarcel	}
73184251Smarcel	exit(EX_USAGE);
74184251Smarcel}
75184251Smarcel
76184251Smarcelstatic void
77184251Smarcelprint_bytes(void *data, uint32_t length)
78184251Smarcel{
79184251Smarcel	uint32_t	i, j;
80184251Smarcel	uint8_t		*p, *end;
81184251Smarcel
82184251Smarcel	end = (uint8_t *)data + length;
83184251Smarcel
84184251Smarcel	for (i = 0; i < length; i++) {
85184251Smarcel		p = (uint8_t *)data + (i*16);
86184251Smarcel		printf("%03x: ", i*16);
87184251Smarcel		for (j = 0; j < 16 && p < end; j++)
88184251Smarcel			printf("%02x ", *p++);
89184251Smarcel		if (p >= end)
90184251Smarcel			break;
91184251Smarcel		printf("\n");
92184251Smarcel	}
93184251Smarcel	printf("\n");
94184251Smarcel}
95184251Smarcel
96184251Smarcelstatic void
97184251Smarcelprint_dwords(void *data, uint32_t length)
98184251Smarcel{
99184251Smarcel	uint32_t	*p;
100184251Smarcel	uint32_t	i, j;
101184251Smarcel
102184251Smarcel	p = (uint32_t *)data;
103184251Smarcel	length /= sizeof(uint32_t);
104184251Smarcel
105184251Smarcel	for (i = 0; i < length; i+=8) {
106184251Smarcel		printf("%03x: ", i*4);
107184251Smarcel		for (j = 0; j < 8; j++)
108184251Smarcel			printf("%08x ", p[i+j]);
109184251Smarcel		printf("\n");
110184251Smarcel	}
111184251Smarcel
112184251Smarcel	printf("\n");
113184251Smarcel}
114184251Smarcel
115184251Smarcelvoid
116184251Smarcelprint_hex(void *data, uint32_t length)
117184251Smarcel{
118184251Smarcel	if (length >= sizeof(uint32_t) || length % sizeof(uint32_t) == 0)
119184251Smarcel		print_dwords(data, length);
120184251Smarcel	else
121184251Smarcel		print_bytes(data, length);
122184251Smarcel}
123184251Smarcel
124184251Smarcelvoid
125184251Smarcelread_controller_data(int fd, struct nvme_controller_data *cdata)
126184251Smarcel{
127184251Smarcel	struct nvme_pt_command	pt;
128184251Smarcel
129184251Smarcel	memset(&pt, 0, sizeof(pt));
130184251Smarcel	pt.cmd.opc = NVME_OPC_IDENTIFY;
131184251Smarcel	pt.cmd.cdw10 = 1;
132184251Smarcel	pt.buf = cdata;
133184251Smarcel	pt.len = sizeof(*cdata);
134184251Smarcel	pt.is_read = 1;
135184251Smarcel
136184251Smarcel	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) {
137184251Smarcel		printf("Identify request failed. errno=%d (%s)\n",
138184251Smarcel		    errno, strerror(errno));
139184251Smarcel		exit(EX_IOERR);
140184251Smarcel	}
141184251Smarcel
142184251Smarcel	if (nvme_completion_is_error(&pt.cpl)) {
143184251Smarcel		printf("Passthrough command returned error.\n");
144184251Smarcel		exit(EX_IOERR);
145184251Smarcel	}
146184251Smarcel}
147184251Smarcel
148184251Smarcelvoid
149184251Smarcelread_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata)
150184251Smarcel{
151184251Smarcel	struct nvme_pt_command	pt;
152184251Smarcel
153184251Smarcel	memset(&pt, 0, sizeof(pt));
154184251Smarcel	pt.cmd.opc = NVME_OPC_IDENTIFY;
155188087Ssam	pt.cmd.nsid = nsid;
156188087Ssam	pt.buf = nsdata;
157188087Ssam	pt.len = sizeof(*nsdata);
158188087Ssam	pt.is_read = 1;
159188087Ssam
160188087Ssam	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) {
161188087Ssam		printf("Identify request failed. errno=%d (%s)\n",
162188087Ssam		    errno, strerror(errno));
163188087Ssam		exit(EX_IOERR);
164188087Ssam	}
165184251Smarcel
166184251Smarcel	if (nvme_completion_is_error(&pt.cpl)) {
167184251Smarcel		printf("Passthrough command returned error.\n");
168184251Smarcel		exit(EX_IOERR);
169184251Smarcel	}
170184251Smarcel}
171184251Smarcel
172184251Smarcelint
173184251Smarcelopen_dev(const char *str, int *fd, int show_error, int exit_on_error)
174184251Smarcel{
175184251Smarcel	struct stat	devstat;
176184251Smarcel	char		full_path[64];
177184251Smarcel
178184251Smarcel	if (!strnstr(str, NVME_CTRLR_PREFIX, strlen(NVME_CTRLR_PREFIX))) {
179184251Smarcel		if (show_error)
180184251Smarcel			fprintf(stderr,
181184251Smarcel			    "Controller/namespace IDs must begin with '%s'.\n",
182184251Smarcel			    NVME_CTRLR_PREFIX);
183184251Smarcel		if (exit_on_error)
184184251Smarcel			exit(EX_USAGE);
185184251Smarcel		else
186184251Smarcel			return (EX_USAGE);
187184251Smarcel	}
188184251Smarcel
189184251Smarcel	snprintf(full_path, sizeof(full_path), "/dev/%s", str);
190184251Smarcel	if (stat(full_path, &devstat) != 0) {
191184251Smarcel		if (show_error)
192184251Smarcel			fprintf(stderr, "Could not stat %s. errno=%d (%s)\n",
193184251Smarcel			    full_path, errno, strerror(errno));
194184251Smarcel		if (exit_on_error)
195184251Smarcel			exit(EX_NOINPUT);
196184251Smarcel		else
197184251Smarcel			return (EX_NOINPUT);
198184251Smarcel	}
199184251Smarcel
200184251Smarcel	*fd = open(full_path, O_RDWR);
201184251Smarcel	if (*fd < 0) {
202184251Smarcel		if (show_error)
203184251Smarcel			fprintf(stderr, "Could not open %s. errno=%d (%s)\n",
204184251Smarcel			    full_path, errno, strerror(errno));
205184251Smarcel		if (exit_on_error)
206184251Smarcel			exit(EX_NOPERM);
207184251Smarcel		else
208184251Smarcel			return (EX_NOPERM);
209184251Smarcel	}
210184251Smarcel
211184251Smarcel	return (EX_OK);
212184251Smarcel}
213184251Smarcel
214184251Smarcelint
215184251Smarcelmain(int argc, char *argv[])
216184251Smarcel{
217184251Smarcel	struct nvme_function *f;
218184251Smarcel
219184251Smarcel	if (argc < 2)
220184251Smarcel		usage();
221184251Smarcel
222184251Smarcel	f = funcs;
223184251Smarcel	while (f->name != NULL) {
224184251Smarcel		if (strcmp(argv[1], f->name) == 0)
225184251Smarcel			f->fn(argc-1, &argv[1]);
226184251Smarcel		f++;
227184251Smarcel	}
228184251Smarcel
229184251Smarcel	usage();
230184251Smarcel
231184251Smarcel	return (0);
232184251Smarcel}
233184251Smarcel
234184251Smarcel