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