[PATCH] Support residual io counts from io engines
[fio.git] / engines / sg.c
CommitLineData
2866c82d
JA
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>
5f350952
JA
11
12#include "../fio.h"
13#include "../os.h"
2866c82d 14
34cfcdaf
JA
15#ifdef FIO_HAVE_SGIO
16
2866c82d
JA
17struct sgio_cmd {
18 unsigned char cdb[10];
19 int nr;
20};
21
22struct sgio_data {
23 struct sgio_cmd *cmds;
24 struct io_u **events;
25 unsigned int bs;
26};
27
28static 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) {
cec6b55d
JA
43 hdr->dxferp = io_u->xfer_buf;
44 hdr->dxfer_len = io_u->xfer_buflen;
2866c82d
JA
45 }
46}
47
48static 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
64static int fio_sgio_getevents(struct thread_data *td, int min, int max,
65 struct timespec fio_unused *t)
66{
53cdc686 67 struct fio_file *f = &td->files[0];
2866c82d 68 struct sgio_data *sd = td->io_ops->data;
53cdc686 69 struct pollfd pfd = { .fd = f->fd, .events = POLLIN };
2866c82d
JA
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) {
53cdc686
JA
77 fl = fcntl(f->fd, F_GETFL);
78 fcntl(f->fd, F_SETFL, fl | O_NONBLOCK);
2866c82d
JA
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
53cdc686 90 ret = read(f->fd, buf, left * sizeof(struct sg_io_hdr));
2866c82d
JA
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)
53cdc686 112 fcntl(f->fd, F_SETFL, fl);
2866c82d
JA
113
114 free(buf);
115 return r;
116}
117
7a16dd02
JA
118static int fio_sgio_ioctl_doio(struct thread_data *td,
119 struct fio_file *f, struct io_u *io_u)
2866c82d
JA
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
53cdc686 126 return ioctl(f->fd, SG_IO, hdr);
2866c82d
JA
127}
128
7a16dd02 129static int fio_sgio_rw_doio(struct fio_file *f, struct io_u *io_u, int sync)
2866c82d
JA
130{
131 struct sg_io_hdr *hdr = &io_u->hdr;
132 int ret;
133
53cdc686 134 ret = write(f->fd, hdr, sizeof(*hdr));
2866c82d
JA
135 if (ret < 0)
136 return errno;
137
138 if (sync) {
53cdc686 139 ret = read(f->fd, hdr, sizeof(*hdr));
2866c82d
JA
140 if (ret < 0)
141 return errno;
142 }
143
144 return 0;
145}
146
147static int fio_sgio_doio(struct thread_data *td, struct io_u *io_u, int sync)
148{
53cdc686
JA
149 struct fio_file *f = io_u->file;
150
2866c82d 151 if (td->filetype == FIO_TYPE_BD)
53cdc686 152 return fio_sgio_ioctl_doio(td, f, io_u);
2866c82d 153
7a16dd02 154 return fio_sgio_rw_doio(f, io_u, sync);
2866c82d
JA
155}
156
2866c82d
JA
157static 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
cec6b55d 163 if (io_u->xfer_buflen & (sd->bs - 1)) {
2866c82d
JA
164 log_err("read/write not sector aligned\n");
165 return EINVAL;
166 }
167
2866c82d 168 if (io_u->ddir == DDIR_READ) {
87dc1ab1
JA
169 sgio_hdr_init(sd, hdr, io_u, 1);
170
2866c82d
JA
171 hdr->dxfer_direction = SG_DXFER_FROM_DEV;
172 hdr->cmdp[0] = 0x28;
87dc1ab1
JA
173 } else if (io_u->ddir == DDIR_WRITE) {
174 sgio_hdr_init(sd, hdr, io_u, 1);
175
2866c82d
JA
176 hdr->dxfer_direction = SG_DXFER_TO_DEV;
177 hdr->cmdp[0] = 0x2a;
87dc1ab1
JA
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) {
cec6b55d 186 nr_blocks = io_u->xfer_buflen / sd->bs;
87dc1ab1 187 lba = io_u->offset / sd->bs;
1e97cce9
JA
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);
2866c82d
JA
194 }
195
2866c82d
JA
196 return 0;
197}
198
199static 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
87dc1ab1 204 ret = fio_sgio_doio(td, io_u, io_u->ddir == DDIR_SYNC);
2866c82d
JA
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
216static 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
223static 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
254static 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
262static int fio_sgio_init(struct thread_data *td)
263{
53cdc686 264 struct fio_file *f = &td->files[0];
2866c82d
JA
265 struct sgio_data *sd;
266 unsigned int bs;
267 int ret;
268
269 sd = malloc(sizeof(*sd));
cb781c75 270 memset(sd, 0, sizeof(*sd));
2866c82d 271 sd->cmds = malloc(td->iodepth * sizeof(struct sgio_cmd));
cb781c75 272 memset(sd->cmds, 0, td->iodepth * sizeof(struct sgio_cmd));
2866c82d 273 sd->events = malloc(td->iodepth * sizeof(struct io_u *));
cb781c75 274 memset(sd->events, 0, td->iodepth * sizeof(struct io_u *));
2866c82d
JA
275 td->io_ops->data = sd;
276
277 if (td->filetype == FIO_TYPE_BD) {
53cdc686 278 if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
2866c82d 279 td_verror(td, errno);
cb781c75 280 goto err;
2866c82d
JA
281 }
282 } else if (td->filetype == FIO_TYPE_CHAR) {
283 int version;
284
53cdc686 285 if (ioctl(f->fd, SG_GET_VERSION_NUM, &version) < 0) {
2866c82d 286 td_verror(td, errno);
cb781c75 287 goto err;
2866c82d
JA
288 }
289
290 ret = fio_sgio_get_bs(td, &bs);
291 if (ret)
cb781c75 292 goto err;
2866c82d
JA
293 } else {
294 log_err("ioengine sgio only works on block devices\n");
cb781c75 295 goto err;
2866c82d
JA
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;
cb781c75
JA
310err:
311 free(sd->events);
312 free(sd->cmds);
313 free(sd);
e8b8c9f1 314 td->io_ops->data = NULL;
cb781c75 315 return 1;
2866c82d
JA
316}
317
5f350952 318static struct ioengine_ops ioengine = {
2866c82d
JA
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,
b2a15192 327 .flags = FIO_SYNCIO | FIO_RAWIO,
2866c82d 328};
34cfcdaf
JA
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 */
337static int fio_sgio_init(struct thread_data fio_unused *td)
338{
339 fprintf(stderr, "fio: sgio not available\n");
340 return 1;
341}
342
5f350952 343static struct ioengine_ops ioengine = {
34cfcdaf
JA
344 .name = "sgio",
345 .version = FIO_IOOPS_VERSION,
346 .init = fio_sgio_init,
347};
348
349#endif
5f350952
JA
350
351static void fio_init fio_sgio_register(void)
352{
353 register_ioengine(&ioengine);
354}
355
356static void fio_exit fio_sgio_unregister(void)
357{
358 unregister_ioengine(&ioengine);
359}