14cb79292SJim Harris /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 4eadf2a44SJim Harris * Copyright (C) 2012-2013 Intel Corporation 54cb79292SJim Harris * All rights reserved. 64cb79292SJim Harris * 74cb79292SJim Harris * Redistribution and use in source and binary forms, with or without 84cb79292SJim Harris * modification, are permitted provided that the following conditions 94cb79292SJim Harris * are met: 104cb79292SJim Harris * 1. Redistributions of source code must retain the above copyright 114cb79292SJim Harris * notice, this list of conditions and the following disclaimer. 124cb79292SJim Harris * 2. Redistributions in binary form must reproduce the above copyright 134cb79292SJim Harris * notice, this list of conditions and the following disclaimer in the 144cb79292SJim Harris * documentation and/or other materials provided with the distribution. 154cb79292SJim Harris * 164cb79292SJim Harris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 174cb79292SJim Harris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 184cb79292SJim Harris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 194cb79292SJim Harris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 204cb79292SJim Harris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 214cb79292SJim Harris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 224cb79292SJim Harris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 234cb79292SJim Harris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 244cb79292SJim Harris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 254cb79292SJim Harris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 264cb79292SJim Harris * SUCH DAMAGE. 274cb79292SJim Harris */ 284cb79292SJim Harris 294cb79292SJim Harris #include <sys/param.h> 304cb79292SJim Harris #include <sys/ioccom.h> 314cb79292SJim Harris #include <sys/stat.h> 324cb79292SJim Harris 334cb79292SJim Harris #include <ctype.h> 34228c4255SWarner Losh #include <dlfcn.h> 35821ef73cSJim Harris #include <err.h> 362528d6a3SJim Harris #include <errno.h> 374cb79292SJim Harris #include <fcntl.h> 3856d11d4aSStefan Eßer #include <libutil.h> 39dddb618eSJim Harris #include <paths.h> 404cb79292SJim Harris #include <stdbool.h> 414cb79292SJim Harris #include <stddef.h> 424cb79292SJim Harris #include <stdio.h> 434cb79292SJim Harris #include <stdlib.h> 444cb79292SJim Harris #include <string.h> 455dc463f9SAlexander Motin #include <sysexits.h> 464cb79292SJim Harris #include <unistd.h> 474cb79292SJim Harris 486660d5e4SJim Harris #include "nvmecontrol.h" 49b846efd7SJim Harris 50e83c9e35SJim Harris static void 51e83c9e35SJim Harris print_bytes(void *data, uint32_t length) 52e83c9e35SJim Harris { 53e83c9e35SJim Harris uint32_t i, j; 54e83c9e35SJim Harris uint8_t *p, *end; 55e83c9e35SJim Harris 56e83c9e35SJim Harris end = (uint8_t *)data + length; 57e83c9e35SJim Harris 58e83c9e35SJim Harris for (i = 0; i < length; i++) { 59e83c9e35SJim Harris p = (uint8_t *)data + (i*16); 60e83c9e35SJim Harris printf("%03x: ", i*16); 61e83c9e35SJim Harris for (j = 0; j < 16 && p < end; j++) 62e83c9e35SJim Harris printf("%02x ", *p++); 63e83c9e35SJim Harris if (p >= end) 64e83c9e35SJim Harris break; 65e83c9e35SJim Harris printf("\n"); 66e83c9e35SJim Harris } 67e83c9e35SJim Harris printf("\n"); 68e83c9e35SJim Harris } 69e83c9e35SJim Harris 70e83c9e35SJim Harris static void 71e83c9e35SJim Harris print_dwords(void *data, uint32_t length) 72e83c9e35SJim Harris { 73e83c9e35SJim Harris uint32_t *p; 74e83c9e35SJim Harris uint32_t i, j; 75e83c9e35SJim Harris 76e83c9e35SJim Harris p = (uint32_t *)data; 77e83c9e35SJim Harris length /= sizeof(uint32_t); 78e83c9e35SJim Harris 79e83c9e35SJim Harris for (i = 0; i < length; i+=8) { 80e83c9e35SJim Harris printf("%03x: ", i*4); 81e83c9e35SJim Harris for (j = 0; j < 8; j++) 82e83c9e35SJim Harris printf("%08x ", p[i+j]); 83e83c9e35SJim Harris printf("\n"); 84e83c9e35SJim Harris } 85e83c9e35SJim Harris 86e83c9e35SJim Harris printf("\n"); 87e83c9e35SJim Harris } 88e83c9e35SJim Harris 89e83c9e35SJim Harris void 90e83c9e35SJim Harris print_hex(void *data, uint32_t length) 91e83c9e35SJim Harris { 92e83c9e35SJim Harris if (length >= sizeof(uint32_t) || length % sizeof(uint32_t) == 0) 93e83c9e35SJim Harris print_dwords(data, length); 94e83c9e35SJim Harris else 95e83c9e35SJim Harris print_bytes(data, length); 96e83c9e35SJim Harris } 97e83c9e35SJim Harris 985dc463f9SAlexander Motin int 995076698eSJim Harris read_controller_data(int fd, struct nvme_controller_data *cdata) 1005076698eSJim Harris { 1015076698eSJim Harris struct nvme_pt_command pt; 1025076698eSJim Harris 1035076698eSJim Harris memset(&pt, 0, sizeof(pt)); 1049544e6dcSChuck Tuffli pt.cmd.opc = NVME_OPC_IDENTIFY; 1050d787e9bSWojciech Macek pt.cmd.cdw10 = htole32(1); 1065076698eSJim Harris pt.buf = cdata; 1075076698eSJim Harris pt.len = sizeof(*cdata); 1085076698eSJim Harris pt.is_read = 1; 1095076698eSJim Harris 110821ef73cSJim Harris if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 1115dc463f9SAlexander Motin return (errno); 1125076698eSJim Harris 1130d787e9bSWojciech Macek /* Convert data to host endian */ 1140d787e9bSWojciech Macek nvme_controller_data_swapbytes(cdata); 1150d787e9bSWojciech Macek 116821ef73cSJim Harris if (nvme_completion_is_error(&pt.cpl)) 1175dc463f9SAlexander Motin return (EIO); 1185dc463f9SAlexander Motin return (0); 1195076698eSJim Harris } 1205076698eSJim Harris 1215dc463f9SAlexander Motin int 122635c517aSAlexander Motin read_namespace_data(int fd, uint32_t nsid, struct nvme_namespace_data *nsdata) 1235076698eSJim Harris { 1245076698eSJim Harris struct nvme_pt_command pt; 1255076698eSJim Harris 1265076698eSJim Harris memset(&pt, 0, sizeof(pt)); 1279544e6dcSChuck Tuffli pt.cmd.opc = NVME_OPC_IDENTIFY; 1280d787e9bSWojciech Macek pt.cmd.nsid = htole32(nsid); 1293b3dd3f7SAlexander Motin pt.cmd.cdw10 = htole32(0); 1305076698eSJim Harris pt.buf = nsdata; 1315076698eSJim Harris pt.len = sizeof(*nsdata); 1325076698eSJim Harris pt.is_read = 1; 1335076698eSJim Harris 134821ef73cSJim Harris if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 1355dc463f9SAlexander Motin return (errno); 1365076698eSJim Harris 1370d787e9bSWojciech Macek /* Convert data to host endian */ 1380d787e9bSWojciech Macek nvme_namespace_data_swapbytes(nsdata); 1390d787e9bSWojciech Macek 140821ef73cSJim Harris if (nvme_completion_is_error(&pt.cpl)) 1415dc463f9SAlexander Motin return (EIO); 1425dc463f9SAlexander Motin return (0); 1435076698eSJim Harris } 1444cb79292SJim Harris 1456660d5e4SJim Harris int 146*9e1db51dSJohn Baldwin read_active_namespaces(int fd, uint32_t nsid, struct nvme_ns_list *nslist) 147*9e1db51dSJohn Baldwin { 148*9e1db51dSJohn Baldwin struct nvme_pt_command pt; 149*9e1db51dSJohn Baldwin 150*9e1db51dSJohn Baldwin memset(&pt, 0, sizeof(pt)); 151*9e1db51dSJohn Baldwin pt.cmd.opc = NVME_OPC_IDENTIFY; 152*9e1db51dSJohn Baldwin pt.cmd.nsid = htole32(nsid); 153*9e1db51dSJohn Baldwin pt.cmd.cdw10 = htole32(2); 154*9e1db51dSJohn Baldwin pt.buf = nslist; 155*9e1db51dSJohn Baldwin pt.len = sizeof(*nslist); 156*9e1db51dSJohn Baldwin pt.is_read = 1; 157*9e1db51dSJohn Baldwin 158*9e1db51dSJohn Baldwin if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 159*9e1db51dSJohn Baldwin return (errno); 160*9e1db51dSJohn Baldwin 161*9e1db51dSJohn Baldwin /* Convert data to host endian */ 162*9e1db51dSJohn Baldwin nvme_ns_list_swapbytes(nslist); 163*9e1db51dSJohn Baldwin 164*9e1db51dSJohn Baldwin if (nvme_completion_is_error(&pt.cpl)) 165*9e1db51dSJohn Baldwin return (EIO); 166*9e1db51dSJohn Baldwin return (0); 167*9e1db51dSJohn Baldwin } 168*9e1db51dSJohn Baldwin 169*9e1db51dSJohn Baldwin int 1701f15d49eSAlexander Motin open_dev(const char *str, int *fd, int write, int exit_on_error) 171eadf2a44SJim Harris { 172b12cae88SWarner Losh char full_path[MAXPATHLEN]; 173eadf2a44SJim Harris 174b12cae88SWarner Losh if (str[0] == '/') /* Full path */ 175b12cae88SWarner Losh strlcpy(full_path, str, sizeof(full_path)); 176b12cae88SWarner Losh else /* Add /dev/ */ 177dddb618eSJim Harris snprintf(full_path, sizeof(full_path), _PATH_DEV"%s", str); 1781f15d49eSAlexander Motin *fd = open(full_path, write ? O_RDWR : O_RDONLY); 179eadf2a44SJim Harris if (*fd < 0) { 1801f15d49eSAlexander Motin if (exit_on_error) { 1815dc463f9SAlexander Motin err(EX_OSFILE, "could not open %s%s", full_path, 1821f15d49eSAlexander Motin write ? " for write" : ""); 1831f15d49eSAlexander Motin } else 184b378da27SJim Harris return (errno); 185eadf2a44SJim Harris } 186eadf2a44SJim Harris 187821ef73cSJim Harris return (0); 188eadf2a44SJim Harris } 189eadf2a44SJim Harris 1902528d6a3SJim Harris void 191a7bf63beSAlexander Motin get_nsid(int fd, char **ctrlr_str, uint32_t *nsid) 1922528d6a3SJim Harris { 193a7bf63beSAlexander Motin struct nvme_get_nsid gnsid; 1942528d6a3SJim Harris 195a7bf63beSAlexander Motin if (ioctl(fd, NVME_GET_NSID, &gnsid) < 0) 1965dc463f9SAlexander Motin err(EX_OSERR, "NVME_GET_NSID ioctl failed"); 197a7bf63beSAlexander Motin if (ctrlr_str != NULL) 198a7bf63beSAlexander Motin *ctrlr_str = strndup(gnsid.cdev, sizeof(gnsid.cdev)); 199a7bf63beSAlexander Motin if (nsid != NULL) 200a7bf63beSAlexander Motin *nsid = gnsid.nsid; 2012528d6a3SJim Harris } 2022528d6a3SJim Harris 2034cb79292SJim Harris int 2044cb79292SJim Harris main(int argc, char *argv[]) 2054cb79292SJim Harris { 20656d11d4aSStefan Eßer static char dir[MAXPATHLEN]; 2074cb79292SJim Harris 208f634b4c1SWarner Losh cmd_init(); 2094cb79292SJim Harris 2108e103108SScott Long cmd_load_dir("/lib/nvmecontrol", NULL, NULL); 21156d11d4aSStefan Eßer snprintf(dir, MAXPATHLEN, "%s/lib/nvmecontrol", getlocalbase()); 21256d11d4aSStefan Eßer cmd_load_dir(dir, NULL, NULL); 213228c4255SWarner Losh 214f634b4c1SWarner Losh cmd_dispatch(argc, argv, NULL); 2154cb79292SJim Harris 2164cb79292SJim Harris return (0); 2174cb79292SJim Harris } 218