2 * nvme structure declarations and helper functions for the
8 int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u,
11 struct nvme_data *data = FILE_ENG_DATA(io_u->file);
15 memset(cmd, 0, sizeof(struct nvme_uring_cmd));
17 if (io_u->ddir == DDIR_READ)
18 cmd->opcode = nvme_cmd_read;
19 else if (io_u->ddir == DDIR_WRITE)
20 cmd->opcode = nvme_cmd_write;
24 slba = io_u->offset >> data->lba_shift;
25 nlb = (io_u->xfer_buflen >> data->lba_shift) - 1;
27 /* cdw10 and cdw11 represent starting lba */
28 cmd->cdw10 = slba & 0xffffffff;
29 cmd->cdw11 = slba >> 32;
30 /* cdw12 represent number of lba's for read/write */
31 cmd->cdw12 = nlb | (io_u->dtype << 20);
32 cmd->cdw13 = io_u->dspec << 16;
34 iov->iov_base = io_u->xfer_buf;
35 iov->iov_len = io_u->xfer_buflen;
36 cmd->addr = (__u64)(uintptr_t)iov;
39 cmd->addr = (__u64)(uintptr_t)io_u->xfer_buf;
40 cmd->data_len = io_u->xfer_buflen;
42 cmd->nsid = data->nsid;
46 static int nvme_trim(int fd, __u32 nsid, __u32 nr_range, __u32 data_len,
49 struct nvme_passthru_cmd cmd = {
50 .opcode = nvme_cmd_dsm,
52 .addr = (__u64)(uintptr_t)data,
54 .cdw10 = nr_range - 1,
55 .cdw11 = NVME_ATTRIBUTE_DEALLOCATE,
58 return ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
61 int fio_nvme_trim(const struct thread_data *td, struct fio_file *f,
62 unsigned long long offset, unsigned long long len)
64 struct nvme_data *data = FILE_ENG_DATA(f);
65 struct nvme_dsm_range dsm;
68 dsm.nlb = (len >> data->lba_shift);
69 dsm.slba = (offset >> data->lba_shift);
71 ret = nvme_trim(f->fd, data->nsid, 1, sizeof(struct nvme_dsm_range),
74 log_err("%s: nvme_trim failed for offset %llu and len %llu, err=%d\n",
75 f->file_name, offset, len, ret);
80 static int nvme_identify(int fd, __u32 nsid, enum nvme_identify_cns cns,
81 enum nvme_csi csi, void *data)
83 struct nvme_passthru_cmd cmd = {
84 .opcode = nvme_admin_identify,
86 .addr = (__u64)(uintptr_t)data,
87 .data_len = NVME_IDENTIFY_DATA_SIZE,
89 .cdw11 = csi << NVME_IDENTIFY_CSI_SHIFT,
90 .timeout_ms = NVME_DEFAULT_IOCTL_TIMEOUT,
93 return ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
96 int fio_nvme_get_info(struct fio_file *f, __u32 *nsid, __u32 *lba_sz,
104 if (f->filetype != FIO_TYPE_CHAR) {
105 log_err("ioengine io_uring_cmd only works with nvme ns "
106 "generic char devices (/dev/ngXnY)\n");
110 fd = open(f->file_name, O_RDONLY);
114 namespace_id = ioctl(fd, NVME_IOCTL_ID);
115 if (namespace_id < 0) {
117 log_err("failed to fetch namespace-id");
123 * Identify namespace to get namespace-id, namespace size in LBA's
126 err = nvme_identify(fd, namespace_id, NVME_IDENTIFY_CNS_NS,
129 log_err("failed to fetch identify namespace\n");
134 *nsid = namespace_id;
137 * 16 or 64 as maximum number of supported LBA formats.
138 * From flbas bit 0-3 indicates lsb and bit 5-6 indicates msb
139 * of the format index used to format the namespace.
142 format_idx = ns.flbas & 0xf;
144 format_idx = (ns.flbas & 0xf) + (((ns.flbas >> 5) & 0x3) << 4);
146 *lba_sz = 1 << ns.lbaf[format_idx].ds;
153 int fio_nvme_get_zoned_model(struct thread_data *td, struct fio_file *f,
154 enum zbd_zoned_model *model)
156 struct nvme_data *data = FILE_ENG_DATA(f);
157 struct nvme_id_ns ns;
158 struct nvme_passthru_cmd cmd;
161 if (f->filetype != FIO_TYPE_CHAR)
164 /* File is not yet opened */
165 fd = open(f->file_name, O_RDONLY | O_LARGEFILE);
169 /* Using nvme_id_ns for data as sizes are same */
170 ret = nvme_identify(fd, data->nsid, NVME_IDENTIFY_CNS_CSI_CTRL,
177 memset(&cmd, 0, sizeof(struct nvme_passthru_cmd));
179 /* Using nvme_id_ns for data as sizes are same */
180 ret = nvme_identify(fd, data->nsid, NVME_IDENTIFY_CNS_CSI_NS,
187 *model = ZBD_HOST_MANAGED;
193 static int nvme_report_zones(int fd, __u32 nsid, __u64 slba, __u32 zras_feat,
194 __u32 data_len, void *data)
196 struct nvme_passthru_cmd cmd = {
197 .opcode = nvme_zns_cmd_mgmt_recv,
199 .addr = (__u64)(uintptr_t)data,
200 .data_len = data_len,
201 .cdw10 = slba & 0xffffffff,
203 .cdw12 = (data_len >> 2) - 1,
204 .cdw13 = NVME_ZNS_ZRA_REPORT_ZONES | zras_feat,
205 .timeout_ms = NVME_DEFAULT_IOCTL_TIMEOUT,
208 return ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
211 int fio_nvme_report_zones(struct thread_data *td, struct fio_file *f,
212 uint64_t offset, struct zbd_zone *zbdz,
213 unsigned int nr_zones)
215 struct nvme_data *data = FILE_ENG_DATA(f);
216 struct nvme_zone_report *zr;
217 struct nvme_zns_id_ns zns_ns;
218 struct nvme_id_ns ns;
219 unsigned int i = 0, j, zones_fetched = 0;
220 unsigned int max_zones, zones_chunks = 1024;
225 /* File is not yet opened */
226 fd = open(f->file_name, O_RDONLY | O_LARGEFILE);
231 zr_len = sizeof(*zr) + (zones_chunks * sizeof(struct nvme_zns_desc));
232 zr = calloc(1, zr_len);
238 ret = nvme_identify(fd, data->nsid, NVME_IDENTIFY_CNS_NS,
241 log_err("%s: nvme_identify_ns failed, err=%d\n", f->file_name,
246 ret = nvme_identify(fd, data->nsid, NVME_IDENTIFY_CNS_CSI_NS,
247 NVME_CSI_ZNS, &zns_ns);
249 log_err("%s: nvme_zns_identify_ns failed, err=%d\n",
253 zlen = zns_ns.lbafe[ns.flbas & 0x0f].zsze << data->lba_shift;
255 max_zones = (f->real_file_size - offset) / zlen;
256 if (max_zones < nr_zones)
257 nr_zones = max_zones;
259 if (nr_zones < zones_chunks)
260 zones_chunks = nr_zones;
262 while (zones_fetched < nr_zones) {
263 if (zones_fetched + zones_chunks >= nr_zones) {
264 zones_chunks = nr_zones - zones_fetched;
265 zr_len = sizeof(*zr) + (zones_chunks * sizeof(struct nvme_zns_desc));
267 ret = nvme_report_zones(fd, data->nsid, offset >> data->lba_shift,
268 NVME_ZNS_ZRAS_FEAT_ERZ, zr_len, (void *)zr);
270 log_err("%s: nvme_zns_report_zones failed, err=%d\n",
275 /* Transform the zone-report */
276 for (j = 0; j < zr->nr_zones; j++, i++) {
277 struct nvme_zns_desc *desc = (struct nvme_zns_desc *)&(zr->entries[j]);
279 zbdz[i].start = desc->zslba << data->lba_shift;
281 zbdz[i].wp = desc->wp << data->lba_shift;
282 zbdz[i].capacity = desc->zcap << data->lba_shift;
284 /* Zone Type is stored in first 4 bits. */
285 switch (desc->zt & 0x0f) {
286 case NVME_ZONE_TYPE_SEQWRITE_REQ:
287 zbdz[i].type = ZBD_ZONE_TYPE_SWR;
290 log_err("%s: invalid type for zone at offset %llu.\n",
291 f->file_name, (unsigned long long) desc->zslba);
296 /* Zone State is stored in last 4 bits. */
297 switch (desc->zs >> 4) {
298 case NVME_ZNS_ZS_EMPTY:
299 zbdz[i].cond = ZBD_ZONE_COND_EMPTY;
301 case NVME_ZNS_ZS_IMPL_OPEN:
302 zbdz[i].cond = ZBD_ZONE_COND_IMP_OPEN;
304 case NVME_ZNS_ZS_EXPL_OPEN:
305 zbdz[i].cond = ZBD_ZONE_COND_EXP_OPEN;
307 case NVME_ZNS_ZS_CLOSED:
308 zbdz[i].cond = ZBD_ZONE_COND_CLOSED;
310 case NVME_ZNS_ZS_FULL:
311 zbdz[i].cond = ZBD_ZONE_COND_FULL;
313 case NVME_ZNS_ZS_READ_ONLY:
314 case NVME_ZNS_ZS_OFFLINE:
316 /* Treat all these conditions as offline (don't use!) */
317 zbdz[i].cond = ZBD_ZONE_COND_OFFLINE;
318 zbdz[i].wp = zbdz[i].start;
321 zones_fetched += zr->nr_zones;
322 offset += zr->nr_zones * zlen;
333 int fio_nvme_reset_wp(struct thread_data *td, struct fio_file *f,
334 uint64_t offset, uint64_t length)
336 struct nvme_data *data = FILE_ENG_DATA(f);
337 unsigned int nr_zones;
338 unsigned long long zslba;
341 /* If the file is not yet opened, open it for this function. */
344 fd = open(f->file_name, O_RDWR | O_LARGEFILE);
349 zslba = offset >> data->lba_shift;
350 nr_zones = (length + td->o.zone_size - 1) / td->o.zone_size;
352 for (i = 0; i < nr_zones; i++, zslba += (td->o.zone_size >> data->lba_shift)) {
353 struct nvme_passthru_cmd cmd = {
354 .opcode = nvme_zns_cmd_mgmt_send,
356 .cdw10 = zslba & 0xffffffff,
357 .cdw11 = zslba >> 32,
358 .cdw13 = NVME_ZNS_ZSA_RESET,
359 .addr = (__u64)(uintptr_t)NULL,
361 .timeout_ms = NVME_DEFAULT_IOCTL_TIMEOUT,
364 ret = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
372 int fio_nvme_get_max_open_zones(struct thread_data *td, struct fio_file *f,
373 unsigned int *max_open_zones)
375 struct nvme_data *data = FILE_ENG_DATA(f);
376 struct nvme_zns_id_ns zns_ns;
379 fd = open(f->file_name, O_RDONLY | O_LARGEFILE);
383 ret = nvme_identify(fd, data->nsid, NVME_IDENTIFY_CNS_CSI_NS,
384 NVME_CSI_ZNS, &zns_ns);
386 log_err("%s: nvme_zns_identify_ns failed, err=%d\n",
391 *max_open_zones = zns_ns.mor + 1;
397 static inline int nvme_fdp_reclaim_unit_handle_status(int fd, __u32 nsid,
398 __u32 data_len, void *data)
400 struct nvme_passthru_cmd cmd = {
401 .opcode = nvme_cmd_io_mgmt_recv,
403 .addr = (__u64)(uintptr_t)data,
404 .data_len = data_len,
406 .cdw11 = (data_len >> 2) - 1,
409 return ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
412 int fio_nvme_iomgmt_ruhs(struct thread_data *td, struct fio_file *f,
413 struct nvme_fdp_ruh_status *ruhs, __u32 bytes)
415 struct nvme_data *data = FILE_ENG_DATA(f);
418 fd = open(f->file_name, O_RDONLY | O_LARGEFILE);
422 ret = nvme_fdp_reclaim_unit_handle_status(fd, data->nsid, bytes, ruhs);
424 log_err("%s: nvme_fdp_reclaim_unit_handle_status failed, err=%d\n",