engines/sg: Make I/O error messages more informative
[fio.git] / engines / sg.c
index 2148e87c190f8c1dfc4f648aecb99796888ca777..c2c0de39ef82903464f728f3e4ea489de993f538 100644 (file)
@@ -8,13 +8,46 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
-#include <assert.h>
-#include <sys/poll.h>
+#include <poll.h>
 
 #include "../fio.h"
+#include "../optgroup.h"
 
 #ifdef FIO_HAVE_SGIO
 
+
+struct sg_options {
+       void *pad;
+       unsigned int readfua;
+       unsigned int writefua;
+};
+
+static struct fio_option options[] = {
+       {
+               .name   = "readfua",
+               .lname  = "sg engine read fua flag support",
+               .type   = FIO_OPT_BOOL,
+               .off1   = offsetof(struct sg_options, readfua),
+               .help   = "Set FUA flag (force unit access) for all Read operations",
+               .def    = "0",
+               .category = FIO_OPT_C_ENGINE,
+               .group  = FIO_OPT_G_SG,
+       },
+       {
+               .name   = "writefua",
+               .lname  = "sg engine write fua flag support",
+               .type   = FIO_OPT_BOOL,
+               .off1   = offsetof(struct sg_options, writefua),
+               .help   = "Set FUA flag (force unit access) for all Write operations",
+               .def    = "0",
+               .category = FIO_OPT_C_ENGINE,
+               .group  = FIO_OPT_G_SG,
+       },
+       {
+               .name   = NULL,
+       },
+};
+
 #define MAX_10B_LBA  0xFFFFFFFFULL
 #define SCSI_TIMEOUT_MS 30000   // 30 second timeout; currently no method to override
 #define MAX_SB 64               // sense block maximum return size
@@ -124,7 +157,7 @@ static int fio_sgio_getevents(struct thread_data *td, unsigned int min,
        }
 
        while (left) {
-               void *p;
+               char *p;
 
                dprint(FD_IO, "sgio_getevents: sd %p: left=%d\n", sd, left);
 
@@ -184,7 +217,7 @@ re_read:
                        if (hdr->info & SG_INFO_CHECK) {
                                struct io_u *io_u;
                                io_u = (struct io_u *)(hdr->usr_ptr);
-                               memcpy((void*)&(io_u->hdr), (void*)hdr, sizeof(struct sg_io_hdr));
+                               memcpy(&io_u->hdr, hdr, sizeof(struct sg_io_hdr));
                                sd->events[i]->error = EIO;
                        }
                }
@@ -254,11 +287,11 @@ static int fio_sgio_doio(struct thread_data *td, struct io_u *io_u, int do_sync)
 
        if (f->filetype == FIO_TYPE_BLOCK) {
                ret = fio_sgio_ioctl_doio(td, f, io_u);
-               td->error = io_u->error;
+               td_verror(td, io_u->error, __func__);
        } else {
                ret = fio_sgio_rw_doio(f, io_u, do_sync);
                if (do_sync)
-                       td->error = io_u->error;
+                       td_verror(td, io_u->error, __func__);
        }
 
        return ret;
@@ -267,6 +300,7 @@ static int fio_sgio_doio(struct thread_data *td, struct io_u *io_u, int do_sync)
 static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u)
 {
        struct sg_io_hdr *hdr = &io_u->hdr;
+       struct sg_options *o = td->eo;
        struct sgio_data *sd = td->io_ops_data;
        long long nr_blocks, lba;
 
@@ -286,6 +320,10 @@ static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u)
                        hdr->cmdp[0] = 0x28; // read(10)
                else
                        hdr->cmdp[0] = 0x88; // read(16)
+
+               if (o->readfua)
+                       hdr->cmdp[1] |= 0x08;
+
        } else if (io_u->ddir == DDIR_WRITE) {
                sgio_hdr_init(sd, hdr, io_u, 1);
 
@@ -294,6 +332,10 @@ static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u)
                        hdr->cmdp[0] = 0x2a; // write(10)
                else
                        hdr->cmdp[0] = 0x8a; // write(16)
+
+               if (o->writefua)
+                       hdr->cmdp[1] |= 0x08;
+
        } else {
                sgio_hdr_init(sd, hdr, io_u, 0);
                hdr->dxfer_direction = SG_DXFER_NONE;
@@ -413,8 +455,10 @@ static int fio_sgio_read_capacity(struct thread_data *td, unsigned int *bs,
                return ret;
        }
 
-       *bs      = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
-       *max_lba = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]) & MAX_10B_LBA;  // for some reason max_lba is being sign extended even though unsigned.
+       *bs      = ((unsigned long) buf[4] << 24) | ((unsigned long) buf[5] << 16) |
+                  ((unsigned long) buf[6] << 8) | (unsigned long) buf[7];
+       *max_lba = ((unsigned long) buf[0] << 24) | ((unsigned long) buf[1] << 16) |
+                  ((unsigned long) buf[2] << 8) | (unsigned long) buf[3];
 
        /*
         * If max lba masked by MAX_10B_LBA equals MAX_10B_LBA,
@@ -572,17 +616,17 @@ static char *fio_sgio_errdetails(struct io_u *io_u)
        struct sg_io_hdr *hdr = &io_u->hdr;
 #define MAXERRDETAIL 1024
 #define MAXMSGCHUNK  128
-       char *msg, msgchunk[MAXMSGCHUNK], *ret = NULL;
+       char *msg, msgchunk[MAXMSGCHUNK];
        int i;
 
        msg = calloc(1, MAXERRDETAIL);
+       strcpy(msg, "");
 
        /*
         * can't seem to find sg_err.h, so I'll just echo the define values
         * so others can search on internet to find clearer clues of meaning.
         */
        if (hdr->info & SG_INFO_CHECK) {
-               ret = msg;
                if (hdr->host_status) {
                        snprintf(msgchunk, MAXMSGCHUNK, "SG Host Status: 0x%02x; ", hdr->host_status);
                        strlcat(msg, msgchunk, MAXERRDETAIL);
@@ -755,14 +799,14 @@ static char *fio_sgio_errdetails(struct io_u *io_u)
                if (hdr->resid != 0) {
                        snprintf(msgchunk, MAXMSGCHUNK, "SG Driver: %d bytes out of %d not transferred. ", hdr->resid, hdr->dxfer_len);
                        strlcat(msg, msgchunk, MAXERRDETAIL);
-                       ret = msg;
                }
        }
 
-       if (!ret)
-               ret = strdup("SG Driver did not report a Host, Driver or Device check");
+       if (!(hdr->info & SG_INFO_CHECK) && !strlen(msg))
+               strncpy(msg, "SG Driver did not report a Host, Driver or Device check",
+                       MAXERRDETAIL - 1);
 
-       return ret;
+       return msg;
 }
 
 /*
@@ -822,6 +866,8 @@ static struct ioengine_ops ioengine = {
        .close_file     = generic_close_file,
        .get_file_size  = fio_sgio_get_file_size,
        .flags          = FIO_SYNCIO | FIO_RAWIO,
+       .options        = options,
+       .option_struct_size     = sizeof(struct sg_options)
 };
 
 #else /* FIO_HAVE_SGIO */