1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (C) 2018 Alexander Motin <mav@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/ioccom.h> 34 35 #include <ctype.h> 36 #include <err.h> 37 #include <fcntl.h> 38 #include <stddef.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include "nvmecontrol.h" 45 46 #define FORMAT_USAGE \ 47 "format [-f fmt] [-m mset] [-p pi] [-l pil] [-E] [-C] <controller id|namespace id>\n" 48 49 static void 50 format(const struct nvme_function *nf, int argc, char *argv[]) 51 { 52 struct nvme_controller_data cd; 53 struct nvme_namespace_data nsd; 54 struct nvme_pt_command pt; 55 char path[64]; 56 char *target; 57 uint32_t nsid; 58 int ch, fd; 59 int lbaf = -1, mset = -1, pi = -1, pil = -1, ses = 0; 60 61 if (argc < 2) 62 usage(nf); 63 64 while ((ch = getopt(argc, argv, "f:m:p:l:EC")) != -1) { 65 switch ((char)ch) { 66 case 'f': 67 lbaf = strtol(optarg, NULL, 0); 68 break; 69 case 'm': 70 mset = strtol(optarg, NULL, 0); 71 break; 72 case 'p': 73 pi = strtol(optarg, NULL, 0); 74 break; 75 case 'l': 76 pil = strtol(optarg, NULL, 0); 77 break; 78 case 'E': 79 if (ses == 2) 80 errx(1, "-E and -C are mutually exclusive"); 81 ses = 1; 82 break; 83 case 'C': 84 if (ses == 1) 85 errx(1, "-E and -C are mutually exclusive"); 86 ses = 2; 87 break; 88 default: 89 usage(nf); 90 } 91 } 92 93 /* Check that a controller or namespace was specified. */ 94 if (optind >= argc) 95 usage(nf); 96 target = argv[optind]; 97 98 /* 99 * Check if the specified device node exists before continuing. 100 * This is a cleaner check for cases where the correct controller 101 * is specified, but an invalid namespace on that controller. 102 */ 103 open_dev(target, &fd, 1, 1); 104 105 /* 106 * If device node contains "ns", we consider it a namespace, 107 * otherwise, consider it a controller. 108 */ 109 if (strstr(target, NVME_NS_PREFIX) == NULL) { 110 nsid = NVME_GLOBAL_NAMESPACE_TAG; 111 } else { 112 /* 113 * We send FORMAT commands to the controller, not the namespace, 114 * since it is an admin cmd. The namespace ID will be specified 115 * in the command itself. So parse the namespace's device node 116 * string to get the controller substring and namespace ID. 117 */ 118 close(fd); 119 parse_ns_str(target, path, &nsid); 120 open_dev(path, &fd, 1, 1); 121 } 122 123 /* Check that controller can execute this command. */ 124 read_controller_data(fd, &cd); 125 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_FORMAT_SHIFT) & 126 NVME_CTRLR_DATA_OACS_FORMAT_MASK) == 0) 127 errx(1, "controller does not support format"); 128 if (((cd.fna >> NVME_CTRLR_DATA_FNA_CRYPTO_ERASE_SHIFT) & 129 NVME_CTRLR_DATA_FNA_CRYPTO_ERASE_MASK) == 0 && ses == 2) 130 errx(1, "controller does not support cryptographic erase"); 131 132 if (nsid != NVME_GLOBAL_NAMESPACE_TAG) { 133 if (((cd.fna >> NVME_CTRLR_DATA_FNA_FORMAT_ALL_SHIFT) & 134 NVME_CTRLR_DATA_FNA_FORMAT_ALL_MASK) && ses == 0) 135 errx(1, "controller does not support per-NS format"); 136 if (((cd.fna >> NVME_CTRLR_DATA_FNA_ERASE_ALL_SHIFT) & 137 NVME_CTRLR_DATA_FNA_ERASE_ALL_MASK) && ses != 0) 138 errx(1, "controller does not support per-NS erase"); 139 140 /* Try to keep previous namespace parameters. */ 141 read_namespace_data(fd, nsid, &nsd); 142 if (lbaf < 0) 143 lbaf = (nsd.flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) 144 & NVME_NS_DATA_FLBAS_FORMAT_MASK; 145 if (lbaf > nsd.nlbaf) 146 errx(1, "LBA format is out of range"); 147 if (mset < 0) 148 mset = (nsd.flbas >> NVME_NS_DATA_FLBAS_EXTENDED_SHIFT) 149 & NVME_NS_DATA_FLBAS_EXTENDED_MASK; 150 if (pi < 0) 151 pi = (nsd.dps >> NVME_NS_DATA_DPS_MD_START_SHIFT) 152 & NVME_NS_DATA_DPS_MD_START_MASK; 153 if (pil < 0) 154 pil = (nsd.dps >> NVME_NS_DATA_DPS_PIT_SHIFT) 155 & NVME_NS_DATA_DPS_PIT_MASK; 156 } else { 157 158 /* We have no previous parameters, so default to zeroes. */ 159 if (lbaf < 0) 160 lbaf = 0; 161 if (mset < 0) 162 mset = 0; 163 if (pi < 0) 164 pi = 0; 165 if (pil < 0) 166 pil = 0; 167 } 168 169 memset(&pt, 0, sizeof(pt)); 170 pt.cmd.opc = NVME_OPC_FORMAT_NVM; 171 pt.cmd.nsid = htole32(nsid); 172 pt.cmd.cdw10 = htole32((ses << 9) + (pil << 8) + (pi << 5) + 173 (mset << 4) + lbaf); 174 175 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 176 err(1, "format request failed"); 177 178 if (nvme_completion_is_error(&pt.cpl)) 179 errx(1, "format request returned error"); 180 close(fd); 181 exit(0); 182 } 183 184 NVME_COMMAND(top, format, format, FORMAT_USAGE); 185