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