engines/sg: add support for WRITE AND VERIFY, WRITE SAME
authorVincent Fu <vincent.fu@wdc.com>
Wed, 16 May 2018 23:17:47 +0000 (19:17 -0400)
committerVincent Fu <vincent.fu@wdc.com>
Fri, 18 May 2018 17:49:23 +0000 (13:49 -0400)
Add an sg ioengine option to treat write IO as either WRITE AND VERIFY
or WRITE SAME commands

The new ioengine option sg_write_mode can take 3 values:

write (default)
  WRITE opcodes are issued as usual
verify
  WRITE AND VERIFY opcodes are issued
same
  WRITE SAME opcodes are issued

WRITE AND VERIFY opcodes are issued with the BYTCHK bit set to 0. This
directs the device to carry out a medium verification with no data
comparison.

WRITE SAME transfers a single block of data to the device and writes
this same block of data to a contiguous sequence of LBAs beginning at
the specified offset.

fio's block size parameter specifies the amount of data written with
each command. However, the amount of data actually transferred to the
device is equal to the device's block (sector) size. For a device with
512 byte sectors, blocksize=8k will write 16 sectors with each command.
fio will still generate 8k of data for each command but only the first
512 bytes will be used and transferred to the device.

engines/sg.c

index d4848bc..06cd194 100644 (file)
 
 #ifdef FIO_HAVE_SGIO
 
+enum {
+       FIO_SG_WRITE            = 1,
+       FIO_SG_WRITE_VERIFY     = 2,
+       FIO_SG_WRITE_SAME       = 3
+};
 
 struct sg_options {
        void *pad;
        unsigned int readfua;
        unsigned int writefua;
+       unsigned int write_mode;
 };
 
 static struct fio_option options[] = {
@@ -43,6 +49,30 @@ static struct fio_option options[] = {
                .category = FIO_OPT_C_ENGINE,
                .group  = FIO_OPT_G_SG,
        },
+       {
+               .name   = "sg_write_mode",
+               .lname  = "specify sg write mode",
+               .type   = FIO_OPT_STR,
+               .off1   = offsetof(struct sg_options, write_mode),
+               .help   = "Specify SCSI WRITE mode",
+               .def    = "write",
+               .posval = {
+                         { .ival = "write",
+                           .oval = FIO_SG_WRITE,
+                           .help = "Issue standard SCSI WRITE commands",
+                         },
+                         { .ival = "verify",
+                           .oval = FIO_SG_WRITE_VERIFY,
+                           .help = "Issue SCSI WRITE AND VERIFY commands",
+                         },
+                         { .ival = "same",
+                           .oval = FIO_SG_WRITE_SAME,
+                           .help = "Issue SCSI WRITE SAME commands",
+                         },
+               },
+               .category = FIO_OPT_C_ENGINE,
+               .group  = FIO_OPT_G_SG,
+       },
        {
                .name   = NULL,
        },
@@ -329,14 +359,30 @@ static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u)
                sgio_hdr_init(sd, hdr, io_u, 1);
 
                hdr->dxfer_direction = SG_DXFER_TO_DEV;
-               if (lba < MAX_10B_LBA)
-                       hdr->cmdp[0] = 0x2a; // write(10)
-               else
-                       hdr->cmdp[0] = 0x8a; // write(16)
-
-               if (o->writefua)
-                       hdr->cmdp[1] |= 0x08;
-
+               switch(o->write_mode) {
+               case FIO_SG_WRITE:
+                       if (lba < MAX_10B_LBA)
+                               hdr->cmdp[0] = 0x2a; // write(10)
+                       else
+                               hdr->cmdp[0] = 0x8a; // write(16)
+                       if (o->writefua)
+                               hdr->cmdp[1] |= 0x08;
+                       break;
+               case FIO_SG_WRITE_VERIFY:
+                       if (lba < MAX_10B_LBA)
+                               hdr->cmdp[0] = 0x2e; // write and verify(10)
+                       else
+                               hdr->cmdp[0] = 0x8e; // write and verify(16)
+                       break;
+                       // BYTCHK is disabled by virtue of the memset in sgio_hdr_init
+               case FIO_SG_WRITE_SAME:
+                       hdr->dxfer_len = sd->bs;
+                       if (lba < MAX_10B_LBA)
+                               hdr->cmdp[0] = 0x41; // write same(10)
+                       else
+                               hdr->cmdp[0] = 0x93; // write same(16)
+                       break;
+               };
        } else {
                sgio_hdr_init(sd, hdr, io_u, 0);
                hdr->dxfer_direction = SG_DXFER_NONE;