stat: make add lat percentile functions inline
[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)) {
71 if (f->filetype == FIO_TYPE_CHAR && !read_only)
72 flags |= O_RDWR;
73 else
74 flags |= O_RDONLY;
56a19325
DF
75 }
76
976fb54e 77 if (td->o.oatomic) {
56a19325 78 td_verror(td, EINVAL, "libzbc does not support O_ATOMIC");
976fb54e
DF
79 log_err("%s: libzbc does not support O_ATOMIC\n", f->file_name);
80 return -EINVAL;
81 }
56a19325
DF
82
83 ld = calloc(1, sizeof(*ld));
84 if (!ld)
85 return -ENOMEM;
86
87 ret = zbc_open(f->file_name,
ed2eb875
DF
88 flags | ZBC_O_DRV_BLOCK | ZBC_O_DRV_SCSI | ZBC_O_DRV_ATA,
89 &ld->zdev);
56a19325
DF
90 if (ret) {
91 log_err("%s: zbc_open() failed, err=%d\n",
92 f->file_name, ret);
891660e4 93 goto err;
56a19325
DF
94 }
95
96 ret = libzbc_get_dev_info(ld, f);
891660e4
DF
97 if (ret)
98 goto err_close;
56a19325
DF
99
100 td->io_ops_data = ld;
101out:
102 if (p_ld)
103 *p_ld = ld;
104
105 return 0;
891660e4
DF
106
107err_close:
108 zbc_close(ld->zdev);
109err:
110 free(ld);
111 return ret;
56a19325
DF
112}
113
114static int libzbc_close_dev(struct thread_data *td)
115{
116 struct libzbc_data *ld = td->io_ops_data;
117 int ret = 0;
118
119 td->io_ops_data = NULL;
120 if (ld) {
121 if (ld->zdev)
122 ret = zbc_close(ld->zdev);
123 free(ld);
124 }
125
126 return ret;
127}
128static int libzbc_open_file(struct thread_data *td, struct fio_file *f)
129{
130 return libzbc_open_dev(td, f, NULL);
131}
132
133static int libzbc_close_file(struct thread_data *td, struct fio_file *f)
134{
135 int ret;
136
137 ret = libzbc_close_dev(td);
138 if (ret)
139 log_err("%s: close device failed err %d\n",
140 f->file_name, ret);
141
142 return ret;
143}
144
145static void libzbc_cleanup(struct thread_data *td)
146{
147 libzbc_close_dev(td);
148}
149
150static int libzbc_invalidate(struct thread_data *td, struct fio_file *f)
151{
152 /* Passthrough IO do not cache data. Nothing to do */
153 return 0;
154}
155
156static int libzbc_get_file_size(struct thread_data *td, struct fio_file *f)
157{
158 struct libzbc_data *ld;
159 int ret;
160
161 if (fio_file_size_known(f))
162 return 0;
163
164 ret = libzbc_open_dev(td, f, &ld);
165 if (ret)
166 return ret;
167
168 f->real_file_size = ld->nr_sectors << 9;
169 fio_file_set_size_known(f);
170
171 return 0;
172}
173
174static int libzbc_get_zoned_model(struct thread_data *td, struct fio_file *f,
175 enum zbd_zoned_model *model)
176{
177 struct libzbc_data *ld;
178 int ret;
179
2c7dd23e
NC
180 if (f->filetype != FIO_TYPE_BLOCK && f->filetype != FIO_TYPE_CHAR)
181 return -EINVAL;
56a19325
DF
182
183 ret = libzbc_open_dev(td, f, &ld);
184 if (ret)
185 return ret;
186
187 switch (ld->model) {
188 case ZBC_DM_HOST_AWARE:
189 *model = ZBD_HOST_AWARE;
190 break;
191 case ZBC_DM_HOST_MANAGED:
192 *model = ZBD_HOST_MANAGED;
193 break;
194 default:
195 *model = ZBD_NONE;
196 break;
197 }
198
199 return 0;
200}
201
202static int libzbc_report_zones(struct thread_data *td, struct fio_file *f,
203 uint64_t offset, struct zbd_zone *zbdz,
204 unsigned int nr_zones)
205{
206 struct libzbc_data *ld;
207 uint64_t sector = offset >> 9;
208 struct zbc_zone *zones;
209 unsigned int i;
210 int ret;
211
212 ret = libzbc_open_dev(td, f, &ld);
213 if (ret)
214 return ret;
215
216 if (sector >= ld->nr_sectors)
217 return 0;
218
219 zones = calloc(nr_zones, sizeof(struct zbc_zone));
220 if (!zones) {
221 ret = -ENOMEM;
222 goto out;
223 }
224
225 ret = zbc_report_zones(ld->zdev, sector, ZBC_RO_ALL, zones, &nr_zones);
226 if (ret < 0) {
227 log_err("%s: zbc_report_zones failed, err=%d\n",
228 f->file_name, ret);
229 goto out;
230 }
231
232 for (i = 0; i < nr_zones; i++, zbdz++) {
233 zbdz->start = zones[i].zbz_start << 9;
234 zbdz->len = zones[i].zbz_length << 9;
235 zbdz->wp = zones[i].zbz_write_pointer << 9;
236d23a8
SK
236 /*
237 * ZBC/ZAC do not define zone capacity, so use the zone size as
238 * the zone capacity.
239 */
240 zbdz->capacity = zbdz->len;
56a19325
DF
241
242 switch (zones[i].zbz_type) {
243 case ZBC_ZT_CONVENTIONAL:
244 zbdz->type = ZBD_ZONE_TYPE_CNV;
245 break;
246 case ZBC_ZT_SEQUENTIAL_REQ:
247 zbdz->type = ZBD_ZONE_TYPE_SWR;
248 break;
249 case ZBC_ZT_SEQUENTIAL_PREF:
250 zbdz->type = ZBD_ZONE_TYPE_SWP;
251 break;
252 default:
253 td_verror(td, errno, "invalid zone type");
254 log_err("%s: invalid type for zone at sector %llu.\n",
255 f->file_name, (unsigned long long)zbdz->start);
256 ret = -EIO;
257 goto out;
258 }
259
260 switch (zones[i].zbz_condition) {
261 case ZBC_ZC_NOT_WP:
262 zbdz->cond = ZBD_ZONE_COND_NOT_WP;
263 break;
264 case ZBC_ZC_EMPTY:
265 zbdz->cond = ZBD_ZONE_COND_EMPTY;
266 break;
267 case ZBC_ZC_IMP_OPEN:
268 zbdz->cond = ZBD_ZONE_COND_IMP_OPEN;
269 break;
270 case ZBC_ZC_EXP_OPEN:
271 zbdz->cond = ZBD_ZONE_COND_EXP_OPEN;
272 break;
273 case ZBC_ZC_CLOSED:
274 zbdz->cond = ZBD_ZONE_COND_CLOSED;
275 break;
276 case ZBC_ZC_FULL:
277 zbdz->cond = ZBD_ZONE_COND_FULL;
278 break;
279 case ZBC_ZC_RDONLY:
280 case ZBC_ZC_OFFLINE:
281 default:
282 /* Treat all these conditions as offline (don't use!) */
283 zbdz->cond = ZBD_ZONE_COND_OFFLINE;
59b67452 284 zbdz->wp = zbdz->start;
56a19325
DF
285 }
286 }
287
288 ret = nr_zones;
289out:
290 free(zones);
291 return ret;
292}
293
294static int libzbc_reset_wp(struct thread_data *td, struct fio_file *f,
295 uint64_t offset, uint64_t length)
296{
297 struct libzbc_data *ld = td->io_ops_data;
298 uint64_t sector = offset >> 9;
299 uint64_t end_sector = (offset + length) >> 9;
300 unsigned int nr_zones;
301 struct zbc_errno err;
302 int i, ret;
303
304 assert(ld);
305 assert(ld->zdev);
306
307 nr_zones = (length + td->o.zone_size - 1) / td->o.zone_size;
308 if (!sector && end_sector >= ld->nr_sectors) {
309 /* Reset all zones */
310 ret = zbc_reset_zone(ld->zdev, 0, ZBC_OP_ALL_ZONES);
311 if (ret)
312 goto err;
313
314 return 0;
315 }
316
317 for (i = 0; i < nr_zones; i++, sector += td->o.zone_size >> 9) {
318 ret = zbc_reset_zone(ld->zdev, sector, 0);
319 if (ret)
320 goto err;
321 }
322
323 return 0;
324
325err:
326 zbc_errno(ld->zdev, &err);
327 td_verror(td, errno, "zbc_reset_zone failed");
328 if (err.sk)
329 log_err("%s: reset wp failed %s:%s\n",
330 f->file_name,
331 zbc_sk_str(err.sk), zbc_asc_ascq_str(err.asc_ascq));
332 return -ret;
333}
334
e8267436
NC
335static int libzbc_get_max_open_zones(struct thread_data *td, struct fio_file *f,
336 unsigned int *max_open_zones)
337{
338 struct libzbc_data *ld;
339 int ret;
340
341 ret = libzbc_open_dev(td, f, &ld);
342 if (ret)
343 return ret;
344
345 if (ld->max_open_seq_req == ZBC_NO_LIMIT)
346 *max_open_zones = 0;
347 else
348 *max_open_zones = ld->max_open_seq_req;
349
350 return 0;
351}
352
56a19325
DF
353ssize_t libzbc_rw(struct thread_data *td, struct io_u *io_u)
354{
355 struct libzbc_data *ld = td->io_ops_data;
356 struct fio_file *f = io_u->file;
357 uint64_t sector = io_u->offset >> 9;
358 size_t count = io_u->xfer_buflen >> 9;
359 struct zbc_errno err;
360 ssize_t ret;
361
362 if (io_u->ddir == DDIR_WRITE)
363 ret = zbc_pwrite(ld->zdev, io_u->xfer_buf, count, sector);
364 else
365 ret = zbc_pread(ld->zdev, io_u->xfer_buf, count, sector);
366 if (ret == count)
367 return ret;
368
369 if (ret > 0) {
370 log_err("Short %s, len=%zu, ret=%zd\n",
371 io_u->ddir == DDIR_READ ? "read" : "write",
372 count << 9, ret << 9);
373 return -EIO;
374 }
375
376 /* I/O error */
377 zbc_errno(ld->zdev, &err);
378 td_verror(td, errno, "libzbc i/o failed");
379 if (err.sk) {
380 log_err("%s: op %u offset %llu+%llu failed (%s:%s), err %zd\n",
381 f->file_name, io_u->ddir,
382 io_u->offset, io_u->xfer_buflen,
383 zbc_sk_str(err.sk),
384 zbc_asc_ascq_str(err.asc_ascq), ret);
385 } else {
386 log_err("%s: op %u offset %llu+%llu failed, err %zd\n",
387 f->file_name, io_u->ddir,
388 io_u->offset, io_u->xfer_buflen, ret);
389 }
390
391 return -EIO;
392}
393
394static enum fio_q_status libzbc_queue(struct thread_data *td, struct io_u *io_u)
395{
396 struct libzbc_data *ld = td->io_ops_data;
397 struct fio_file *f = io_u->file;
398 ssize_t ret = 0;
399
400 fio_ro_check(td, io_u);
401
402 dprint(FD_ZBD, "%p:%s: libzbc queue %llu\n",
403 td, f->file_name, io_u->offset);
404
405 if (io_u->ddir == DDIR_READ || io_u->ddir == DDIR_WRITE) {
406 ret = libzbc_rw(td, io_u);
407 } else if (ddir_sync(io_u->ddir)) {
408 ret = zbc_flush(ld->zdev);
409 if (ret)
410 log_err("zbc_flush error %zd\n", ret);
84f07387
SK
411 } else if (io_u->ddir == DDIR_TRIM) {
412 ret = zbd_do_io_u_trim(td, io_u);
413 if (!ret)
414 ret = EINVAL;
415 } else {
56a19325
DF
416 log_err("Unsupported operation %u\n", io_u->ddir);
417 ret = -EINVAL;
418 }
419 if (ret < 0)
420 io_u->error = -ret;
421
422 return FIO_Q_COMPLETED;
423}
424
5a8a6a03 425FIO_STATIC struct ioengine_ops ioengine = {
56a19325
DF
426 .name = "libzbc",
427 .version = FIO_IOOPS_VERSION,
428 .open_file = libzbc_open_file,
429 .close_file = libzbc_close_file,
430 .cleanup = libzbc_cleanup,
431 .invalidate = libzbc_invalidate,
432 .get_file_size = libzbc_get_file_size,
433 .get_zoned_model = libzbc_get_zoned_model,
434 .report_zones = libzbc_report_zones,
435 .reset_wp = libzbc_reset_wp,
e8267436 436 .get_max_open_zones = libzbc_get_max_open_zones,
56a19325
DF
437 .queue = libzbc_queue,
438 .flags = FIO_SYNCIO | FIO_NOEXTEND | FIO_RAWIO,
439};
440
441static void fio_init fio_libzbc_register(void)
442{
443 register_ioengine(&ioengine);
444}
445
446static void fio_exit fio_libzbc_unregister(void)
447{
448 unregister_ioengine(&ioengine);
449}