1635c517aSAlexander Motin /*- 2635c517aSAlexander Motin * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3635c517aSAlexander Motin * 4635c517aSAlexander Motin * Copyright (C) 2018 Alexander Motin <mav@FreeBSD.org> 5635c517aSAlexander Motin * All rights reserved. 6635c517aSAlexander Motin * 7635c517aSAlexander Motin * Redistribution and use in source and binary forms, with or without 8635c517aSAlexander Motin * modification, are permitted provided that the following conditions 9635c517aSAlexander Motin * are met: 10635c517aSAlexander Motin * 1. Redistributions of source code must retain the above copyright 11635c517aSAlexander Motin * notice, this list of conditions and the following disclaimer. 12635c517aSAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright 13635c517aSAlexander Motin * notice, this list of conditions and the following disclaimer in the 14635c517aSAlexander Motin * documentation and/or other materials provided with the distribution. 15635c517aSAlexander Motin * 16635c517aSAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17635c517aSAlexander Motin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18635c517aSAlexander Motin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19635c517aSAlexander Motin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20635c517aSAlexander Motin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21635c517aSAlexander Motin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22635c517aSAlexander Motin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23635c517aSAlexander Motin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24635c517aSAlexander Motin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25635c517aSAlexander Motin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26635c517aSAlexander Motin * SUCH DAMAGE. 27635c517aSAlexander Motin */ 28635c517aSAlexander Motin 29635c517aSAlexander Motin #include <sys/cdefs.h> 30635c517aSAlexander Motin __FBSDID("$FreeBSD$"); 31635c517aSAlexander Motin 32635c517aSAlexander Motin #include <sys/param.h> 33635c517aSAlexander Motin #include <sys/ioccom.h> 34635c517aSAlexander Motin 35635c517aSAlexander Motin #include <ctype.h> 36635c517aSAlexander Motin #include <err.h> 37635c517aSAlexander Motin #include <fcntl.h> 38635c517aSAlexander Motin #include <stddef.h> 39635c517aSAlexander Motin #include <stdio.h> 40635c517aSAlexander Motin #include <stdlib.h> 41635c517aSAlexander Motin #include <string.h> 42635c517aSAlexander Motin #include <unistd.h> 43635c517aSAlexander Motin 44635c517aSAlexander Motin #include "nvmecontrol.h" 45635c517aSAlexander Motin 46635c517aSAlexander Motin static void 47635c517aSAlexander Motin format_usage(void) 48635c517aSAlexander Motin { 49635c517aSAlexander Motin fprintf(stderr, "usage:\n"); 50635c517aSAlexander Motin fprintf(stderr, FORMAT_USAGE); 51635c517aSAlexander Motin exit(1); 52635c517aSAlexander Motin } 53635c517aSAlexander Motin 54635c517aSAlexander Motin void 55635c517aSAlexander Motin format(int argc, char *argv[]) 56635c517aSAlexander Motin { 57635c517aSAlexander Motin struct nvme_controller_data cd; 58635c517aSAlexander Motin struct nvme_namespace_data nsd; 59635c517aSAlexander Motin struct nvme_pt_command pt; 60635c517aSAlexander Motin char path[64]; 61635c517aSAlexander Motin char *target; 62635c517aSAlexander Motin uint32_t nsid; 63635c517aSAlexander Motin int ch, fd; 64635c517aSAlexander Motin int lbaf = -1, mset = -1, pi = -1, pil = -1, ses = 0; 65635c517aSAlexander Motin 66635c517aSAlexander Motin if (argc < 2) 67635c517aSAlexander Motin format_usage(); 68635c517aSAlexander Motin 69635c517aSAlexander Motin while ((ch = getopt(argc, argv, "f:m:p:l:EC")) != -1) { 70635c517aSAlexander Motin switch ((char)ch) { 71635c517aSAlexander Motin case 'f': 72635c517aSAlexander Motin lbaf = strtol(optarg, NULL, 0); 73635c517aSAlexander Motin break; 74635c517aSAlexander Motin case 'm': 75635c517aSAlexander Motin mset = strtol(optarg, NULL, 0); 76635c517aSAlexander Motin break; 77635c517aSAlexander Motin case 'p': 78635c517aSAlexander Motin pi = strtol(optarg, NULL, 0); 79635c517aSAlexander Motin break; 80635c517aSAlexander Motin case 'l': 81635c517aSAlexander Motin pil = strtol(optarg, NULL, 0); 82635c517aSAlexander Motin break; 83635c517aSAlexander Motin case 'E': 84011bbaa5SAlexander Motin if (ses == 2) 85011bbaa5SAlexander Motin errx(1, "-E and -C are mutually exclusive"); 86635c517aSAlexander Motin ses = 1; 87635c517aSAlexander Motin break; 88635c517aSAlexander Motin case 'C': 89011bbaa5SAlexander Motin if (ses == 1) 90011bbaa5SAlexander Motin errx(1, "-E and -C are mutually exclusive"); 91635c517aSAlexander Motin ses = 2; 92635c517aSAlexander Motin break; 93635c517aSAlexander Motin default: 94635c517aSAlexander Motin format_usage(); 95635c517aSAlexander Motin } 96635c517aSAlexander Motin } 97635c517aSAlexander Motin 98635c517aSAlexander Motin /* Check that a controller or namespace was specified. */ 99635c517aSAlexander Motin if (optind >= argc) 100635c517aSAlexander Motin format_usage(); 101635c517aSAlexander Motin target = argv[optind]; 102635c517aSAlexander Motin 103635c517aSAlexander Motin /* 104635c517aSAlexander Motin * Check if the specified device node exists before continuing. 105635c517aSAlexander Motin * This is a cleaner check for cases where the correct controller 106635c517aSAlexander Motin * is specified, but an invalid namespace on that controller. 107635c517aSAlexander Motin */ 108635c517aSAlexander Motin open_dev(target, &fd, 1, 1); 109635c517aSAlexander Motin 110635c517aSAlexander Motin /* 111635c517aSAlexander Motin * If device node contains "ns", we consider it a namespace, 112635c517aSAlexander Motin * otherwise, consider it a controller. 113635c517aSAlexander Motin */ 114635c517aSAlexander Motin if (strstr(target, NVME_NS_PREFIX) == NULL) { 115635c517aSAlexander Motin nsid = NVME_GLOBAL_NAMESPACE_TAG; 116635c517aSAlexander Motin } else { 117635c517aSAlexander Motin /* 118635c517aSAlexander Motin * We send FORMAT commands to the controller, not the namespace, 119635c517aSAlexander Motin * since it is an admin cmd. The namespace ID will be specified 120635c517aSAlexander Motin * in the command itself. So parse the namespace's device node 121635c517aSAlexander Motin * string to get the controller substring and namespace ID. 122635c517aSAlexander Motin */ 123635c517aSAlexander Motin close(fd); 124011bbaa5SAlexander Motin parse_ns_str(target, path, &nsid); 125635c517aSAlexander Motin open_dev(path, &fd, 1, 1); 126011bbaa5SAlexander Motin } 127635c517aSAlexander Motin 128635c517aSAlexander Motin /* Check that controller can execute this command. */ 129635c517aSAlexander Motin read_controller_data(fd, &cd); 130011bbaa5SAlexander Motin if (((cd.oacs >> NVME_CTRLR_DATA_OACS_FORMAT_SHIFT) & 131011bbaa5SAlexander Motin NVME_CTRLR_DATA_OACS_FORMAT_MASK) == 0) 132011bbaa5SAlexander Motin errx(1, "controller does not support format"); 133011bbaa5SAlexander Motin if (((cd.fna >> NVME_CTRLR_DATA_FNA_CRYPTO_ERASE_SHIFT) & 134011bbaa5SAlexander Motin NVME_CTRLR_DATA_FNA_CRYPTO_ERASE_MASK) == 0 && ses == 2) 135011bbaa5SAlexander Motin errx(1, "controller does not support cryptographic erase"); 136011bbaa5SAlexander Motin 137011bbaa5SAlexander Motin if (nsid != NVME_GLOBAL_NAMESPACE_TAG) { 138011bbaa5SAlexander Motin if (((cd.fna >> NVME_CTRLR_DATA_FNA_FORMAT_ALL_SHIFT) & 139011bbaa5SAlexander Motin NVME_CTRLR_DATA_FNA_FORMAT_ALL_MASK) && ses == 0) 140011bbaa5SAlexander Motin errx(1, "controller does not support per-NS format"); 141011bbaa5SAlexander Motin if (((cd.fna >> NVME_CTRLR_DATA_FNA_ERASE_ALL_SHIFT) & 142011bbaa5SAlexander Motin NVME_CTRLR_DATA_FNA_ERASE_ALL_MASK) && ses != 0) 143011bbaa5SAlexander Motin errx(1, "controller does not support per-NS erase"); 144635c517aSAlexander Motin 145635c517aSAlexander Motin /* Try to keep previous namespace parameters. */ 146635c517aSAlexander Motin read_namespace_data(fd, nsid, &nsd); 147635c517aSAlexander Motin if (lbaf < 0) 148635c517aSAlexander Motin lbaf = (nsd.flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) 149635c517aSAlexander Motin & NVME_NS_DATA_FLBAS_FORMAT_MASK; 150011bbaa5SAlexander Motin if (lbaf > nsd.nlbaf) 151011bbaa5SAlexander Motin errx(1, "LBA format is out of range"); 152635c517aSAlexander Motin if (mset < 0) 153635c517aSAlexander Motin mset = (nsd.flbas >> NVME_NS_DATA_FLBAS_EXTENDED_SHIFT) 154635c517aSAlexander Motin & NVME_NS_DATA_FLBAS_EXTENDED_MASK; 155635c517aSAlexander Motin if (pi < 0) 156635c517aSAlexander Motin pi = (nsd.dps >> NVME_NS_DATA_DPS_MD_START_SHIFT) 157635c517aSAlexander Motin & NVME_NS_DATA_DPS_MD_START_MASK; 158635c517aSAlexander Motin if (pil < 0) 159635c517aSAlexander Motin pil = (nsd.dps >> NVME_NS_DATA_DPS_PIT_SHIFT) 160635c517aSAlexander Motin & NVME_NS_DATA_DPS_PIT_MASK; 161011bbaa5SAlexander Motin } else { 162011bbaa5SAlexander Motin 163011bbaa5SAlexander Motin /* We have no previous parameters, so default to zeroes. */ 164011bbaa5SAlexander Motin if (lbaf < 0) 165011bbaa5SAlexander Motin lbaf = 0; 166011bbaa5SAlexander Motin if (mset < 0) 167011bbaa5SAlexander Motin mset = 0; 168011bbaa5SAlexander Motin if (pi < 0) 169011bbaa5SAlexander Motin pi = 0; 170011bbaa5SAlexander Motin if (pil < 0) 171011bbaa5SAlexander Motin pil = 0; 172635c517aSAlexander Motin } 173635c517aSAlexander Motin 174635c517aSAlexander Motin memset(&pt, 0, sizeof(pt)); 175635c517aSAlexander Motin pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_FORMAT_NVM); 176635c517aSAlexander Motin pt.cmd.nsid = htole32(nsid); 177635c517aSAlexander Motin pt.cmd.cdw10 = htole32((ses << 9) + (pil << 8) + (pi << 5) + 178635c517aSAlexander Motin (mset << 4) + lbaf); 179635c517aSAlexander Motin 180635c517aSAlexander Motin if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 181635c517aSAlexander Motin err(1, "format request failed"); 182635c517aSAlexander Motin 183635c517aSAlexander Motin if (nvme_completion_is_error(&pt.cpl)) 184635c517aSAlexander Motin errx(1, "format request returned error"); 185635c517aSAlexander Motin close(fd); 186635c517aSAlexander Motin exit(0); 187635c517aSAlexander Motin } 188