NULL engine: ->commit() has side effects, make sure it always works
[fio.git] / engines / sg.c
1 /*
2  * sg engine
3  *
4  * IO engine that uses the Linux SG v3 interface to talk to SCSI devices
5  *
6  */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <assert.h>
12 #include <sys/poll.h>
13
14 #include "../fio.h"
15 #include "../os.h"
16
17 #ifdef FIO_HAVE_SGIO
18
19 struct sgio_cmd {
20         unsigned char cdb[10];
21         int nr;
22 };
23
24 struct sgio_data {
25         struct sgio_cmd *cmds;
26         struct io_u **events;
27         struct pollfd *pfds;
28         int *fd_flags;
29         void *sgbuf;
30         unsigned int bs;
31         int type_checked;
32 };
33
34 static void sgio_hdr_init(struct sgio_data *sd, struct sg_io_hdr *hdr,
35                           struct io_u *io_u, int fs)
36 {
37         struct sgio_cmd *sc = &sd->cmds[io_u->index];
38
39         memset(hdr, 0, sizeof(*hdr));
40         memset(sc->cdb, 0, sizeof(sc->cdb));
41
42         hdr->interface_id = 'S';
43         hdr->cmdp = sc->cdb;
44         hdr->cmd_len = sizeof(sc->cdb);
45         hdr->pack_id = io_u->index;
46         hdr->usr_ptr = io_u;
47
48         if (fs) {
49                 hdr->dxferp = io_u->xfer_buf;
50                 hdr->dxfer_len = io_u->xfer_buflen;
51         }
52 }
53
54 static int pollin_events(struct pollfd *pfds, int fds)
55 {
56         int i;
57
58         for (i = 0; i < fds; i++)
59                 if (pfds[i].revents & POLLIN)
60                         return 1;
61
62         return 0;
63 }
64
65 static int fio_sgio_getevents(struct thread_data *td, int min, int max,
66                               struct timespec fio_unused *t)
67 {
68         /*
69          * normally hard coding &td->files[0] is a bug that needs to be fixed,
70          * but it's ok here as all files should point to the same device.
71          */
72         struct fio_file *f = &td->files[0];
73         struct sgio_data *sd = td->io_ops->data;
74         int left = max, ret, r = 0;
75         void *buf = sd->sgbuf;
76         unsigned int i, events;
77
78         /*
79          * Fill in the file descriptors
80          */
81         for_each_file(td, f, i) {
82                 /*
83                  * don't block for min events == 0
84                  */
85                 if (!min) {
86                         sd->fd_flags[i] = fcntl(f->fd, F_GETFL);
87                         fcntl(f->fd, F_SETFL, sd->fd_flags[i] | O_NONBLOCK);
88                 }
89                 sd->pfds[i].fd = f->fd;
90                 sd->pfds[i].events = POLLIN;
91         }
92
93         while (left) {
94                 void *p;
95
96                 do {
97                         if (!min)
98                                 break;
99
100                         ret = poll(sd->pfds, td->o.nr_files, -1);
101                         if (ret < 0) {
102                                 if (!r)
103                                         r = -errno;
104                                 td_verror(td, errno, "poll");
105                                 break;
106                         } else if (!ret)
107                                 continue;
108
109                         if (pollin_events(sd->pfds, td->o.nr_files))
110                                 break;
111                 } while (1);
112
113                 if (r < 0)
114                         break;
115
116 re_read:
117                 p = buf;
118                 events = 0;
119                 for_each_file(td, f, i) {
120                         ret = read(f->fd, p, left * sizeof(struct sg_io_hdr));
121                         if (ret < 0) {
122                                 if (errno == EAGAIN)
123                                         continue;
124                                 r = -errno;
125                                 td_verror(td, errno, "read");
126                                 break;
127                         } else if (ret) {
128                                 p += ret;
129                                 events += ret / sizeof(struct sg_io_hdr);
130                         }
131                 }
132
133                 if (r < 0)
134                         break;
135                 if (!events) {
136                         usleep(1000);
137                         goto re_read;
138                 }
139
140                 left -= events;
141                 r += events;
142
143                 for (i = 0; i < events; i++) {
144                         struct sg_io_hdr *hdr = (struct sg_io_hdr *) buf + i;
145
146                         sd->events[i] = hdr->usr_ptr;
147                 }
148         }
149
150         if (!min) {
151                 for_each_file(td, f, i)
152                         fcntl(f->fd, F_SETFL, sd->fd_flags[i]);
153         }
154
155         return r;
156 }
157
158 static int fio_sgio_ioctl_doio(struct thread_data *td,
159                                struct fio_file *f, struct io_u *io_u)
160 {
161         struct sgio_data *sd = td->io_ops->data;
162         struct sg_io_hdr *hdr = &io_u->hdr;
163         int ret;
164
165         sd->events[0] = io_u;
166
167         ret = ioctl(f->fd, SG_IO, hdr);
168         if (ret < 0)
169                 return -errno;
170
171         return FIO_Q_COMPLETED;
172 }
173
174 static int fio_sgio_rw_doio(struct fio_file *f, struct io_u *io_u, int sync)
175 {
176         struct sg_io_hdr *hdr = &io_u->hdr;
177         int ret;
178
179         ret = write(f->fd, hdr, sizeof(*hdr));
180         if (ret < 0)
181                 return errno;
182
183         if (sync) {
184                 ret = read(f->fd, hdr, sizeof(*hdr));
185                 if (ret < 0)
186                         return -errno;
187                 return FIO_Q_COMPLETED;
188         }
189
190         return FIO_Q_QUEUED;
191 }
192
193 static int fio_sgio_doio(struct thread_data *td, struct io_u *io_u, int sync)
194 {
195         struct fio_file *f = io_u->file;
196
197         if (f->filetype == FIO_TYPE_BD)
198                 return fio_sgio_ioctl_doio(td, f, io_u);
199
200         return fio_sgio_rw_doio(f, io_u, sync);
201 }
202
203 static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u)
204 {
205         struct sg_io_hdr *hdr = &io_u->hdr;
206         struct sgio_data *sd = td->io_ops->data;
207         int nr_blocks, lba;
208
209         if (io_u->xfer_buflen & (sd->bs - 1)) {
210                 log_err("read/write not sector aligned\n");
211                 return EINVAL;
212         }
213
214         if (io_u->ddir == DDIR_READ) {
215                 sgio_hdr_init(sd, hdr, io_u, 1);
216
217                 hdr->dxfer_direction = SG_DXFER_FROM_DEV;
218                 hdr->cmdp[0] = 0x28;
219         } else if (io_u->ddir == DDIR_WRITE) {
220                 sgio_hdr_init(sd, hdr, io_u, 1);
221
222                 hdr->dxfer_direction = SG_DXFER_TO_DEV;
223                 hdr->cmdp[0] = 0x2a;
224         } else {
225                 sgio_hdr_init(sd, hdr, io_u, 0);
226
227                 hdr->dxfer_direction = SG_DXFER_NONE;
228                 hdr->cmdp[0] = 0x35;
229         }
230
231         if (hdr->dxfer_direction != SG_DXFER_NONE) {
232                 nr_blocks = io_u->xfer_buflen / sd->bs;
233                 lba = io_u->offset / sd->bs;
234                 hdr->cmdp[2] = (unsigned char) ((lba >> 24) & 0xff);
235                 hdr->cmdp[3] = (unsigned char) ((lba >> 16) & 0xff);
236                 hdr->cmdp[4] = (unsigned char) ((lba >>  8) & 0xff);
237                 hdr->cmdp[5] = (unsigned char) (lba & 0xff);
238                 hdr->cmdp[7] = (unsigned char) ((nr_blocks >> 8) & 0xff);
239                 hdr->cmdp[8] = (unsigned char) (nr_blocks & 0xff);
240         }
241
242         return 0;
243 }
244
245 static int fio_sgio_queue(struct thread_data *td, struct io_u *io_u)
246 {
247         struct sg_io_hdr *hdr = &io_u->hdr;
248         int ret;
249
250         ret = fio_sgio_doio(td, io_u, io_u->ddir == DDIR_SYNC);
251
252         if (ret < 0)
253                 io_u->error = errno;
254         else if (hdr->status) {
255                 io_u->resid = hdr->resid;
256                 io_u->error = EIO;
257         }
258
259         if (io_u->error) {
260                 td_verror(td, io_u->error, "xfer");
261                 return FIO_Q_COMPLETED;
262         }
263
264         return ret;
265 }
266
267 static struct io_u *fio_sgio_event(struct thread_data *td, int event)
268 {
269         struct sgio_data *sd = td->io_ops->data;
270
271         return sd->events[event];
272 }
273
274 static int fio_sgio_get_bs(struct thread_data *td, unsigned int *bs)
275 {
276         struct sgio_data *sd = td->io_ops->data;
277         struct io_u *io_u;
278         struct sg_io_hdr *hdr;
279         unsigned char buf[8];
280         int ret;
281
282         io_u = __get_io_u(td);
283         io_u->file = &td->files[0];
284         assert(io_u);
285
286         hdr = &io_u->hdr;
287         sgio_hdr_init(sd, hdr, io_u, 0);
288         memset(buf, 0, sizeof(buf));
289
290         hdr->cmdp[0] = 0x25;
291         hdr->dxfer_direction = SG_DXFER_FROM_DEV;
292         hdr->dxferp = buf;
293         hdr->dxfer_len = sizeof(buf);
294
295         ret = fio_sgio_doio(td, io_u, 1);
296         if (ret) {
297                 put_io_u(td, io_u);
298                 return ret;
299         }
300
301         *bs = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
302         put_io_u(td, io_u);
303         return 0;
304 }
305
306 static void fio_sgio_cleanup(struct thread_data *td)
307 {
308         struct sgio_data *sd = td->io_ops->data;
309
310         if (sd) {
311                 free(sd->events);
312                 free(sd->cmds);
313                 free(sd->fd_flags);
314                 free(sd->pfds);
315                 free(sd->sgbuf);
316                 free(sd);
317
318                 td->io_ops->data = NULL;
319         }
320 }
321
322 static int fio_sgio_init(struct thread_data *td)
323 {
324         struct sgio_data *sd;
325
326         sd = malloc(sizeof(*sd));
327         memset(sd, 0, sizeof(*sd));
328         sd->cmds = malloc(td->o.iodepth * sizeof(struct sgio_cmd));
329         memset(sd->cmds, 0, td->o.iodepth * sizeof(struct sgio_cmd));
330         sd->events = malloc(td->o.iodepth * sizeof(struct io_u *));
331         memset(sd->events, 0, td->o.iodepth * sizeof(struct io_u *));
332         sd->pfds = malloc(sizeof(struct pollfd) * td->o.nr_files);
333         memset(sd->pfds, 0, sizeof(struct pollfd) * td->o.nr_files);
334         sd->fd_flags = malloc(sizeof(int) * td->o.nr_files);
335         memset(sd->fd_flags, 0, sizeof(int) * td->o.nr_files);
336         sd->sgbuf = malloc(sizeof(struct sg_io_hdr) * td->o.iodepth);
337         memset(sd->sgbuf, 0, sizeof(struct sg_io_hdr) * td->o.iodepth);
338
339         td->io_ops->data = sd;
340
341         /*
342          * we want to do it, regardless of whether odirect is set or not
343          */
344         td->o.override_sync = 1;
345         return 0;
346 }
347
348 static int fio_sgio_type_check(struct thread_data *td, struct fio_file *f)
349 {
350         struct sgio_data *sd = td->io_ops->data;
351         unsigned int bs;
352
353         if (f->filetype == FIO_TYPE_BD) {
354                 if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
355                         td_verror(td, errno, "ioctl");
356                         return 1;
357                 }
358         } else if (f->filetype == FIO_TYPE_CHAR) {
359                 int version, ret;
360
361                 if (ioctl(f->fd, SG_GET_VERSION_NUM, &version) < 0) {
362                         td_verror(td, errno, "ioctl");
363                         return 1;
364                 }
365
366                 ret = fio_sgio_get_bs(td, &bs);
367                 if (ret)
368                         return 1;
369         } else {
370                 log_err("ioengine sgio only works on block devices\n");
371                 return 1;
372         }
373
374         sd->bs = bs;
375
376         if (f->filetype == FIO_TYPE_BD) {
377                 td->io_ops->getevents = NULL;
378                 td->io_ops->event = NULL;
379         }
380
381         return 0;
382 }
383
384 static int fio_sgio_open(struct thread_data *td, struct fio_file *f)
385 {
386         struct sgio_data *sd = td->io_ops->data;
387         int ret;
388
389         ret = generic_open_file(td, f);
390         if (ret)
391                 return ret;
392
393         if (!sd->type_checked && fio_sgio_type_check(td, f)) {
394                 generic_close_file(td, f);
395                 return 1;
396         }
397
398         return 0;
399 }
400
401 static struct ioengine_ops ioengine = {
402         .name           = "sg",
403         .version        = FIO_IOOPS_VERSION,
404         .init           = fio_sgio_init,
405         .prep           = fio_sgio_prep,
406         .queue          = fio_sgio_queue,
407         .getevents      = fio_sgio_getevents,
408         .event          = fio_sgio_event,
409         .cleanup        = fio_sgio_cleanup,
410         .open_file      = fio_sgio_open,
411         .close_file     = generic_close_file,
412         .flags          = FIO_SYNCIO | FIO_RAWIO,
413 };
414
415 #else /* FIO_HAVE_SGIO */
416
417 /*
418  * When we have a proper configure system in place, we simply wont build
419  * and install this io engine. For now install a crippled version that
420  * just complains and fails to load.
421  */
422 static int fio_sgio_init(struct thread_data fio_unused *td)
423 {
424         fprintf(stderr, "fio: sgio not available\n");
425         return 1;
426 }
427
428 static struct ioengine_ops ioengine = {
429         .name           = "sgio",
430         .version        = FIO_IOOPS_VERSION,
431         .init           = fio_sgio_init,
432 };
433
434 #endif
435
436 static void fio_init fio_sgio_register(void)
437 {
438         register_ioengine(&ioengine);
439 }
440
441 static void fio_exit fio_sgio_unregister(void)
442 {
443         unregister_ioengine(&ioengine);
444 }