t/nvmept_trim: increase transfer size for some tests
[fio.git] / engines / libzbc.c
CommitLineData
56a19325
DF
1/*
2 * Copyright (C) 2019 Western Digital Corporation or its affiliates.
3 *
4 * This file is released under the GPL.
5 *
6 * libzbc engine
7 * IO engine using libzbc library to talk to SMR disks.
8 */
9#include <stdlib.h>
10#include <unistd.h>
11#include <errno.h>
12#include <libzbc/zbc.h>
13
14#include "fio.h"
15#include "err.h"
16#include "zbd_types.h"
84f07387 17#include "zbd.h"
56a19325
DF
18
19struct libzbc_data {
20 struct zbc_device *zdev;
21 enum zbc_dev_model model;
22 uint64_t nr_sectors;
e8267436 23 uint32_t max_open_seq_req;
56a19325
DF
24};
25
26static int libzbc_get_dev_info(struct libzbc_data *ld, struct fio_file *f)
27{
28 struct zbc_device_info *zinfo;
29
30 zinfo = calloc(1, sizeof(*zinfo));
31 if (!zinfo)
32 return -ENOMEM;
33
34 zbc_get_device_info(ld->zdev, zinfo);
35 ld->model = zinfo->zbd_model;
36 ld->nr_sectors = zinfo->zbd_sectors;
e8267436 37 ld->max_open_seq_req = zinfo->zbd_max_nr_open_seq_req;
56a19325
DF
38
39 dprint(FD_ZBD, "%s: vendor_id:%s, type: %s, model: %s\n",
40 f->file_name, zinfo->zbd_vendor_id,
41 zbc_device_type_str(zinfo->zbd_type),
42 zbc_device_model_str(zinfo->zbd_model));
43
44 free(zinfo);
45
46 return 0;
47}
48
49static int libzbc_open_dev(struct thread_data *td, struct fio_file *f,
50 struct libzbc_data **p_ld)
51{
52 struct libzbc_data *ld = td->io_ops_data;
976fb54e 53 int ret, flags = OS_O_DIRECT;
56a19325
DF
54
55 if (ld) {
56 /* Already open */
57 assert(ld->zdev);
58 goto out;
59 }
60
61 if (f->filetype != FIO_TYPE_BLOCK && f->filetype != FIO_TYPE_CHAR) {
62 td_verror(td, EINVAL, "wrong file type");
63 log_err("ioengine libzbc only works on block or character devices\n");
64 return -EINVAL;
65 }
66
84f07387 67 if (td_write(td) || td_trim(td)) {
56a19325
DF
68 if (!read_only)
69 flags |= O_RDWR;
70 } else if (td_read(td)) {
56a19325 71 flags |= O_RDONLY;
56a19325
DF
72 }
73
56a19325
DF
74 ld = calloc(1, sizeof(*ld));
75 if (!ld)
76 return -ENOMEM;
77
78 ret = zbc_open(f->file_name,
79eb6c9a 79 flags | ZBC_O_DRV_SCSI | ZBC_O_DRV_ATA,
ed2eb875 80 &ld->zdev);
56a19325
DF
81 if (ret) {
82 log_err("%s: zbc_open() failed, err=%d\n",
83 f->file_name, ret);
891660e4 84 goto err;
56a19325
DF
85 }
86
87 ret = libzbc_get_dev_info(ld, f);
891660e4
DF
88 if (ret)
89 goto err_close;
56a19325
DF
90
91 td->io_ops_data = ld;
92out:
93 if (p_ld)
94 *p_ld = ld;
95
96 return 0;
891660e4
DF
97
98err_close:
99 zbc_close(ld->zdev);
100err:
101 free(ld);
102 return ret;
56a19325
DF
103}
104
105static int libzbc_close_dev(struct thread_data *td)
106{
107 struct libzbc_data *ld = td->io_ops_data;
108 int ret = 0;
109
110 td->io_ops_data = NULL;
111 if (ld) {
112 if (ld->zdev)
113 ret = zbc_close(ld->zdev);
114 free(ld);
115 }
116
117 return ret;
118}
119static int libzbc_open_file(struct thread_data *td, struct fio_file *f)
120{
121 return libzbc_open_dev(td, f, NULL);
122}
123
124static int libzbc_close_file(struct thread_data *td, struct fio_file *f)
125{
126 int ret;
127
128 ret = libzbc_close_dev(td);
129 if (ret)
130 log_err("%s: close device failed err %d\n",
131 f->file_name, ret);
132
133 return ret;
134}
135
136static void libzbc_cleanup(struct thread_data *td)
137{
138 libzbc_close_dev(td);
139}
140
141static int libzbc_invalidate(struct thread_data *td, struct fio_file *f)
142{
143 /* Passthrough IO do not cache data. Nothing to do */
144 return 0;
145}
146
147static int libzbc_get_file_size(struct thread_data *td, struct fio_file *f)
148{
149 struct libzbc_data *ld;
150 int ret;
151
152 if (fio_file_size_known(f))
153 return 0;
154
155 ret = libzbc_open_dev(td, f, &ld);
156 if (ret)
157 return ret;
158
159 f->real_file_size = ld->nr_sectors << 9;
160 fio_file_set_size_known(f);
161
162 return 0;
163}
164
165static int libzbc_get_zoned_model(struct thread_data *td, struct fio_file *f,
166 enum zbd_zoned_model *model)
167{
168 struct libzbc_data *ld;
169 int ret;
170
2c7dd23e
NC
171 if (f->filetype != FIO_TYPE_BLOCK && f->filetype != FIO_TYPE_CHAR)
172 return -EINVAL;
56a19325
DF
173
174 ret = libzbc_open_dev(td, f, &ld);
175 if (ret)
176 return ret;
177
178 switch (ld->model) {
179 case ZBC_DM_HOST_AWARE:
180 *model = ZBD_HOST_AWARE;
181 break;
182 case ZBC_DM_HOST_MANAGED:
183 *model = ZBD_HOST_MANAGED;
184 break;
185 default:
186 *model = ZBD_NONE;
187 break;
188 }
189
190 return 0;
191}
192
193static int libzbc_report_zones(struct thread_data *td, struct fio_file *f,
194 uint64_t offset, struct zbd_zone *zbdz,
195 unsigned int nr_zones)
196{
197 struct libzbc_data *ld;
198 uint64_t sector = offset >> 9;
199 struct zbc_zone *zones;
200 unsigned int i;
201 int ret;
202
203 ret = libzbc_open_dev(td, f, &ld);
204 if (ret)
205 return ret;
206
207 if (sector >= ld->nr_sectors)
208 return 0;
209
210 zones = calloc(nr_zones, sizeof(struct zbc_zone));
211 if (!zones) {
212 ret = -ENOMEM;
213 goto out;
214 }
215
216 ret = zbc_report_zones(ld->zdev, sector, ZBC_RO_ALL, zones, &nr_zones);
217 if (ret < 0) {
218 log_err("%s: zbc_report_zones failed, err=%d\n",
219 f->file_name, ret);
220 goto out;
221 }
222
223 for (i = 0; i < nr_zones; i++, zbdz++) {
224 zbdz->start = zones[i].zbz_start << 9;
225 zbdz->len = zones[i].zbz_length << 9;
226 zbdz->wp = zones[i].zbz_write_pointer << 9;
236d23a8
SK
227 /*
228 * ZBC/ZAC do not define zone capacity, so use the zone size as
229 * the zone capacity.
230 */
231 zbdz->capacity = zbdz->len;
56a19325
DF
232
233 switch (zones[i].zbz_type) {
234 case ZBC_ZT_CONVENTIONAL:
235 zbdz->type = ZBD_ZONE_TYPE_CNV;
236 break;
237 case ZBC_ZT_SEQUENTIAL_REQ:
238 zbdz->type = ZBD_ZONE_TYPE_SWR;
239 break;
240 case ZBC_ZT_SEQUENTIAL_PREF:
241 zbdz->type = ZBD_ZONE_TYPE_SWP;
242 break;
243 default:
244 td_verror(td, errno, "invalid zone type");
245 log_err("%s: invalid type for zone at sector %llu.\n",
246 f->file_name, (unsigned long long)zbdz->start);
247 ret = -EIO;
248 goto out;
249 }
250
251 switch (zones[i].zbz_condition) {
252 case ZBC_ZC_NOT_WP:
253 zbdz->cond = ZBD_ZONE_COND_NOT_WP;
254 break;
255 case ZBC_ZC_EMPTY:
256 zbdz->cond = ZBD_ZONE_COND_EMPTY;
257 break;
258 case ZBC_ZC_IMP_OPEN:
259 zbdz->cond = ZBD_ZONE_COND_IMP_OPEN;
260 break;
261 case ZBC_ZC_EXP_OPEN:
262 zbdz->cond = ZBD_ZONE_COND_EXP_OPEN;
263 break;
264 case ZBC_ZC_CLOSED:
265 zbdz->cond = ZBD_ZONE_COND_CLOSED;
266 break;
267 case ZBC_ZC_FULL:
268 zbdz->cond = ZBD_ZONE_COND_FULL;
269 break;
270 case ZBC_ZC_RDONLY:
271 case ZBC_ZC_OFFLINE:
272 default:
273 /* Treat all these conditions as offline (don't use!) */
274 zbdz->cond = ZBD_ZONE_COND_OFFLINE;
59b67452 275 zbdz->wp = zbdz->start;
56a19325
DF
276 }
277 }
278
279 ret = nr_zones;
280out:
281 free(zones);
282 return ret;
283}
284
285static int libzbc_reset_wp(struct thread_data *td, struct fio_file *f,
286 uint64_t offset, uint64_t length)
287{
288 struct libzbc_data *ld = td->io_ops_data;
289 uint64_t sector = offset >> 9;
290 uint64_t end_sector = (offset + length) >> 9;
291 unsigned int nr_zones;
292 struct zbc_errno err;
293 int i, ret;
294
295 assert(ld);
296 assert(ld->zdev);
297
298 nr_zones = (length + td->o.zone_size - 1) / td->o.zone_size;
299 if (!sector && end_sector >= ld->nr_sectors) {
300 /* Reset all zones */
301 ret = zbc_reset_zone(ld->zdev, 0, ZBC_OP_ALL_ZONES);
302 if (ret)
303 goto err;
304
305 return 0;
306 }
307
308 for (i = 0; i < nr_zones; i++, sector += td->o.zone_size >> 9) {
309 ret = zbc_reset_zone(ld->zdev, sector, 0);
310 if (ret)
311 goto err;
312 }
313
314 return 0;
315
316err:
317 zbc_errno(ld->zdev, &err);
318 td_verror(td, errno, "zbc_reset_zone failed");
319 if (err.sk)
320 log_err("%s: reset wp failed %s:%s\n",
321 f->file_name,
322 zbc_sk_str(err.sk), zbc_asc_ascq_str(err.asc_ascq));
323 return -ret;
324}
325
a7f1b5cd
SK
326static int libzbc_finish_zone(struct thread_data *td, struct fio_file *f,
327 uint64_t offset, uint64_t length)
328{
329 struct libzbc_data *ld = td->io_ops_data;
330 uint64_t sector = offset >> 9;
331 unsigned int nr_zones;
332 struct zbc_errno err;
333 int i, ret;
334
335 assert(ld);
336 assert(ld->zdev);
337
338 nr_zones = (length + td->o.zone_size - 1) / td->o.zone_size;
339 assert(nr_zones > 0);
340
341 for (i = 0; i < nr_zones; i++, sector += td->o.zone_size >> 9) {
342 ret = zbc_finish_zone(ld->zdev, sector, 0);
343 if (ret)
344 goto err;
345 }
346
347 return 0;
348
349err:
350 zbc_errno(ld->zdev, &err);
351 td_verror(td, errno, "zbc_finish_zone failed");
352 if (err.sk)
353 log_err("%s: finish zone failed %s:%s\n",
354 f->file_name,
355 zbc_sk_str(err.sk), zbc_asc_ascq_str(err.asc_ascq));
356 return -ret;
357}
358
e8267436
NC
359static int libzbc_get_max_open_zones(struct thread_data *td, struct fio_file *f,
360 unsigned int *max_open_zones)
361{
362 struct libzbc_data *ld;
363 int ret;
364
365 ret = libzbc_open_dev(td, f, &ld);
366 if (ret)
367 return ret;
368
369 if (ld->max_open_seq_req == ZBC_NO_LIMIT)
370 *max_open_zones = 0;
371 else
372 *max_open_zones = ld->max_open_seq_req;
373
374 return 0;
375}
376
56a19325
DF
377ssize_t libzbc_rw(struct thread_data *td, struct io_u *io_u)
378{
379 struct libzbc_data *ld = td->io_ops_data;
380 struct fio_file *f = io_u->file;
381 uint64_t sector = io_u->offset >> 9;
382 size_t count = io_u->xfer_buflen >> 9;
383 struct zbc_errno err;
384 ssize_t ret;
385
386 if (io_u->ddir == DDIR_WRITE)
387 ret = zbc_pwrite(ld->zdev, io_u->xfer_buf, count, sector);
388 else
389 ret = zbc_pread(ld->zdev, io_u->xfer_buf, count, sector);
390 if (ret == count)
391 return ret;
392
393 if (ret > 0) {
394 log_err("Short %s, len=%zu, ret=%zd\n",
395 io_u->ddir == DDIR_READ ? "read" : "write",
396 count << 9, ret << 9);
397 return -EIO;
398 }
399
400 /* I/O error */
401 zbc_errno(ld->zdev, &err);
402 td_verror(td, errno, "libzbc i/o failed");
403 if (err.sk) {
404 log_err("%s: op %u offset %llu+%llu failed (%s:%s), err %zd\n",
405 f->file_name, io_u->ddir,
406 io_u->offset, io_u->xfer_buflen,
407 zbc_sk_str(err.sk),
408 zbc_asc_ascq_str(err.asc_ascq), ret);
409 } else {
410 log_err("%s: op %u offset %llu+%llu failed, err %zd\n",
411 f->file_name, io_u->ddir,
412 io_u->offset, io_u->xfer_buflen, ret);
413 }
414
415 return -EIO;
416}
417
418static enum fio_q_status libzbc_queue(struct thread_data *td, struct io_u *io_u)
419{
420 struct libzbc_data *ld = td->io_ops_data;
421 struct fio_file *f = io_u->file;
422 ssize_t ret = 0;
423
424 fio_ro_check(td, io_u);
425
426 dprint(FD_ZBD, "%p:%s: libzbc queue %llu\n",
427 td, f->file_name, io_u->offset);
428
429 if (io_u->ddir == DDIR_READ || io_u->ddir == DDIR_WRITE) {
430 ret = libzbc_rw(td, io_u);
431 } else if (ddir_sync(io_u->ddir)) {
432 ret = zbc_flush(ld->zdev);
433 if (ret)
434 log_err("zbc_flush error %zd\n", ret);
84f07387
SK
435 } else if (io_u->ddir == DDIR_TRIM) {
436 ret = zbd_do_io_u_trim(td, io_u);
437 if (!ret)
438 ret = EINVAL;
439 } else {
56a19325
DF
440 log_err("Unsupported operation %u\n", io_u->ddir);
441 ret = -EINVAL;
442 }
443 if (ret < 0)
444 io_u->error = -ret;
445
446 return FIO_Q_COMPLETED;
447}
448
5a8a6a03 449FIO_STATIC struct ioengine_ops ioengine = {
56a19325
DF
450 .name = "libzbc",
451 .version = FIO_IOOPS_VERSION,
452 .open_file = libzbc_open_file,
453 .close_file = libzbc_close_file,
454 .cleanup = libzbc_cleanup,
455 .invalidate = libzbc_invalidate,
456 .get_file_size = libzbc_get_file_size,
457 .get_zoned_model = libzbc_get_zoned_model,
458 .report_zones = libzbc_report_zones,
459 .reset_wp = libzbc_reset_wp,
e8267436 460 .get_max_open_zones = libzbc_get_max_open_zones,
a7f1b5cd 461 .finish_zone = libzbc_finish_zone,
56a19325 462 .queue = libzbc_queue,
06ec57ef 463 .flags = FIO_SYNCIO | FIO_NOEXTEND | FIO_RAWIO,
56a19325
DF
464};
465
466static void fio_init fio_libzbc_register(void)
467{
468 register_ioengine(&ioengine);
469}
470
471static void fio_exit fio_libzbc_unregister(void)
472{
473 unregister_ioengine(&ioengine);
474}