nvmecontrol.c revision 252278
1139749Simp/*-
2197404Sjoel * Copyright (C) 2012-2013 Intel Corporation
3197404Sjoel * All rights reserved.
4197404Sjoel *
550724Scg * Redistribution and use in source and binary forms, with or without
6197404Sjoel * modification, are permitted provided that the following conditions
7197404Sjoel * are met:
8197404Sjoel * 1. Redistributions of source code must retain the above copyright
9197404Sjoel *    notice, this list of conditions and the following disclaimer.
10197404Sjoel * 2. Redistributions in binary form must reproduce the above copyright
11197404Sjoel *    notice, this list of conditions and the following disclaimer in the
12197404Sjoel *    documentation and/or other materials provided with the distribution.
13197404Sjoel *
14197404Sjoel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15197404Sjoel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16197404Sjoel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17197404Sjoel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18197404Sjoel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19197404Sjoel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20197404Sjoel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21197404Sjoel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22197404Sjoel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23197404Sjoel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24197404Sjoel * SUCH DAMAGE.
25197404Sjoel */
26197404Sjoel
27197404Sjoel#include <sys/cdefs.h>
28197404Sjoel__FBSDID("$FreeBSD: head/sbin/nvmecontrol/nvmecontrol.c 252278 2013-06-27 00:08:25Z jimharris $");
29119853Scg
30197404Sjoel#include <sys/param.h>
3150724Scg#include <sys/ioccom.h>
3250724Scg#include <sys/stat.h>
3350724Scg
3450724Scg#include <ctype.h>
3550724Scg#include <errno.h>
3650724Scg#include <fcntl.h>
3750724Scg#include <stdbool.h>
3850724Scg#include <stddef.h>
3950724Scg#include <stdio.h>
4050724Scg#include <stdlib.h>
4150724Scg#include <string.h>
4250724Scg#include <sysexits.h>
4350724Scg#include <unistd.h>
4450724Scg
4550724Scg#include "nvmecontrol.h"
4650724Scg
4750724Scgtypedef void (*nvme_fn_t)(int argc, char *argv[]);
4850724Scg
4950724Scgstruct nvme_function {
5050724Scg	const char	*name;
5150724Scg	nvme_fn_t	fn;
5250724Scg	const char	*usage;
5350724Scg} funcs[] = {
5450724Scg	{"devlist",	devlist,	DEVLIST_USAGE},
5550724Scg	{"identify",	identify,	IDENTIFY_USAGE},
5650724Scg	{"perftest",	perftest,	PERFTEST_USAGE},
5750724Scg	{"reset",	reset,		RESET_USAGE},
5850724Scg	{"logpage",	logpage,	LOGPAGE_USAGE},
5950724Scg	{"firmware",	firmware,	FIRMWARE_USAGE},
6050724Scg	{NULL,		NULL,		NULL},
6150724Scg};
6250724Scg
6350724Scgstatic void
6450724Scgusage(void)
6553413Sroger{
66197404Sjoel	struct nvme_function *f;
67197404Sjoel
68197404Sjoel	f = funcs;
6953413Sroger	fprintf(stderr, "usage:\n");
7053413Sroger	while (f->name != NULL) {
7154831Scg		fprintf(stderr, "%s", f->usage);
7254831Scg		f++;
7353413Sroger	}
7453413Sroger	exit(EX_USAGE);
7553413Sroger}
76193640Sariff
77193640Sariffstatic void
78193640Sariffprint_bytes(void *data, uint32_t length)
79193640Sariff{
8053465Scg	uint32_t	i, j;
8153465Scg	uint8_t		*p, *end;
8253465Scg
8350724Scg	end = (uint8_t *)data + length;
84119287Simp
85119287Simp	for (i = 0; i < length; i++) {
8650724Scg		p = (uint8_t *)data + (i*16);
8753413Sroger		printf("%03x: ", i*16);
8853413Sroger		for (j = 0; j < 16 && p < end; j++)
8970134Scg			printf("%02x ", *p++);
9070134Scg		if (p >= end)
9182180Scg			break;
9282180Scg		printf("\n");
9350724Scg	}
9450724Scg	printf("\n");
9550724Scg}
9650724Scg
9753413Srogerstatic void
9856154Speterprint_dwords(void *data, uint32_t length)
9976086Scg{
100119548Sorion	uint32_t	*p;
10150724Scg	uint32_t	i, j;
10278033Scg
10376086Scg	p = (uint32_t *)data;
10476086Scg	length /= sizeof(uint32_t);
10576086Scg
10676086Scg	for (i = 0; i < length; i+=8) {
10776086Scg		printf("%03x: ", i*4);
10876086Scg		for (j = 0; j < 8; j++)
10976086Scg			printf("%08x ", p[i+j]);
11076086Scg		printf("\n");
11176086Scg	}
11276086Scg
11395678Scg	printf("\n");
11476086Scg}
115119548Sorion
116119548Sorionvoid
11784658Scgprint_hex(void *data, uint32_t length)
11859019Scg{
119152419Sariff	if (length >= sizeof(uint32_t) || length % sizeof(uint32_t) == 0)
120152419Sariff		print_dwords(data, length);
121152419Sariff	else
122152419Sariff		print_bytes(data, length);
123152419Sariff}
124152419Sariff
125167648Sariffvoid
126167648Sariffread_controller_data(int fd, struct nvme_controller_data *cdata)
127167648Sariff{
128167648Sariff	struct nvme_pt_command	pt;
129167648Sariff
130152419Sariff	memset(&pt, 0, sizeof(pt));
131152419Sariff	pt.cmd.opc = NVME_OPC_IDENTIFY;
132152419Sariff	pt.cmd.cdw10 = 1;
13350724Scg	pt.buf = cdata;
13450724Scg	pt.len = sizeof(*cdata);
13550724Scg	pt.is_read = 1;
13655209Scg
13750724Scg	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) {
13874763Scg		printf("Identify request failed. errno=%d (%s)\n",
13974763Scg		    errno, strerror(errno));
140152419Sariff		exit(EX_IOERR);
141152419Sariff	}
142164614Sariff
143164614Sariff	if (nvme_completion_is_error(&pt.cpl)) {
144164614Sariff		printf("Passthrough command returned error.\n");
14555209Scg		exit(EX_IOERR);
14650724Scg	}
147152419Sariff}
148152419Sariff
149152419Sariffvoid
150152419Sariffread_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata)
151152419Sariff{
152152419Sariff	struct nvme_pt_command	pt;
153152419Sariff
154152419Sariff	memset(&pt, 0, sizeof(pt));
155152419Sariff	pt.cmd.opc = NVME_OPC_IDENTIFY;
156152419Sariff	pt.cmd.nsid = nsid;
157152419Sariff	pt.buf = nsdata;
158152419Sariff	pt.len = sizeof(*nsdata);
159152419Sariff	pt.is_read = 1;
160152419Sariff
161152419Sariff	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) {
162152419Sariff		printf("Identify request failed. errno=%d (%s)\n",
163152419Sariff		    errno, strerror(errno));
164152419Sariff		exit(EX_IOERR);
165152419Sariff	}
166152419Sariff
167152419Sariff	if (nvme_completion_is_error(&pt.cpl)) {
168152419Sariff		printf("Passthrough command returned error.\n");
169152419Sariff		exit(EX_IOERR);
170152419Sariff	}
171152419Sariff}
172152419Sariff
173152419Sariffint
174152419Sariffopen_dev(const char *str, int *fd, int show_error, int exit_on_error)
175152419Sariff{
176152419Sariff	struct stat	devstat;
177152419Sariff	char		full_path[64];
178152419Sariff
179152419Sariff	if (!strnstr(str, NVME_CTRLR_PREFIX, strlen(NVME_CTRLR_PREFIX))) {
180152419Sariff		if (show_error)
181152419Sariff			fprintf(stderr,
182152419Sariff			    "Controller/namespace IDs must begin with '%s'.\n",
183152419Sariff			    NVME_CTRLR_PREFIX);
184152419Sariff		if (exit_on_error)
185152419Sariff			exit(EX_USAGE);
186152419Sariff		else
187152419Sariff			return (EX_USAGE);
188152419Sariff	}
189152419Sariff
190152419Sariff	snprintf(full_path, sizeof(full_path), "/dev/%s", str);
191152419Sariff	if (stat(full_path, &devstat) != 0) {
192152419Sariff		if (show_error)
193152419Sariff			fprintf(stderr, "Could not stat %s. errno=%d (%s)\n",
194152419Sariff			    full_path, errno, strerror(errno));
195152419Sariff		if (exit_on_error)
196152419Sariff			exit(EX_NOINPUT);
197152419Sariff		else
198152419Sariff			return (EX_NOINPUT);
199152419Sariff	}
200152419Sariff
201152419Sariff	*fd = open(full_path, O_RDWR);
202152419Sariff	if (*fd < 0) {
203152419Sariff		if (show_error)
204152419Sariff			fprintf(stderr, "Could not open %s. errno=%d (%s)\n",
205152419Sariff			    full_path, errno, strerror(errno));
206152419Sariff		if (exit_on_error)
207152419Sariff			exit(EX_NOPERM);
208152419Sariff		else
20955209Scg			return (EX_NOPERM);
21050724Scg	}
21150724Scg
21250724Scg	return (EX_OK);
21350724Scg}
21465644Scg
21565644Scgint
21665644Scgmain(int argc, char *argv[])
21765644Scg{
21859019Scg	struct nvme_function *f;
21954831Scg
220164614Sariff	if (argc < 2)
22184658Scg		usage();
22250724Scg
223150832Snetchild	f = funcs;
224150832Snetchild	while (f->name != NULL) {
225152419Sariff		if (strcmp(argv[1], f->name) == 0)
226152419Sariff			f->fn(argc-1, &argv[1]);
227148591Snetchild		f++;
228164614Sariff	}
229164614Sariff
23055209Scg	usage();
23150724Scg
232150832Snetchild	return (0);
233150832Snetchild}
234150832Snetchild