implement WRITE10
authorroot <root@rcn1.VSOFS1.COM>
Wed, 22 Jul 2009 02:17:15 +0000 (12:17 +1000)
committerroot <root@rcn1.VSOFS1.COM>
Wed, 22 Jul 2009 02:17:15 +0000 (12:17 +1000)
also make sure the lba is wrapped if it points to something larget than the device so that loadfiles will not fail when used against a smaller device

dbench.c
dbench.h
linux_scsi.c
loadfiles/scsi.txt

index 725deb7..acc4d27 100644 (file)
--- a/dbench.c
+++ b/dbench.c
@@ -45,6 +45,7 @@ struct options options = {
        .export              = "/tmp",
        .protocol            = "tcp",
        .run_once            = 0,
+       .allow_scsi_writes   = 0,
        .trunc_io            = 0,
 };
 
@@ -393,6 +394,8 @@ static void process_opts(int argc, const char **argv)
                  "Stop once reaching the end of the loadfile", NULL},
                { "scsi",  0, POPT_ARG_STRING, &options.scsi_dev, 0, 
                  "scsi device", NULL },
+               { "allow-scsi-writes", 0, POPT_ARG_NONE, &options.allow_scsi_writes, 0,
+                 "Allow SCSI write command to the device", NULL},
                { "warmup", 0, POPT_ARG_INT, &options.warmup, 0, 
                  "How meny seconds of warmup to run", NULL },
                POPT_TABLEEND
index c5d62b2..4de5251 100644 (file)
--- a/dbench.h
+++ b/dbench.h
@@ -151,6 +151,7 @@ struct options {
        const char *export;
        const char *protocol;
        int run_once;
+       int allow_scsi_writes;
        int trunc_io;
        const char *scsi_dev;
 };
index 8fcc4af..b2e1b7a 100644 (file)
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <scsi/sg.h>
+#include <stdint.h>
 
 #define SCSI_TIMEOUT 5000 /* ms */
 
 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
 
 struct scsi_device {
-       int fd;
+       int fd;
+       uint32_t blocks;
 };
 
+static int check_sense(unsigned char sc, const char *expected);
+static int scsi_io(int fd, unsigned char *cdb, unsigned char cdb_size, int xfer_dir, unsigned int *data_size, char *data, unsigned char *sc);
+
+static void num_device_blocks(struct scsi_device *sd)
+{
+       unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
+       int res;
+       unsigned int data_size=8;
+       char data[data_size];
+       unsigned char sc;
+
+       res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
+       if(res){
+               printf("SCSI_IO failed when reading disk capacity\n");
+               exit(10);
+       }
+       if (!check_sense(sc, "0x00")) {
+               printf("READCAPACITY10 failed (0x%02x) - expected 0x00\n", sc);
+               exit(10);
+       }
+
+       sd->blocks = (0xff & data[0]);
+       sd->blocks = (sd->blocks<<8) | (0xff & data[1]);
+       sd->blocks = (sd->blocks<<8) | (0xff & data[2]);
+       sd->blocks = (sd->blocks<<8) | (0xff & data[3]);
+
+       sd->blocks++;
+}
+
 static void scsi_setup(struct child_struct *child)
 {
        int vers;
@@ -48,7 +79,7 @@ static void scsi_setup(struct child_struct *child)
        child->private=sd;
        if((sd->fd=open(options.scsi_dev, O_RDWR))<0){
                printf("Failed to open scsi device node : %s\n", options.scsi_dev);
-               free(sd);
+               free(sd);
                exit(10);
        }
        if ((ioctl(sd->fd, SG_GET_VERSION_NUM, &vers) < 0) || (vers < 30000)) {
@@ -57,6 +88,9 @@ static void scsi_setup(struct child_struct *child)
                free(sd);
                exit(10);
        }
+
+       /* read disk capacity */
+       num_device_blocks(sd);
 }
 
 static void scsi_cleanup(struct child_struct *child)
