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
generate_eui64(uint32_t low)41 generate_eui64(uint32_t low)
42 {
43 return (OUI_FREEBSD_NVME_LOW << 16 | low);
44 }
45
46 static uint32_t
crc32(const void * buf,size_t len)47 crc32(const void *buf, size_t len)
48 {
49 return (calculate_crc32c(0xffffffff, buf, len) ^ 0xffffffff);
50 }
51
52 static void
init_ramdisk(const char * config,struct backing_device * dev)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
init_filedevice(const char * config,int fd,struct stat * sb,struct backing_device * dev)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
init_chardevice(const char * config,int fd,struct backing_device * dev)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
init_device(const char * config,struct backing_device * dev)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
register_devices(int ac,char ** av)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
device_count(void)139 device_count(void)
140 {
141 return (ndevices);
142 }
143
144 static struct backing_device *
lookup_device(uint32_t nsid)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
device_active_nslist(uint32_t nsid,struct nvme_ns_list * nslist)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
device_identification_descriptor(uint32_t nsid,void * buf)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
device_namespace_data(uint32_t nsid,struct nvme_namespace_data * nsdata)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
read_buffer(int fd,void * buf,size_t len,off_t offset)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
device_read(uint32_t nsid,uint64_t lba,u_int nlb,const struct nvmf_capsule * nc)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
write_buffer(int fd,const void * buf,size_t len,off_t offset)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
device_write(uint32_t nsid,uint64_t lba,u_int nlb,const struct nvmf_capsule * nc)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
device_flush(uint32_t nsid,const struct nvmf_capsule * nc)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