1 /* 2 * sg engine 3 * 4 * IO engine that uses the Linux SG v3 interface to talk to SCSI devices 5 * 6 */ 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <unistd.h> 10 #include <errno.h> 11 #include <assert.h> 12 #include <sys/poll.h> 13 14 #include "../fio.h" 15 16 #ifdef FIO_HAVE_SGIO 17 18 struct sgio_cmd { 19 unsigned char cdb[10]; 20 int nr; 21 }; 22 23 struct sgio_data { 24 struct sgio_cmd *cmds; 25 struct io_u **events; 26 struct pollfd *pfds; 27 int *fd_flags; 28 void *sgbuf; 29 unsigned int bs; 30 int type_checked; 31 }; 32 33 static void sgio_hdr_init(struct sgio_data *sd, struct sg_io_hdr *hdr, 34 struct io_u *io_u, int fs) 35 { 36 struct sgio_cmd *sc = &sd->cmds[io_u->index]; 37 38 memset(hdr, 0, sizeof(*hdr)); 39 memset(sc->cdb, 0, sizeof(sc->cdb)); 40 41 hdr->interface_id = 'S'; 42 hdr->cmdp = sc->cdb; 43 hdr->cmd_len = sizeof(sc->cdb); 44 hdr->pack_id = io_u->index; 45 hdr->usr_ptr = io_u; 46 47 if (fs) { 48 hdr->dxferp = io_u->xfer_buf; 49 hdr->dxfer_len = io_u->xfer_buflen; 50 } 51 } 52 53 static int pollin_events(struct pollfd *pfds, int fds) 54 { 55 int i; 56 57 for (i = 0; i < fds; i++) 58 if (pfds[i].revents & POLLIN) 59 return 1; 60 61 return 0; 62 } 63 64 static int fio_sgio_getevents(struct thread_data *td, unsigned int min, 65 unsigned int max, 66 const struct timespec fio_unused *t) 67 { 68 struct sgio_data *sd = td->io_ops->data; 69 int left = max, ret, r = 0; 70 void *buf = sd->sgbuf; 71 unsigned int i, events; 72 struct fio_file *f; 73 74 /* 75 * Fill in the file descriptors 76 */ 77 for_each_file(td, f, i) { 78 /* 79 * don't block for min events == 0 80 */ 81 if (!min) 82 sd->fd_flags[i] = fio_set_fd_nonblocking(f->fd, "sg"); 83 else 84 sd->fd_flags[i] = -1; 85 86 sd->pfds[i].fd = f->fd; 87 sd->pfds[i].events = POLLIN; 88 } 89 90 while (left) { 91 void *p; 92 93 do { 94 if (!min) 95 break; 96 97 ret = poll(sd->pfds, td->o.nr_files, -1); 98 if (ret < 0) { 99 if (!r) 100 r = -errno; 101 td_verror(td, errno, "poll"); 102 break; 103 } else if (!ret) 104 continue; 105 106 if (pollin_events(sd->pfds, td->o.nr_files)) 107 break; 108 } while (1); 109 110 if (r < 0) 111 break; 112 113 re_read: 114 p = buf; 115 events = 0; 116 for_each_file(td, f, i) { 117 ret = read(f->fd, p, left * sizeof(struct sg_io_hdr)); 118 if (ret < 0) { 119 if (errno == EAGAIN) 120 continue; 121 r = -errno; 122 td_verror(td, errno, "read"); 123 break; 124 } else if (ret) { 125 p += ret; 126 events += ret / sizeof(struct sg_io_hdr); 127 } 128 } 129 130 if (r < 0) 131 break; 132 if (!events) { 133 usleep(1000); 134 goto re_read; 135 } 136 137 left -= events; 138 r += events; 139 140 for (i = 0; i < events; i++) { 141 struct sg_io_hdr *hdr = (struct sg_io_hdr *) buf + i; 142 143 sd->events[i] = hdr->usr_ptr; 144 } 145 } 146 147 if (!min) { 148 for_each_file(td, f, i) { 149 if (sd->fd_flags[i] == -1) 150 continue; 151 152 if (fcntl(f->fd, F_SETFL, sd->fd_flags[i]) < 0) 153 log_err("fio: sg failed to restore fcntl flags: %s\n", strerror(errno)); 154 } 155 } 156 157 return r; 158 } 159 160 static int fio_sgio_ioctl_doio(struct thread_data *td, 161 struct fio_file *f, struct io_u *io_u) 162 { 163 struct sgio_data *sd = td->io_ops->data; 164 struct sg_io_hdr *hdr = &io_u->hdr; 165 int ret; 166 167 sd->events[0] = io_u; 168 169 ret = ioctl(f->fd, SG_IO, hdr); 170 if (ret < 0) 171 return ret; 172 173 return FIO_Q_COMPLETED; 174 } 175 176 static int fio_sgio_rw_doio(struct fio_file *f, struct io_u *io_u, int do_sync) 177 { 178 struct sg_io_hdr *hdr = &io_u->hdr; 179 int ret; 180 181 ret = write(f->fd, hdr, sizeof(*hdr)); 182 if (ret < 0) 183 return ret; 184 185 if (do_sync) { 186 ret = read(f->fd, hdr, sizeof(*hdr)); 187 if (ret < 0) 188 return ret; 189 return FIO_Q_COMPLETED; 190 } 191 192 return FIO_Q_QUEUED; 193 } 194 195 static int fio_sgio_doio(struct thread_data *td, struct io_u *io_u, int do_sync) 196 { 197 struct fio_file *f = io_u->file; 198 199 if (f->filetype == FIO_TYPE_BD) 200 return fio_sgio_ioctl_doio(td, f, io_u); 201 202 return fio_sgio_rw_doio(f, io_u, do_sync); 203 } 204 205 static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u) 206 { 207 struct sg_io_hdr *hdr = &io_u->hdr; 208 struct sgio_data *sd = td->io_ops->data; 209 int nr_blocks, lba; 210 211 if (io_u->xfer_buflen & (sd->bs - 1)) { 212 log_err("read/write not sector aligned\n"); 213 return EINVAL; 214 } 215 216 if (io_u->ddir == DDIR_READ) { 217 sgio_hdr_init(sd, hdr, io_u, 1); 218 219 hdr->dxfer_direction = SG_DXFER_FROM_DEV; 220 hdr->cmdp[0] = 0x28; 221 } else if (io_u->ddir == DDIR_WRITE) { 222 sgio_hdr_init(sd, hdr, io_u, 1); 223 224 hdr->dxfer_direction = SG_DXFER_TO_DEV; 225 hdr->cmdp[0] = 0x2a; 226 } else { 227 sgio_hdr_init(sd, hdr, io_u, 0); 228 229 hdr->dxfer_direction = SG_DXFER_NONE; 230 hdr->cmdp[0] = 0x35; 231 } 232 233 if (hdr->dxfer_direction != SG_DXFER_NONE) { 234 nr_blocks = io_u->xfer_buflen / sd->bs; 235 lba = io_u->offset / sd->bs; 236 hdr->cmdp[2] = (unsigned char) ((lba >> 24) & 0xff); 237 hdr->cmdp[3] = (unsigned char) ((lba >> 16) & 0xff); 238 hdr->cmdp[4] = (unsigned char) ((lba >> 8) & 0xff); 239 hdr->cmdp[5] = (unsigned char) (lba & 0xff); 240 hdr->cmdp[7] = (unsigned char) ((nr_blocks >> 8) & 0xff); 241 hdr->cmdp[8] = (unsigned char) (nr_blocks & 0xff); 242 } 243 244 return 0; 245 } 246 247 static int fio_sgio_queue(struct thread_data *td, struct io_u *io_u) 248 { 249 struct sg_io_hdr *hdr = &io_u->hdr; 250 int ret, do_sync = 0; 251 252 fio_ro_check(td, io_u); 253 254 if (td->o.sync_io || td->o.odirect || ddir_sync(io_u->ddir)) 255 do_sync = 1; 256 257 ret = fio_sgio_doio(td, io_u, do_sync); 258 259 if (ret < 0) 260 io_u->error = errno; 261 else if (hdr->status) { 262 io_u->resid = hdr->resid; 263 io_u->error = EIO; 264 } 265 266 if (io_u->error) { 267 td_verror(td, io_u->error, "xfer"); 268 return FIO_Q_COMPLETED; 269 } 270 271 return ret; 272 } 273 274 static struct io_u *fio_sgio_event(struct thread_data *td, int event) 275 { 276 struct sgio_data *sd = td->io_ops->data; 277 278 return sd->events[event]; 279 } 280 281 static int fio_sgio_get_bs(struct thread_data *td, unsigned int *bs) 282 { 283 struct sgio_data *sd = td->io_ops->data; 284 struct io_u io_u; 285 struct sg_io_hdr *hdr; 286 unsigned char buf[8]; 287 int ret; 288 289 memset(&io_u, 0, sizeof(io_u)); 290 io_u.file = td->files[0]; 291 292 hdr = &io_u.hdr; 293 sgio_hdr_init(sd, hdr, &io_u, 0); 294 memset(buf, 0, sizeof(buf)); 295 296 hdr->cmdp[0] = 0x25; 297 hdr->dxfer_direction = SG_DXFER_FROM_DEV; 298 hdr->dxferp = buf; 299 hdr->dxfer_len = sizeof(buf); 300 301 ret = fio_sgio_doio(td, &io_u, 1); 302 if (ret) 303 return ret; 304 305 *bs = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; 306 return 0; 307 } 308 309 static void fio_sgio_cleanup(struct thread_data *td) 310 { 311 struct sgio_data *sd = td->io_ops->data; 312 313 if (sd) { 314 free(sd->events); 315 free(sd->cmds); 316 free(sd->fd_flags); 317 free(sd->pfds); 318 free(sd->sgbuf); 319 free(sd); 320 } 321 } 322 323 static int fio_sgio_init(struct thread_data *td) 324 { 325 struct sgio_data *sd; 326 327 sd = malloc(sizeof(*sd)); 328 memset(sd, 0, sizeof(*sd)); 329 sd->cmds = malloc(td->o.iodepth * sizeof(struct sgio_cmd)); 330 memset(sd->cmds, 0, td->o.iodepth * sizeof(struct sgio_cmd)); 331 sd->events = malloc(td->o.iodepth * sizeof(struct io_u *)); 332 memset(sd->events, 0, td->o.iodepth * sizeof(struct io_u *)); 333 sd->pfds = malloc(sizeof(struct pollfd) * td->o.nr_files); 334 memset(sd->pfds, 0, sizeof(struct pollfd) * td->o.nr_files); 335 sd->fd_flags = malloc(sizeof(int) * td->o.nr_files); 336 memset(sd->fd_flags, 0, sizeof(int) * td->o.nr_files); 337 sd->sgbuf = malloc(sizeof(struct sg_io_hdr) * td->o.iodepth); 338 memset(sd->sgbuf, 0, sizeof(struct sg_io_hdr) * td->o.iodepth); 339 340 td->io_ops->data = sd; 341 342 /* 343 * we want to do it, regardless of whether odirect is set or not 344 */ 345 td->o.override_sync = 1; 346 return 0; 347 } 348 349 static int fio_sgio_type_check(struct thread_data *td, struct fio_file *f) 350 { 351 struct sgio_data *sd = td->io_ops->data; 352 unsigned int bs; 353 354 if (f->filetype == FIO_TYPE_BD) { 355 if (ioctl(f->fd, BLKSSZGET, &bs) < 0) { 356 td_verror(td, errno, "ioctl"); 357 return 1; 358 } 359 } else if (f->filetype == FIO_TYPE_CHAR) { 360 int version, ret; 361 362 if (ioctl(f->fd, SG_GET_VERSION_NUM, &version) < 0) { 363 td_verror(td, errno, "ioctl"); 364 return 1; 365 } 366 367 ret = fio_sgio_get_bs(td, &bs); 368 if (ret) 369 return 1; 370 } else { 371 log_err("ioengine sg only works on block devices\n"); 372 return 1; 373 } 374 375 sd->bs = bs; 376 377 if (f->filetype == FIO_TYPE_BD) { 378 td->io_ops->getevents = NULL; 379 td->io_ops->event = NULL; 380 } 381 382 return 0; 383 } 384 385 static int fio_sgio_open(struct thread_data *td, struct fio_file *f) 386 { 387 struct sgio_data *sd = td->io_ops->data; 388 int ret; 389 390 ret = generic_open_file(td, f); 391 if (ret) 392 return ret; 393 394 if (sd && !sd->type_checked && fio_sgio_type_check(td, f)) { 395 ret = generic_close_file(td, f); 396 return 1; 397 } 398 399 return 0; 400 } 401 402 static struct ioengine_ops ioengine = { 403 .name = "sg", 404 .version = FIO_IOOPS_VERSION, 405 .init = fio_sgio_init, 406 .prep = fio_sgio_prep, 407 .queue = fio_sgio_queue, 408 .getevents = fio_sgio_getevents, 409 .event = fio_sgio_event, 410 .cleanup = fio_sgio_cleanup, 411 .open_file = fio_sgio_open, 412 .close_file = generic_close_file, 413 .get_file_size = generic_get_file_size, 414 .flags = FIO_SYNCIO | FIO_RAWIO, 415 }; 416 417 #else /* FIO_HAVE_SGIO */ 418 419 /* 420 * When we have a proper configure system in place, we simply wont build 421 * and install this io engine. For now install a crippled version that 422 * just complains and fails to load. 423 */ 424 static int fio_sgio_init(struct thread_data fio_unused *td) 425 { 426 log_err("fio: ioengine sg not available\n"); 427 return 1; 428 } 429 430 static struct ioengine_ops ioengine = { 431 .name = "sg", 432 .version = FIO_IOOPS_VERSION, 433 .init = fio_sgio_init, 434 }; 435 436 #endif 437 438 static void fio_init fio_sgio_register(void) 439 { 440 register_ioengine(&ioengine); 441 } 442 443 static void fio_exit fio_sgio_unregister(void) 444 { 445 unregister_ioengine(&ioengine); 446 } 447