1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2023-2024 Chelsio Communications, Inc. 5 * Written by: John Baldwin <jhb@FreeBSD.org> 6 */ 7 8 #include <sys/disk.h> 9 #include <sys/gsb_crc32.h> 10 #include <sys/ioctl.h> 11 #include <sys/stat.h> 12 #include <net/ieee_oui.h> 13 #include <err.h> 14 #include <errno.h> 15 #include <fcntl.h> 16 #include <libnvmf.h> 17 #include <libutil.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <unistd.h> 21 22 #include "internal.h" 23 24 #define RAMDISK_PREFIX "ramdisk:" 25 26 struct backing_device { 27 enum { RAMDISK, FILE, CDEV } type; 28 union { 29 int fd; /* FILE, CDEV */ 30 void *mem; /* RAMDISK */ 31 }; 32 u_int sector_size; 33 uint64_t nlbas; 34 uint64_t eui64; 35 }; 36 37 static struct backing_device *devices; 38 static u_int ndevices; 39 40 static uint64_t 41 generate_eui64(uint32_t low) 42 { 43 return (OUI_FREEBSD_NVME_LOW << 16 | low); 44 } 45 46 static uint32_t 47 crc32(const void *buf, size_t len) 48 { 49 return (calculate_crc32c(0xffffffff, buf, len) ^ 0xffffffff); 50 } 51 52 static void 53 init_ramdisk(const char *config, struct backing_device *dev) 54 { 55 static uint32_t ramdisk_idx = 1; 56 uint64_t num; 57 58 dev->type = RAMDISK; 59 dev->sector_size = 512; 60 if (expand_number(config, &num)) 61 errx(1, "Invalid ramdisk specification: %s", config); 62 if ((num % dev->sector_size) != 0) 63 errx(1, "Invalid ramdisk size %ju", (uintmax_t)num); 64 dev->mem = calloc(num, 1); 65 dev->nlbas = num / dev->sector_size; 66 dev->eui64 = generate_eui64('M' << 24 | ramdisk_idx++); 67 } 68 69 static void 70 init_filedevice(const char *config, int fd, struct stat *sb, 71 struct backing_device *dev) 72 { 73 dev->type = FILE; 74 dev->fd = fd; 75 dev->sector_size = 512; 76 if ((sb->st_size % dev->sector_size) != 0) 77 errx(1, "File size is not a multiple of 512: %s", config); 78 dev->nlbas = sb->st_size / dev->sector_size; 79 dev->eui64 = generate_eui64('F' << 24 | 80 (crc32(config, strlen(config)) & 0xffffff)); 81 } 82 83 static void 84 init_chardevice(const char *config, int fd, struct backing_device *dev) 85 { 86 off_t len; 87 88 dev->type = CDEV; 89 dev->fd = fd; 90 if (ioctl(fd, DIOCGSECTORSIZE, &dev->sector_size) != 0) 91 err(1, "Failed to fetch sector size for %s", config); 92 if (ioctl(fd, DIOCGMEDIASIZE, &len) != 0) 93 err(1, "Failed to fetch sector size for %s", config); 94 dev->nlbas = len / dev->sector_size; 95 dev->eui64 = generate_eui64('C' << 24 | 96 (crc32(config, strlen(config)) & 0xffffff)); 97 } 98 99 static void 100 init_device(const char *config, struct backing_device *dev) 101 { 102 struct stat sb; 103 int fd; 104 105 /* Check for a RAM disk. */ 106 if (strncmp(RAMDISK_PREFIX, config, strlen(RAMDISK_PREFIX)) == 0) { 107 init_ramdisk(config + strlen(RAMDISK_PREFIX), dev); 108 return; 109 } 110 111 fd = open(config, O_RDWR); 112 if (fd == -1) 113 err(1, "Failed to open %s", config); 114 if (fstat(fd, &sb) == -1) 115 err(1, "fstat"); 116 switch (sb.st_mode & S_IFMT) { 117 case S_IFCHR: 118 init_chardevice(config, fd, dev); 119 break; 120 case S_IFREG: 121 init_filedevice(config, fd, &sb, dev); 122 break; 123 default: 124 errx(1, "Invalid file type for %s", config); 125 } 126 } 127 128 void 129 register_devices(int ac, char **av) 130 { 131 ndevices = ac; 132 devices = calloc(ndevices, sizeof(*devices)); 133 134 for (int i = 0; i < ac; i++) 135 init_device(av[i], &devices[i]); 136 } 137 138 u_int 139 device_count(void) 140 { 141 return (ndevices); 142 } 143 144 static struct backing_device * 145 lookup_device(uint32_t nsid) 146 { 147 if (nsid == 0 || nsid > ndevices) 148 return (NULL); 149 return (&devices[nsid - 1]); 150 } 151 152 void 153 device_active_nslist(uint32_t nsid, struct nvme_ns_list *nslist) 154 { 155 u_int count; 156 157 memset(nslist, 0, sizeof(*nslist)); 158 count = 0; 159 nsid++; 160 while (nsid <= ndevices) { 161 nslist->ns[count] = htole32(nsid); 162 count++; 163 if (count == nitems(nslist->ns)) 164 break; 165 nsid++; 166 } 167 } 168 169 bool 170 device_identification_descriptor(uint32_t nsid, void *buf) 171 { 172 struct backing_device *dev; 173 char *p; 174 175 dev = lookup_device(nsid); 176 if (dev == NULL) 177 return (false); 178 179 memset(buf, 0, 4096); 180 181 p = buf; 182 183 /* EUI64 */ 184 *p++ = 1; 185 *p++ = 8; 186 p += 2; 187 be64enc(p, dev->eui64); 188 return (true); 189 } 190 191 bool 192 device_namespace_data(uint32_t nsid, struct nvme_namespace_data *nsdata) 193 { 194 struct backing_device *dev; 195 196 dev = lookup_device(nsid); 197 if (dev == NULL) 198 return (false); 199 200 memset(nsdata, 0, sizeof(*nsdata)); 201 nsdata->nsze = htole64(dev->nlbas); 202 nsdata->ncap = nsdata->nsze; 203 nsdata->nuse = nsdata->ncap; 204 nsdata->nlbaf = 1 - 1; 205 nsdata->flbas = NVMEF(NVME_NS_DATA_FLBAS_FORMAT, 0); 206 nsdata->lbaf[0] = NVMEF(NVME_NS_DATA_LBAF_LBADS, 207 ffs(dev->sector_size) - 1); 208 209 be64enc(nsdata->eui64, dev->eui64); 210 return (true); 211 } 212 213 static bool 214 read_buffer(int fd, void *buf, size_t len, off_t offset) 215 { 216 ssize_t nread; 217 char *dst; 218 219 dst = buf; 220 while (len > 0) { 221 nread = pread(fd, dst, len, offset); 222 if (nread == -1 && errno == EINTR) 223 continue; 224 if (nread <= 0) 225 return (false); 226 dst += nread; 227 len -= nread; 228 offset += nread; 229 } 230 return (true); 231 } 232 233 void 234 device_read(uint32_t nsid, uint64_t lba, u_int nlb, 235 const struct nvmf_capsule *nc) 236 { 237 struct backing_device *dev; 238 char *p, *src; 239 off_t off; 240 size_t len; 241 242 dev = lookup_device(nsid); 243 if (dev == NULL) { 244 nvmf_send_generic_error(nc, 245 NVME_SC_INVALID_NAMESPACE_OR_FORMAT); 246 return; 247 } 248 249 if (lba + nlb < lba || lba + nlb > dev->nlbas) { 250 nvmf_send_generic_error(nc, NVME_SC_LBA_OUT_OF_RANGE); 251 return; 252 } 253 254 off = lba * dev->sector_size; 255 len = nlb * dev->sector_size; 256 if (nvmf_capsule_data_len(nc) != len) { 257 nvmf_send_generic_error(nc, NVME_SC_INVALID_FIELD); 258 return; 259 } 260 261 if (dev->type == RAMDISK) { 262 p = NULL; 263 src = (char *)dev->mem + off; 264 } else { 265 p = malloc(len); 266 if (!read_buffer(dev->fd, p, len, off)) { 267 free(p); 268 nvmf_send_generic_error(nc, 269 NVME_SC_INTERNAL_DEVICE_ERROR); 270 return; 271 } 272 src = p; 273 } 274 275 nvmf_send_controller_data(nc, src, len); 276 free(p); 277 } 278 279 static bool 280 write_buffer(int fd, const void *buf, size_t len, off_t offset) 281 { 282 ssize_t nwritten; 283 const char *src; 284 285 src = buf; 286 while (len > 0) { 287 nwritten = pwrite(fd, src, len, offset); 288 if (nwritten == -1 && errno == EINTR) 289 continue; 290 if (nwritten <= 0) 291 return (false); 292 src += nwritten; 293 len -= nwritten; 294 offset += nwritten; 295 } 296 return (true); 297 } 298 299 void 300 device_write(uint32_t nsid, uint64_t lba, u_int nlb, 301 const struct nvmf_capsule *nc) 302 { 303 struct backing_device *dev; 304 char *p, *dst; 305 off_t off; 306 size_t len; 307 int error; 308 309 dev = lookup_device(nsid); 310 if (dev == NULL) { 311 nvmf_send_generic_error(nc, 312 NVME_SC_INVALID_NAMESPACE_OR_FORMAT); 313 return; 314 } 315 316 if (lba + nlb < lba || lba + nlb > dev->nlbas) { 317 nvmf_send_generic_error(nc, NVME_SC_LBA_OUT_OF_RANGE); 318 return; 319 } 320 321 off = lba * dev->sector_size; 322 len = nlb * dev->sector_size; 323 if (nvmf_capsule_data_len(nc) != len) { 324 nvmf_send_generic_error(nc, NVME_SC_INVALID_FIELD); 325 return; 326 } 327 328 if (dev->type == RAMDISK) { 329 p = NULL; 330 dst = (char *)dev->mem + off; 331 } else { 332 p = malloc(len); 333 dst = p; 334 } 335 336 error = nvmf_receive_controller_data(nc, 0, dst, len); 337 if (error != 0) { 338 nvmf_send_generic_error(nc, NVME_SC_TRANSIENT_TRANSPORT_ERROR); 339 free(p); 340 return; 341 } 342 343 if (dev->type != RAMDISK) { 344 if (!write_buffer(dev->fd, p, len, off)) { 345 free(p); 346 nvmf_send_generic_error(nc, 347 NVME_SC_INTERNAL_DEVICE_ERROR); 348 return; 349 } 350 } 351 free(p); 352 nvmf_send_success(nc); 353 } 354 355 void 356 device_flush(uint32_t nsid, const struct nvmf_capsule *nc) 357 { 358 struct backing_device *dev; 359 360 dev = lookup_device(nsid); 361 if (dev == NULL) { 362 nvmf_send_generic_error(nc, 363 NVME_SC_INVALID_NAMESPACE_OR_FORMAT); 364 return; 365 } 366 367 switch (dev->type) { 368 case RAMDISK: 369 break; 370 case FILE: 371 if (fdatasync(dev->fd) == -1) { 372 nvmf_send_error(nc, NVME_SCT_MEDIA_ERROR, 373 NVME_SC_WRITE_FAULTS); 374 return; 375 } 376 break; 377 case CDEV: 378 if (ioctl(dev->fd, DIOCGFLUSH) == -1) { 379 nvmf_send_error(nc, NVME_SCT_MEDIA_ERROR, 380 NVME_SC_WRITE_FAULTS); 381 return; 382 } 383 } 384 385 nvmf_send_success(nc); 386 } 387