3ea1e289604ba6159bf9e3c3f92b3b8d0000ee92
[fio.git] / engines / sg.c
1 /*
2  * scsi generic sg v3 io engine
3  *
4  */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <assert.h>
10 #include <sys/poll.h>
11
12 #include "../fio.h"
13 #include "../os.h"
14
15 #ifdef FIO_HAVE_SGIO
16
17 struct sgio_cmd {
18         unsigned char cdb[10];
19         int nr;
20 };
21
22 struct sgio_data {
23         struct sgio_cmd *cmds;
24         struct io_u **events;
25         unsigned int bs;
26 };
27
28 static void sgio_hdr_init(struct sgio_data *sd, struct sg_io_hdr *hdr,
29                           struct io_u *io_u, int fs)
30 {
31         struct sgio_cmd *sc = &sd->cmds[io_u->index];
32
33         memset(hdr, 0, sizeof(*hdr));
34         memset(sc->cdb, 0, sizeof(sc->cdb));
35
36         hdr->interface_id = 'S';
37         hdr->cmdp = sc->cdb;
38         hdr->cmd_len = sizeof(sc->cdb);
39         hdr->pack_id = io_u->index;
40         hdr->usr_ptr = io_u;
41
42         if (fs) {
43                 hdr->dxferp = io_u->buf;
44                 hdr->dxfer_len = io_u->buflen;
45         }
46 }
47
48 static int fio_sgio_ioctl_getevents(struct thread_data *td, int fio_unused min,
49                                     int max, struct timespec fio_unused *t)
50 {
51         assert(max <= 1);
52
53         /*
54          * we can only have one finished io_u for sync io, since the depth
55          * is always 1
56          */
57         if (list_empty(&td->io_u_busylist))
58                 return 0;
59
60         return 1;
61 }
62
63
64 static int fio_sgio_getevents(struct thread_data *td, int min, int max,
65                               struct timespec fio_unused *t)
66 {
67         struct fio_file *f = &td->files[0];
68         struct sgio_data *sd = td->io_ops->data;
69         struct pollfd pfd = { .fd = f->fd, .events = POLLIN };
70         void *buf = malloc(max * sizeof(struct sg_io_hdr));
71         int left = max, ret, events, i, r = 0, fl = 0;
72
73         /*
74          * don't block for !events
75          */
76         if (!min) {
77                 fl = fcntl(f->fd, F_GETFL);
78                 fcntl(f->fd, F_SETFL, fl | O_NONBLOCK);
79         }
80
81         while (left) {
82                 do {
83                         if (!min)
84                                 break;
85                         poll(&pfd, 1, -1);
86                         if (pfd.revents & POLLIN)
87                                 break;
88                 } while (1);
89
90                 ret = read(f->fd, buf, left * sizeof(struct sg_io_hdr));
91                 if (ret < 0) {
92                         if (errno == EAGAIN)
93                                 break;
94                         td_verror(td, errno);
95                         r = -1;
96                         break;
97                 } else if (!ret)
98                         break;
99
100                 events = ret / sizeof(struct sg_io_hdr);
101                 left -= events;
102                 r += events;
103
104                 for (i = 0; i < events; i++) {
105                         struct sg_io_hdr *hdr = (struct sg_io_hdr *) buf + i;
106
107                         sd->events[i] = hdr->usr_ptr;
108                 }
109         }
110
111         if (!min)
112                 fcntl(f->fd, F_SETFL, fl);
113
114         free(buf);
115         return r;
116 }
117
118 static int fio_sgio_ioctl_doio(struct thread_data *td,
119                                struct fio_file *f, struct io_u *io_u)
120 {
121         struct sgio_data *sd = td->io_ops->data;
122         struct sg_io_hdr *hdr = &io_u->hdr;
123
124         sd->events[0] = io_u;
125
126         return ioctl(f->fd, SG_IO, hdr);
127 }
128
129 static int fio_sgio_rw_doio(struct fio_file *f, struct io_u *io_u, int sync)
130 {
131         struct sg_io_hdr *hdr = &io_u->hdr;
132         int ret;
133
134         ret = write(f->fd, hdr, sizeof(*hdr));
135         if (ret < 0)
136                 return errno;
137
138         if (sync) {
139                 ret = read(f->fd, hdr, sizeof(*hdr));
140                 if (ret < 0)
141                         return errno;
142         }
143
144         return 0;
145 }
146
147 static int fio_sgio_doio(struct thread_data *td, struct io_u *io_u, int sync)
148 {
149         struct fio_file *f = io_u->file;
150
151         if (td->filetype == FIO_TYPE_BD)
152                 return fio_sgio_ioctl_doio(td, f, io_u);
153
154         return fio_sgio_rw_doio(f, io_u, sync);
155 }
156
157 static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u)
158 {
159         struct sg_io_hdr *hdr = &io_u->hdr;
160         struct sgio_data *sd = td->io_ops->data;
161         int nr_blocks, lba;
162
163         if (io_u->buflen & (sd->bs - 1)) {
164                 log_err("read/write not sector aligned\n");
165                 return EINVAL;
166         }
167
168         if (io_u->ddir == DDIR_READ) {
169                 sgio_hdr_init(sd, hdr, io_u, 1);
170
171                 hdr->dxfer_direction = SG_DXFER_FROM_DEV;
172                 hdr->cmdp[0] = 0x28;
173         } else if (io_u->ddir == DDIR_WRITE) {
174                 sgio_hdr_init(sd, hdr, io_u, 1);
175
176                 hdr->dxfer_direction = SG_DXFER_TO_DEV;
177                 hdr->cmdp[0] = 0x2a;
178         } else {
179                 sgio_hdr_init(sd, hdr, io_u, 0);
180
181                 hdr->dxfer_direction = SG_DXFER_NONE;
182                 hdr->cmdp[0] = 0x35;
183         }
184
185         if (hdr->dxfer_direction != SG_DXFER_NONE) {
186                 nr_blocks = io_u->buflen / sd->bs;
187                 lba = io_u->offset / sd->bs;
188                 hdr->cmdp[2] = (unsigned char) ((lba >> 24) & 0xff);
189                 hdr->cmdp[3] = (unsigned char) ((lba >> 16) & 0xff);
190                 hdr->cmdp[4] = (unsigned char) ((lba >>  8) & 0xff);
191                 hdr->cmdp[5] = (unsigned char) (lba & 0xff);
192                 hdr->cmdp[7] = (unsigned char) ((nr_blocks >> 8) & 0xff);
193                 hdr->cmdp[8] = (unsigned char) (nr_blocks & 0xff);
194         }
195
196         return 0;
197 }
198
199 static int fio_sgio_queue(struct thread_data *td, struct io_u *io_u)
200 {
201         struct sg_io_hdr *hdr = &io_u->hdr;
202         int ret;
203
204         ret = fio_sgio_doio(td, io_u, io_u->ddir == DDIR_SYNC);
205
206         if (ret < 0)
207                 io_u->error = errno;
208         else if (hdr->status) {
209                 io_u->resid = hdr->resid;
210                 io_u->error = EIO;
211         }
212
213         return io_u->error;
214 }
215
216 static struct io_u *fio_sgio_event(struct thread_data *td, int event)
217 {
218         struct sgio_data *sd = td->io_ops->data;
219
220         return sd->events[event];
221 }
222
223 static int fio_sgio_get_bs(struct thread_data *td, unsigned int *bs)
224 {
225         struct sgio_data *sd = td->io_ops->data;
226         struct io_u *io_u;
227         struct sg_io_hdr *hdr;
228         unsigned char buf[8];
229         int ret;
230
231         io_u = __get_io_u(td);
232         assert(io_u);
233
234         hdr = &io_u->hdr;
235         sgio_hdr_init(sd, hdr, io_u, 0);
236         memset(buf, 0, sizeof(buf));
237
238         hdr->cmdp[0] = 0x25;
239         hdr->dxfer_direction = SG_DXFER_FROM_DEV;
240         hdr->dxferp = buf;
241         hdr->dxfer_len = sizeof(buf);
242
243         ret = fio_sgio_doio(td, io_u, 1);
244         if (ret) {
245                 put_io_u(td, io_u);
246                 return ret;
247         }
248
249         *bs = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
250         put_io_u(td, io_u);
251         return 0;
252 }
253
254 static void fio_sgio_cleanup(struct thread_data *td)
255 {
256         if (td->io_ops->data) {
257                 free(td->io_ops->data);
258                 td->io_ops->data = NULL;
259         }
260 }
261
262 static int fio_sgio_init(struct thread_data *td)
263 {
264         struct fio_file *f = &td->files[0];
265         struct sgio_data *sd;
266         unsigned int bs;
267         int ret;
268
269         sd = malloc(sizeof(*sd));
270         memset(sd, 0, sizeof(*sd));
271         sd->cmds = malloc(td->iodepth * sizeof(struct sgio_cmd));
272         memset(sd->cmds, 0, td->iodepth * sizeof(struct sgio_cmd));
273         sd->events = malloc(td->iodepth * sizeof(struct io_u *));
274         memset(sd->events, 0, td->iodepth * sizeof(struct io_u *));
275         td->io_ops->data = sd;
276
277         if (td->filetype == FIO_TYPE_BD) {
278                 if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
279                         td_verror(td, errno);
280                         goto err;
281                 }
282         } else if (td->filetype == FIO_TYPE_CHAR) {
283                 int version;
284
285                 if (ioctl(f->fd, SG_GET_VERSION_NUM, &version) < 0) {
286                         td_verror(td, errno);
287                         goto err;
288                 }
289
290                 ret = fio_sgio_get_bs(td, &bs);
291                 if (ret)
292                         goto err;
293         } else {
294                 log_err("ioengine sgio only works on block devices\n");
295                 goto err;
296         }
297
298         sd->bs = bs;
299
300         if (td->filetype == FIO_TYPE_BD)
301                 td->io_ops->getevents = fio_sgio_ioctl_getevents;
302         else
303                 td->io_ops->getevents = fio_sgio_getevents;
304
305         /*
306          * we want to do it, regardless of whether odirect is set or not
307          */
308         td->override_sync = 1;
309         return 0;
310 err:
311         free(sd->events);
312         free(sd->cmds);
313         free(sd);
314         td->io_ops->data = NULL;
315         return 1;
316 }
317
318 static struct ioengine_ops ioengine = {
319         .name           = "sg",
320         .version        = FIO_IOOPS_VERSION,
321         .init           = fio_sgio_init,
322         .prep           = fio_sgio_prep,
323         .queue          = fio_sgio_queue,
324         .getevents      = fio_sgio_getevents,
325         .event          = fio_sgio_event,
326         .cleanup        = fio_sgio_cleanup,
327         .flags          = FIO_SYNCIO | FIO_RAWIO,
328 };
329
330 #else /* FIO_HAVE_SGIO */
331
332 /*
333  * When we have a proper configure system in place, we simply wont build
334  * and install this io engine. For now install a crippled version that
335  * just complains and fails to load.
336  */
337 static int fio_sgio_init(struct thread_data fio_unused *td)
338 {
339         fprintf(stderr, "fio: sgio not available\n");
340         return 1;
341 }
342
343 static struct ioengine_ops ioengine = {
344         .name           = "sgio",
345         .version        = FIO_IOOPS_VERSION,
346         .init           = fio_sgio_init,
347 };
348
349 #endif
350
351 static void fio_init fio_sgio_register(void)
352 {
353         register_ioengine(&ioengine);
354 }
355
356 static void fio_exit fio_sgio_unregister(void)
357 {
358         unregister_ioengine(&ioengine);
359 }