@@ -182,15 +216,30 @@ static void scsi_testunitready(struct dbench_op *op)
 
 static void scsi_read6(struct dbench_op *op)
 {
-       struct scsi_device *sd;
+       struct scsi_device *sd=op->child->private;
        unsigned char cdb[]={0x08,0,0,0,0,0};
        int res;
-       int lba = op->params[0];
-       int xferlen = op->params[1];
+       uint32_t lba = op->params[0];
+       uint32_t xferlen = op->params[1];
        unsigned int data_size=1024*1024;
        char data[data_size];
        unsigned char sc;
 
+       /* we only have 24 bit addresses in read 6 */
+       if (lba > 0x00ffffff) {
+               lba &= 0x00ffffff;
+       }
+
+       /* make sure we wrap properly instead of failing if the loadfile
+          is bigger than our device
+       */
+       if (sd->blocks <= lba) {
+               lba = lba%sd->blocks;
+       }
+       if (sd->blocks <= lba+xferlen) {
+               xferlen=1;
+       }
+
        cdb[1] = (lba>>16)&0x1f;
        cdb[2] = (lba>> 8)&0xff;
        cdb[3] = (lba    )&0xff;
@@ -198,8 +247,6 @@ static void scsi_read6(struct dbench_op *op)
        cdb[4] = xferlen&0xff;
        data_size = xferlen*512;
 
-       sd = op->child->private;
-
        res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
        if(res){
                printf("SCSI_IO failed\n");
@@ -216,17 +263,27 @@ static void scsi_read6(struct dbench_op *op)
 
 static void scsi_read10(struct dbench_op *op)
 {
-       struct scsi_device *sd;
+       struct scsi_device *sd=op->child->private;
        unsigned char cdb[]={0x28,0,0,0,0,0,0,0,0,0};
        int res;
-       int lba = op->params[0];
-       int xferlen = op->params[1];
+       uint32_t lba = op->params[0];
+       uint32_t xferlen = op->params[1];
        int rd = op->params[2];
        int grp = op->params[3];
        unsigned int data_size=1024*1024;
        char data[data_size];
        unsigned char sc;
 
+       /* make sure we wrap properly instead of failing if the loadfile
+          is bigger than our device
+       */
+       if (sd->blocks <= lba) {
+               lba = lba%sd->blocks;
+       }
+       if (sd->blocks <= lba+xferlen) {
+               xferlen=1;
+       }
+
        cdb[1] = rd;
 
        cdb[2] = (lba>>24)&0xff;
@@ -240,8 +297,6 @@ static void scsi_read10(struct dbench_op *op)
        cdb[8] = xferlen&0xff;
        data_size = xferlen*512;
 
-       sd = op->child->private;
-
        res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
        if(res){
                printf("SCSI_IO failed\n");
@@ -256,6 +311,61 @@ static void scsi_read10(struct dbench_op *op)
        op->child->bytes += xferlen*512;
 }
 
+static void scsi_write10(struct dbench_op *op)
+{
+       struct scsi_device *sd=op->child->private;
+       unsigned char cdb[]={0x2a,0,0,0,0,0,0,0,0,0};
+       int res;
+       uint32_t lba = op->params[0];
+       uint32_t xferlen = op->params[1];
+       int rd = op->params[2];
+       int fua = op->params[3];
+       unsigned int data_size=1024*1024;
+       char data[data_size];
+       unsigned char sc;
+
+       if (!options.allow_scsi_writes) {
+               printf("Ignoring SCSI write\n");
+               return;
+       }
+
+       /* make sure we wrap properly instead of failing if the loadfile
+          is bigger than our device
+       */
+       if (sd->blocks <= lba) {
+               lba = lba%sd->blocks;
+       }
+       if (sd->blocks <= lba+xferlen) {
+               xferlen=1;
+       }
+
+       cdb[1] = rd;
+
+       cdb[2] = (lba>>24)&0xff;
+       cdb[3] = (lba>>16)&0xff;
+       cdb[4] = (lba>> 8)&0xff;
+       cdb[5] = (lba    )&0xff;
+
+       cdb[6] = fua;
+
+       cdb[7] = (xferlen>>8)&0xff;
+       cdb[8] = xferlen&0xff;
+       data_size = xferlen*512;
+
+       res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, &data_size, data, &sc);
+       if(res){
+               printf("SCSI_IO failed\n");
+               failed(op->child);
+       }
+       if (!check_sense(sc, op->status)) {
+               printf("[%d] READ10 \"%s\" failed (0x%02x) - expected %s\n", 
+                      op->child->line, op->fname, sc, op->status);
+               failed(op->child);
+       }
+
+       op->child->bytes += xferlen*512;
+}
+
 static void scsi_readcapacity10(struct dbench_op *op)
 {
        struct scsi_device *sd;
@@ -293,6 +403,7 @@ static struct backend_op ops[] = {
        { "READ10",           scsi_read10 },
        { "READCAPACITY10",   scsi_readcapacity10 },
        { "TESTUNITREADY",    scsi_testunitready },
+       { "WRITE10",          scsi_write10 },
        { NULL, NULL}
 };
 
index 0753c67..7e0d7dd 100644 (file)
 #
 # timestamp READCAPACITY10 lba pmi(0/1) sense
 0.000 READCAPACITY10 0 0 0x00
+#
+# timestamp WRITE10 lba #xferlen FUAbits
+#   FUAbits are cdb byte#1 in SBC:
+#     a value of 0x06 will force the data to be written to the medium
+#     a value of 0x00 allow the device to only write to nv-ram and not medium
+#   WRITES are ignored by default and must be activated using --allow-scsi-writes
+0.000 WRITE10 5000 1 0x06 0 0x00