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