ignore documentation output directory
[fio.git] / engines / sg.c
index c24b323fc5d609bcf984dc1095f98a75f71e6161..3f7d9110e71fdff6740869f9cd956f020dc72fb2 100644 (file)
@@ -20,7 +20,7 @@
 #define MAX_SB 64               // sense block maximum return size
 
 struct sgio_cmd {
-       unsigned char cdb[16];          // increase to support 16 byte commands
+       unsigned char cdb[16];      // enhanced from 10 to support 16 byte commands
        unsigned char sb[MAX_SB];   // add sense block to commands
        int nr;
 };
@@ -32,7 +32,6 @@ struct sgio_data {
        int *fd_flags;
        void *sgbuf;
        unsigned int bs;
-       long long max_lba;
        int type_checked;
 };
 
@@ -69,11 +68,40 @@ static int pollin_events(struct pollfd *pfds, int fds)
        return 0;
 }
 
+static int sg_fd_read(int fd, void *data, size_t size)
+{
+       int err = 0;
+
+       while (size) {
+               ssize_t ret;
+
+               ret = read(fd, data, size);
+               if (ret < 0) {
+                       if (errno == EAGAIN || errno == EINTR)
+                               continue;
+                       err = errno;
+                       break;
+               } else if (!ret)
+                       break;
+               else {
+                       data += ret;
+                       size -= ret;
+               }
+       }
+
+       if (err)
+               return err;
+       if (size)
+               return EAGAIN;
+
+       return 0;
+}
+
 static int fio_sgio_getevents(struct thread_data *td, unsigned int min,
                              unsigned int max,
                              const struct timespec fio_unused *t)
 {
-       struct sgio_data *sd = td->io_ops->data;
+       struct sgio_data *sd = td->io_ops_data;
        int left = max, eventNum, ret, r = 0;
        void *buf = sd->sgbuf;
        unsigned int i, events;
@@ -125,27 +153,20 @@ re_read:
                events = 0;
                for_each_file(td, f, i) {
                        for (eventNum = 0; eventNum < left; eventNum++) {
-                               ret = read(f->fd, p, sizeof(struct sg_io_hdr));
+                               ret = sg_fd_read(f->fd, p, sizeof(struct sg_io_hdr));
                                dprint(FD_IO, "sgio_getevents: ret: %d\n", ret);
-                               if (ret < 0) {
-                                       /*
-                                        *  not sure if EINTR is needed,
-                                        *  but seems like it should be.
-                                        */
-                                       if (errno == EAGAIN || errno == EINTR)
-                                               continue;
-                                       r = -errno;
-                                       td_verror(td, errno, "read");
+                               if (ret) {
+                                       r = -ret;
+                                       td_verror(td, r, "sg_read");
                                        break;
-                               } else if (ret) {
-                                       p += ret;
-                                       events += 1;  /* ret / sizeof(struct sg_io_hdr); */
-                                       dprint(FD_IO, "sgio_getevents: events: %d\n", events);
                                }
+                               p += sizeof(struct sg_io_hdr);
+                               events++;
+                               dprint(FD_IO, "sgio_getevents: events: %d\n", events);
                        }
                }
 
-               if (r < 0)
+               if (r < 0 && !events)
                        break;
                if (!events) {
                        usleep(1000);
@@ -185,7 +206,7 @@ re_read:
 static int fio_sgio_ioctl_doio(struct thread_data *td,
                               struct fio_file *f, struct io_u *io_u)
 {
-       struct sgio_data *sd = td->io_ops->data;
+       struct sgio_data *sd = td->io_ops_data;
        struct sg_io_hdr *hdr = &io_u->hdr;
        int ret;
 
@@ -246,7 +267,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 sgio_data *sd = td->io_ops->data;
+       struct sgio_data *sd = td->io_ops_data;
        long long nr_blocks, lba;
 
        if (io_u->xfer_buflen & (sd->bs - 1)) {
@@ -287,7 +308,6 @@ static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u)
         * blocks on medium.
         */
        if (hdr->dxfer_direction != SG_DXFER_NONE) {
-
                if (lba < MAX_10B_LBA) {
                        hdr->cmdp[2] = (unsigned char) ((lba >> 24) & 0xff);
                        hdr->cmdp[3] = (unsigned char) ((lba >> 16) & 0xff);
@@ -344,7 +364,7 @@ static int fio_sgio_queue(struct thread_data *td, struct io_u *io_u)
 
 static struct io_u *fio_sgio_event(struct thread_data *td, int event)
 {
-       struct sgio_data *sd = td->io_ops->data;
+       struct sgio_data *sd = td->io_ops_data;
 
        return sd->events[event];
 }
@@ -394,17 +414,16 @@ static int fio_sgio_read_capacity(struct thread_data *td, unsigned int *bs,
        }
 
        *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]) & 0x00000000FFFFFFFFULL;  // for some reason max_lba is being sign extended even though unsigned.
-
+       *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.
 
        /*
-        * If max lba is 0xFFFFFFFF, then need to retry with
-        * 16 byteread capacity
+        * If max lba masked by MAX_10B_LBA equals MAX_10B_LBA,
+        * then need to retry with 16 byte Read Capacity command.
         */
        if (*max_lba == MAX_10B_LBA) {
                hdr.cmd_len = 16;
-               hdr.cmdp[0] = 0x9e; // Read Capacity(16)
-               hdr.cmdp[1] = 0x10; // service action
+               hdr.cmdp[0] = 0x9e; // service action
+               hdr.cmdp[1] = 0x10; // Read Capacity(16)
                hdr.cmdp[10] = (unsigned char) ((sizeof(buf) >> 24) & 0xff);
                hdr.cmdp[11] = (unsigned char) ((sizeof(buf) >> 16) & 0xff);
                hdr.cmdp[12] = (unsigned char) ((sizeof(buf) >> 8) & 0xff);
@@ -441,7 +460,7 @@ static int fio_sgio_read_capacity(struct thread_data *td, unsigned int *bs,
 
 static void fio_sgio_cleanup(struct thread_data *td)
 {
-       struct sgio_data *sd = td->io_ops->data;
+       struct sgio_data *sd = td->io_ops_data;
 
        if (sd) {
                free(sd->events);
@@ -470,7 +489,7 @@ static int fio_sgio_init(struct thread_data *td)
        sd->sgbuf = malloc(sizeof(struct sg_io_hdr) * td->o.iodepth);
        memset(sd->sgbuf, 0, sizeof(struct sg_io_hdr) * td->o.iodepth);
        sd->type_checked = 0;
-       td->io_ops->data = sd;
+       td->io_ops_data = sd;
 
        /*
         * we want to do it, regardless of whether odirect is set or not
@@ -481,11 +500,10 @@ static int fio_sgio_init(struct thread_data *td)
 
 static int fio_sgio_type_check(struct thread_data *td, struct fio_file *f)
 {
-       struct sgio_data *sd = td->io_ops->data;
+       struct sgio_data *sd = td->io_ops_data;
        unsigned int bs = 0;
        unsigned long long max_lba = 0;
 
-
        if (f->filetype == FIO_TYPE_BD) {
                if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
                        td_verror(td, errno, "ioctl");
@@ -507,18 +525,18 @@ static int fio_sgio_type_check(struct thread_data *td, struct fio_file *f)
                }
        } else {
                td_verror(td, EINVAL, "wrong file type");
-               log_err("ioengine sg only works on block devices\n");
+               log_err("ioengine sg only works on block or character devices\n");
                return 1;
        }
 
        sd->bs = bs;
        // Determine size of commands needed based on max_lba
-       sd->max_lba = max_lba;
-       if (max_lba > MAX_10B_LBA) {
-               dprint(FD_IO, "sgio_type_check: using 16 byte operations: max_lba = 0x%016llx\n", max_lba);
+       if (max_lba >= MAX_10B_LBA) {
+               dprint(FD_IO, "sgio_type_check: using 16 byte read/write "
+                       "commands for lba above 0x%016llx/0x%016llx\n",
+                       MAX_10B_LBA, max_lba);
        }
 
-
        if (f->filetype == FIO_TYPE_BD) {
                td->io_ops->getevents = NULL;
                td->io_ops->event = NULL;
@@ -530,7 +548,7 @@ static int fio_sgio_type_check(struct thread_data *td, struct fio_file *f)
 
 static int fio_sgio_open(struct thread_data *td, struct fio_file *f)
 {
-       struct sgio_data *sd = td->io_ops->data;
+       struct sgio_data *sd = td->io_ops_data;
        int ret;
 
        ret = generic_open_file(td, f);
@@ -557,7 +575,7 @@ static char *fio_sgio_errdetails(struct io_u *io_u)
        char *msg, msgchunk[MAXMSGCHUNK], *ret = NULL;
        int i;
 
-       msg = calloc(MAXERRDETAIL, 1);
+       msg = calloc(1, MAXERRDETAIL);
 
        /*
         * can't seem to find sg_err.h, so I'll just echo the define values
@@ -608,6 +626,24 @@ static char *fio_sgio_errdetails(struct io_u *io_u)
                        case 0x0d:
                                strlcat(msg, "SG_ERR_DID_REQUEUE", MAXERRDETAIL);
                                break;
+                       case 0x0e:
+                               strlcat(msg, "SG_ERR_DID_TRANSPORT_DISRUPTED", MAXERRDETAIL);
+                               break;
+                       case 0x0f:
+                               strlcat(msg, "SG_ERR_DID_TRANSPORT_FAILFAST", MAXERRDETAIL);
+                               break;
+                       case 0x10:
+                               strlcat(msg, "SG_ERR_DID_TARGET_FAILURE", MAXERRDETAIL);
+                               break;
+                       case 0x11:
+                               strlcat(msg, "SG_ERR_DID_NEXUS_FAILURE", MAXERRDETAIL);
+                               break;
+                       case 0x12:
+                               strlcat(msg, "SG_ERR_DID_ALLOC_FAILURE", MAXERRDETAIL);
+                               break;
+                       case 0x13:
+                               strlcat(msg, "SG_ERR_DID_MEDIUM_ERROR", MAXERRDETAIL);
+                               break;
                        default:
                                strlcat(msg, "Unknown", MAXERRDETAIL);
                                break;
@@ -753,6 +789,12 @@ static int fio_sgio_get_file_size(struct thread_data *td, struct fio_file *f)
        if (fio_file_size_known(f))
                return 0;
 
+       if (f->filetype != FIO_TYPE_BD && f->filetype != FIO_TYPE_CHAR) {
+               td_verror(td, EINVAL, "wrong file type");
+               log_err("ioengine sg only works on block or character devices\n");
+               return 1;
+       }
+
        ret = fio_sgio_read_capacity(td, &bs, &max_lba);
        if (ret ) {
                td_verror(td, td->error, "fio_sgio_read_capacity");
@@ -778,7 +820,7 @@ static struct ioengine_ops ioengine = {
        .cleanup        = fio_sgio_cleanup,
        .open_file      = fio_sgio_open,
        .close_file     = generic_close_file,
-       .get_file_size  = fio_sgio_get_file_size, // generic_get_file_size
+       .get_file_size  = fio_sgio_get_file_size,
        .flags          = FIO_SYNCIO | FIO_RAWIO,
 };