libiscsi: add option to use libiscsi (if available) instead of the builtin inferior...
authorRonnie Sahlberg <ronniesahlberg@gmail.com>
Sat, 1 Oct 2011 07:19:01 +0000 (17:19 +1000)
committerRonnie Sahlberg <ronniesahlberg@gmail.com>
Sat, 1 Oct 2011 07:19:01 +0000 (17:19 +1000)
also change the arguments to specify portal/port/target/lun to use the 'iscsi url" syntax instead.

add ability to set initiatorname

Makefile.in
config.h.in
configure.in
dbench.c
dbench.h
doc/dbench.1
doc/dbench.1.html
doc/dbench.1.xml
iscsi.c
libiscsi.c [new file with mode: 0644]

index b0c0af6f6f1cee4b11ef8017ccd2d3170a0d6cff..00af80ec0db124081b6977e5819dc8a229b3fcf1 100644 (file)
@@ -11,7 +11,7 @@ datadir=@datadir@
 docdir=@datadir@/doc/dbench
 XSLTPROC = /usr/bin/xsltproc
 INSTALLCMD=@INSTALL@
-LIBS=@LIBS@ -lpopt -lz @LIBSMBCLIENT@
+LIBS=@LIBS@ -lpopt -lz @LIBSMBCLIENT@ @LIBISCSI@
 DESTDIR=/
 CC=@CC@
 CFLAGS=@CFLAGS@ -I. -DVERSION=\"$(VERSION)\" -DDATADIR=\"$(datadir)\"
@@ -19,7 +19,7 @@ EXEEXT=@EXEEXT@
 
 LIBNFS_OBJ = libnfs.o mount_client.o nfs_client.o mount_xdr.o nfs_xdr.o
 
-DB_OBJS = fileio.o util.o dbench.o child.o system.o snprintf.o sockio.o nfsio.o libnfs.a socklib.o @LINUXSCSI@ iscsi.o @SMBO@
+DB_OBJS = fileio.o util.o dbench.o child.o system.o snprintf.o sockio.o nfsio.o libnfs.a socklib.o @LINUXSCSI@ iscsi.o libiscsi.o @SMBO@
 SRV_OBJS = util.o tbench_srv.o socklib.o
 
 all: dbench doc
index 2e09a7473903c03020cf50ac85cc51710e5c8c1f..0b8a24f7472f7794f6968ef2c219191aec7c3dcc 100644 (file)
 /* Define to 1 if you have the `lgetxattr' function. */
 #undef HAVE_LGETXATTR
 
+/* Whether we have LIBISCSI support */
+#undef HAVE_LIBISCSI
+
 /* Whether we have LIBSMBCLIENT support */
 #undef HAVE_LIBSMBCLIENT
 
index 869924f232c81d0019f31e6ff9039e2256d00de9..14e0d3207086ad79e8dc551558d5fa0648dad7a4 100644 (file)
@@ -154,6 +154,47 @@ else
   SMBO=""
 fi
 
+#
+# Check that libiscsi is available
+#
+AC_MSG_CHECKING(whether libiscsi is available)
+ac_save_CFLAGS="$CFLAGS"
+ac_save_LIBS="$LIBS"
+CFLAGS="$CFLAGS $GLIB_CFLAGS"
+LIBS="$GLIB_LIBS $LIBS -liscsi"
+AC_TRY_RUN([
+#include <stdio.h>
+#include <iscsi/iscsi.h>
+
+int main(int argc, char *argv[])
+{
+       struct iscsi_context *iscsi;
+
+       iscsi = iscsi_create_context("iqn.2002-10.com.ronnie:client");
+       if (iscsi == NULL) {
+               printf("Failed to create iscsi context\n");
+               exit(10);
+       }
+
+       iscsi_destroy_context(iscsi);
+
+       return 0;
+}
+], ac_cv_have_libiscsi=yes, ac_cv_have_libiscsi=no,
+   [echo $ac_n "compile with LIBISCSI. Assuming OK... $ac_c"
+    ac_cv_have_libiscsi=yes])
+CFLAGS="$ac_save_CFLAGS"
+LIBS="$ac_save_LIBS"
+if test "$ac_cv_have_libiscsi" = yes ; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(HAVE_LIBISCSI, 1, [Whether we have LIBISCSI support])
+  LIBISCSI="-liscsi"
+else
+  AC_MSG_RESULT(no)
+  AC_MSG_NOTICE(Libiscsi not available. Building DBENCH with old iscsi support)
+  LIBISCSI=""
+fi
+
 #
 # Check whether we have access to Linux SCSI Generic ioctl()
 #
@@ -208,6 +249,7 @@ then
 fi
 
 AC_SUBST(LIBSMBCLIENT)
+AC_SUBST(LIBISCSI)
 AC_SUBST(SMBO)
 AC_SUBST(LINUXSCSI)
 AC_CONFIG_FILES([Makefile])
@@ -221,6 +263,11 @@ if test "$ac_cv_have_libsmbclient" = yes ; then
 else
   AC_MSG_NOTICE(SMB support .......................... [NO])
 fi
+if test "$ac_cv_have_libiscsi" = yes ; then
+  AC_MSG_NOTICE(LIBISCSI support ..................... [YES])
+else
+  AC_MSG_NOTICE(LIBISCSI support ..................... [NO])
+fi
 if test "$ac_cv_linux_scsi_sg" = yes ; then
   AC_MSG_NOTICE(LINUX SCSI SG support ................ [YES])
 else
index ffbba3ce97346e3a40016652c124f24d27088f0b..3f2c6c21e482527e6adddde163e9d685a41b126b 100644 (file)
--- a/dbench.c
+++ b/dbench.c
@@ -48,8 +48,7 @@ struct options options = {
        .run_once            = 0,
        .allow_scsi_writes   = 0,
        .trunc_io            = 0,
-       .iscsi_lun           = 1,
-       .iscsi_port          = 3260,
+       .iscsi_initiatorname = "iqn.2011-09.org.samba.dbench:client",
        .machine_readable    = 0,
 };
 
@@ -428,14 +427,10 @@ static void process_opts(int argc, const char **argv)
                  "scsi device", NULL },
                { "allow-scsi-writes", 0, POPT_ARG_NONE, &options.allow_scsi_writes, 0,
                  "Allow SCSI write command to the device", NULL},
-               { "iscsi-lun", 0, POPT_ARG_INT, &options.iscsi_lun, 0, 
-                 "iSCSI LUN to send I/O to", NULL },
-               { "iscsi-portal",  0, POPT_ARG_STRING, &options.iscsi_portal, 0, 
-                 "ip address of iscsi target", NULL },
-               { "iscsi-port", 0, POPT_ARG_INT, &options.iscsi_port, 0, 
-                 "iSCSI tcp port to connect to", NULL },
-               { "iscsi-target",  0, POPT_ARG_STRING, &options.iscsi_target, 0, 
-                 "iscsi IQN name of target", NULL },
+               { "iscsi-device",  0, POPT_ARG_STRING, &options.iscsi_device, 0, 
+                 "iscsi URL for the target device", NULL },
+               { "iscsi-initiatorname",  0, POPT_ARG_STRING, &options.iscsi_initiatorname, 0, 
+                 "iscsi InitiatorName", NULL },
                { "warmup", 0, POPT_ARG_INT, &options.warmup, 0, 
                  "How many seconds of warmup to run", NULL },
                { "machine-readable", 0, POPT_ARG_NONE, &options.machine_readable, 0,
index 9781a6a008b672e3fb8c4d5178a5dbc9256365a5..14a5a702650c288d0f772eb6db09379dde30d7eb 100644 (file)
--- a/dbench.h
+++ b/dbench.h
@@ -156,10 +156,8 @@ struct options {
        int allow_scsi_writes;
        int trunc_io;
        const char *scsi_dev;
-       const char *iscsi_portal;
-       const char *iscsi_target;
-       int iscsi_lun;
-       int iscsi_port;
+       const char *iscsi_device;
+       const char *iscsi_initiatorname;
        int machine_readable;
        const char *smb_share;
        const char *smb_user;
index b61a6fbb9a2415f561a02e5718f9db3a55778de6..8f31dcb79592ef0d88322c64a538e71e37102762 100644 (file)
+'\" t
 .\"     Title: dbench
-.\"    Author: 
-.\" Generator: DocBook XSL Stylesheets v1.73.2 <http://docbook.sf.net/>
-.\"      Date: 12/08/2009
-.\"    Manual: 
-.\"    Source: 
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\"      Date: 09/29/2011
+.\"    Manual: [FIXME: manual]
+.\"    Source: [FIXME: source]
+.\"  Language: English
 .\"
-.TH "DBENCH" "1" "12/08/2009" "" ""
+.TH "DBENCH" "1" "09/29/2011" "[FIXME: source]" "[FIXME: manual]"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
 .\" disable hyphenation
 .nh
 .\" disable justification (adjust text to left margin only)
 .ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
 .SH "NAME"
-dbench - a benchmark tool
+dbench \- a benchmark tool
 .SH "SYNOPSIS"
-.HP 29
+.HP \w'\fBdbench\ [OPTIONS]\ <num\-procs>\fR\ 'u
 \fBdbench [OPTIONS] <num\-procs>\fR
-.HP 7
-\fBdbench\fR [\-B\ \-\-backend=<dbench\ backend>] [\-c\ \-\-loadfile=<filename>] [\-D\ \-\-directory=<string>] [\-F\ \-\-fsync] [\-R\ \-\-target\-rate=<double>] [\-s\ \-\-sync] [\-S\ \-\-sync\-dir] [\-t\ \-\-timelimit=<integer>] [\-T\ \-\-tcp\-options=<string>] [\-\-run\-once] [\-\-fake\-io] [\-\-scsi=<scsi\-device>] [\-\-server=<hostname>] [\-\-export=<string>] [\-\-protocol=<string>] [\-\-clients\-per\-process=<integer>] [\-\-trunc\-io=<integer>] [\-\-stat\-check] [\-\-skip\-cleanup] [\-\-per\-client\-results] [\-\-iscsi\-portal=<ip\-address>] [\-\-iscsi\-port=<port>] [\-\-iscsi\-target=<iqn\ name>] [\-\-iscsi\-lun=<LUN>] [\-?\ \-\-help] [\-\-usage]
+.HP \w'\fBdbench\fR\ 'u
+\fBdbench\fR [\-B\ \-\-backend=<dbench\ backend>] [\-c\ \-\-loadfile=<filename>] [\-D\ \-\-directory=<string>] [\-F\ \-\-fsync] [\-R\ \-\-target\-rate=<double>] [\-s\ \-\-sync] [\-S\ \-\-sync\-dir] [\-t\ \-\-timelimit=<integer>] [\-T\ \-\-tcp\-options=<string>] [\-\-run\-once] [\-\-fake\-io] [\-\-scsi=<scsi\-device>] [\-\-server=<hostname>] [\-\-export=<string>] [\-\-protocol=<string>] [\-\-clients\-per\-process=<integer>] [\-\-trunc\-io=<integer>] [\-\-stat\-check] [\-\-skip\-cleanup] [\-\-per\-client\-results] [\-\-iscsi\-device=<iSCSI\ URL>] [\-\-iscsi\-initiatorname=<iSCSI\ InitiatorName>] [\-?\ \-\-help] [\-\-usage]
 .SH "DESCRIPTION"
 .PP
-dbench is a utility to benchmark a system based on client workload profiles\.
+dbench is a utility to benchmark a system based on client workload profiles\&.
 .SH "STANDARD OPTIONS"
 .SS "\-B \-\-backend=<dbench backend>"
 .PP
-The backend type specifies which kind of commandset and what kind of tests that dbench will perform\. The backend type specifies which kind of loadfile that can be used\.
+The backend type specifies which kind of commandset and what kind of tests that dbench will perform\&. The backend type specifies which kind of loadfile that can be used\&.
 .PP
-There are currently six types of backends : "fileio", "sockio", "nfs", "scsi", "iscsi" and "smb"\. The default is "fileio" which uses a smbtorture/BENCH\-NBENCH style loadfile\.
+There are currently six types of backends : "fileio", "sockio", "nfs", "scsi", "iscsi" and "smb"\&. The default is "fileio" which uses a smbtorture/BENCH\-NBENCH style loadfile\&.
 .SS "\-c \-\-loadfile=<filename>"
 .PP
-This specifies the name of the loadfile to use\. The loadfile describes the sequence and timing of operations that dbench will issue\.
+This specifies the name of the loadfile to use\&. The loadfile describes the sequence and timing of operations that dbench will issue\&.
 .SS "\-D \-\-directory=<string>"
 .PP
-This controls which directory that dbench will use as the root for when running the loadfile\. This defaults to "\." which refers to the current directory for the "fileio" and "sockio" backends and the root of the export for the "nfs" backend\.
+This controls which directory that dbench will use as the root for when running the loadfile\&. This defaults to "\&." which refers to the current directory for the "fileio" and "sockio" backends and the root of the export for the "nfs" backend\&.
 .SS "\-R \-\-target\-rate=<double>"
 .PP
-By default dbench will try to replay the loadfile and keep the same rate as the original application the loadfile was captured from\. Using this option it is possible to run the load file faster/slower than in the original capture\.
+By default dbench will try to replay the loadfile and keep the same rate as the original application the loadfile was captured from\&. Using this option it is possible to run the load file faster/slower than in the original capture\&.
 .PP
-The argument is specified in MByte/second\. dbench tries to match this target rate by dynamically increasing/decreasing the delays beteen the inidvidual opertaions in the loadfile\. These calculations only take the READ and WRITE operations of the loadfile into account so this may not work reliable for loadfiles with very few READ/WRITE operations\.
+The argument is specified in MByte/second\&. dbench tries to match this target rate by dynamically increasing/decreasing the delays beteen the inidvidual opertaions in the loadfile\&. These calculations only take the READ and WRITE operations of the loadfile into account so this may not work reliable for loadfiles with very few READ/WRITE operations\&.
 .PP
-By setting this limit to something very large, such as 999999\.99 you can effectively tell dbench to "run this loadfile as fast as possible"\.
+By setting this limit to something very large, such as 999999\&.99 you can effectively tell dbench to "run this loadfile as fast as possible"\&.
 .SS "\-t \-\-timelimit=<integer>"
 .PP
-How long to run the test for\.
+How long to run the test for\&.
 .SS "\-\-run\-once"
 .PP
-Only run the loadfile once and stop when the end of the loadfile is reached\.
+Only run the loadfile once and stop when the end of the loadfile is reached\&.
 .PP
-The default for dbench is to wrap the loadfile when the end is reached and continue running the loadfile over and over until the timelimit is reached\.
+The default for dbench is to wrap the loadfile when the end is reached and continue running the loadfile over and over until the timelimit is reached\&.
 .SS "\-\-clients\-per\-process=<integer>"
 .PP
-By default dbench will fork one child process for each client emulated\. Using this option dbench will run multiple emulated clients inside each process\.
+By default dbench will fork one child process for each client emulated\&. Using this option dbench will run multiple emulated clients inside each process\&.
 .PP
-This is useful for testing how performance differs between the case of n processes with one thread of I/O each and one process with n threads of I/O\.
+This is useful for testing how performance differs between the case of n processes with one thread of I/O each and one process with n threads of I/O\&.
 .SS "\-\-skip\-cleanup"
 .PP
-Do not cleanup and delete all temporary files in the clients work directory when the test ends\.
+Do not cleanup and delete all temporary files in the clients work directory when the test ends\&.
 .SS "\-\-per\-client\-results"
 .PP
-When the test is finished print a latency report for each inidvidual client in addition to the aggregated report over all clients\.
+When the test is finished print a latency report for each inidvidual client in addition to the aggregated report over all clients\&.
 .SH "FILEIO OPTIONS"
 .SS "\-F \-\-fsync"
 .PP
-This option only apply to the "fileio" backend\.
+This option only apply to the "fileio" backend\&.
 .PP
-This will make dbench perform a fsync() to the file after each write operation\.
+This will make dbench perform a fsync() to the file after each write operation\&.
 .SS "\-s \-\-sync\-open"
 .PP
-This option only apply to the "fileio" backend\.
+This option only apply to the "fileio" backend\&.
 .PP
-This makes dbench override the loadfile and use O_SYNC for all file open operations\.
+This makes dbench override the loadfile and use O_SYNC for all file open operations\&.
 .SS "\-S \-\-sync\-dir"
 .PP
-This option only apply to the "fileio" backend\.
+This option only apply to the "fileio" backend\&.
 .PP
-Call fsync() on the directory after each "unlink", "rmdir" or "rename" operation\. This emulates how the linux kernel nfs daemon syncs directories after performing directory modifying operations\.
+Call fsync() on the directory after each "unlink", "rmdir" or "rename" operation\&. This emulates how the linux kernel nfs daemon syncs directories after performing directory modifying operations\&.
 .SS "\-\-fake\-io"
 .PP
-This option only apply to the "fileio" backend\.
+This option only apply to the "fileio" backend\&.
 .PP
-Do not do any file read/write operations at all\.
+Do not do any file read/write operations at all\&.
 .SS "\-\-stat\-check"
 .PP
-This option only apply to the "fileio" backend\.
+This option only apply to the "fileio" backend\&.
 .PP
-After each create/mkdir/rmdir/rename operation, immediately try to stat() the object affected and verify that the return code from stat() is correct\. I\.e\. Verify that immediately after we have created an object that stat() will succeed and that immediately after we have deleted an object that stat() will fail\.
+After each create/mkdir/rmdir/rename operation, immediately try to stat() the object affected and verify that the return code from stat() is correct\&. I\&.e\&. Verify that immediately after we have created an object that stat() will succeed and that immediately after we have deleted an object that stat() will fail\&.
 .SH "SOCKIO OPTIONS"
 .SS "\-T \-\-tcp\-options=<string>"
 .PP
-This option only apply to the "sockio" backend\.
+This option only apply to the "sockio" backend\&.
 .SH "SMB OPTIONS"
 .SS "\-\-smb\-share=//<hostname>/<share>[/<path>]"
 .PP
-This option only apply to the "smb" backend\.
+This option only apply to the "smb" backend\&.
 .PP
-This option is mandatory when the "smb" backend is used\.
+This option is mandatory when the "smb" backend is used\&.
 .PP
-This specifies the server and the share to use for the testing\. It also contains an optional path to a directory to use\.
+This specifies the server and the share to use for the testing\&. It also contains an optional path to a directory to use\&.
 .PP
 Example: \-\-smb\-share=//MY\-SERVER/DATA
 .SS "\-\-smb\-user=[<domain>/]<user>%<password>"
 .PP
-This option only apply to the "smb" backend\.
+This option only apply to the "smb" backend\&.
 .PP
-This option is mandatory when the "smb" backend is used\.
+This option is mandatory when the "smb" backend is used\&.
 .PP
-This specifies the username and password to use when authenticationg to the server\.
+This specifies the username and password to use when authenticationg to the server\&.
 .PP
 Example: \-\-smb\-user=Administrator%Password
 .SH "NFS OPTIONS"
 .SS "\-\-server=<hostname>"
 .PP
-This option only apply to the "nfs" backend\.
+This option only apply to the "nfs" backend\&.
 .PP
-This option is mandatory when the "nfs" backend is used\.
+This option is mandatory when the "nfs" backend is used\&.
 .PP
-This specifies the host\-name or ip\-address of the server to test\.
+This specifies the host\-name or ip\-address of the server to test\&.
 .SS "\-\-export=<string>"
 .PP
-This option only apply to the "nfs" backend\.
+This option only apply to the "nfs" backend\&.
 .PP
-This option is mandatory when the "nfs" backend is used\.
+This option is mandatory when the "nfs" backend is used\&.
 .PP
-This specifies the nfs\-export on the server to do i/o to\.
+This specifies the nfs\-export on the server to do i/o to\&.
 .SS "\-\-protocol=<string>"
 .PP
-This option only apply to the "nfs" backend\.
+This option only apply to the "nfs" backend\&.
 .PP
-This specifies whether "tcp" or "udp" is to be used\. Default is "tcp"\.
+This specifies whether "tcp" or "udp" is to be used\&. Default is "tcp"\&.
 .SS "\-\-trunc\-io=<integer>"
 .PP
-This option only apply to the "nfs" backend\.
+This option only apply to the "nfs" backend\&.
 .PP
-Some NFS server may have limitations on how large READ/WRITE I/Os they accept preventing some loadfiles from running\. Using this option will override the length specified in the loadfile and make dbench never issuing any READ/WRITE operations larger than this\.
+Some NFS server may have limitations on how large READ/WRITE I/Os they accept preventing some loadfiles from running\&. Using this option will override the length specified in the loadfile and make dbench never issuing any READ/WRITE operations larger than this\&.
 .SH "SCSI OPTIONS"
 .SS "\-\-scsi=<scsi\-device>"
 .PP
-This option only apply to the "scsi" backend\.
+This option only apply to the "scsi" backend\&.
 .PP
-This option is mandatory when the "scsi" backend is used\.
+This option is mandatory when the "scsi" backend is used\&.
 .PP
-This specifies the device node of the scsi\-device we want to run the loadfile on\. Example: \-\-scsi=/dev/sda
+This specifies the device node of the scsi\-device we want to run the loadfile on\&. Example: \-\-scsi=/dev/sda
 .SH "ISCSI OPTIONS"
 .PP
-Dbench contains a primitive iSCSI initiator, allowing it to perform I/O to some iSCSI targets\.
-.SS "\-\-iscsi\-portal=<ip\-address>"
+Dbench contains a primitive iSCSI initiator, allowing it to perform I/O to some iSCSI targets\&.
+.SS "\-\-iscsi\-device=<iSCSI URL>"
 .PP
-This option only apply to the "iscsi" backend\.
+This option only apply to the "iscsi" backend\&.
 .PP
-This option is mandatory when the "iscsi" backend is used\.
+This option is mandatory when the "iscsi" backend is used\&.
 .PP
-This specifies the host\-name or ip\-address of the target to test\.
-.SS "\-\-iscsi\-port=<tcp port>"
+This specifies the URL to the target device\&. URLs are specified as "iscsi://<ip\-address>[:<port>]/<target\-iqn>/<lun>"
+.SS "\-\-iscsi\-initiatorname=<iSCSI InitiatorName>"
 .PP
-This option only apply to the "iscsi" backend\.
+This option only apply to the "iscsi" backend\&.
 .PP
-This option is optional when the "iscsi" backend is used\. If not used the tcp port defaults to 3260\.
+This option is optional when the "iscsi" backend is used\&.
 .PP
-This specifies the tcp port to connect to on the target\.
-.SS "\-\-iscsi\-target=<iqn name>"
-.PP
-This option only apply to the "iscsi" backend\.
-.PP
-This option is mandatory when the "iscsi" backend is used\.
-.PP
-This specifies the iscsi iqn name of the target to test\.
-.SS "\-\-iscsi\-lun=<LUN>"
-.PP
-This option only apply to the "iscsi" backend\.
-.PP
-This option is mandatory when the "iscsi" backend is used\.
-.PP
-This specifies the LUN of the target to test\.
+This specifies the InitiatorName that dbench will use when connecting to the client\&.
 .SH "COPYRIGHT/LICENSE"
 .sp
+.if n \{\
 .RS 4
+.\}
 .nf
 Copyright (C) Andrew Tridgell 2008
 Copyright (C) Ronnie Sahlberg 2008
@@ -181,14 +186,16 @@ Copyright (C) Ronnie Sahlberg 2008
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 3 of the License, or (at
-your option) any later version\.
+your option) any later version\&.
 
 This program is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\.  See the GNU
-General Public License for more details\.
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&.  See the GNU
+General Public License for more details\&.
 
 You should have received a copy of the GNU General Public License
-along with this program; if not, see http://www\.gnu\.org/licenses/\.
+along with this program; if not, see http://www\&.gnu\&.org/licenses/\&.
 .fi
+.if n \{\
 .RE
+.\}
index 47208f1f288b0cce4f559a6e3f044047cd488e96..3739206895ce3645eb3dcb2775f51dca34212dd5 100644 (file)
@@ -1,21 +1,21 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>dbench</title><meta name="generator" content="DocBook XSL Stylesheets V1.73.2"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en"><a name="dbench.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>dbench &#8212; a benchmark tool</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">dbench [OPTIONS] &lt;num-procs&gt;</code> </p></div><div class="cmdsynopsis"><p><code class="command">dbench</code>  [-B --backend=&lt;dbench backend&gt;] [-c --loadfile=&lt;filename&gt;] [-D --directory=&lt;string&gt;] [-F --fsync] [-R --target-rate=&lt;double&gt;] [-s --sync] [-S --sync-dir] [-t --timelimit=&lt;integer&gt;] [-T --tcp-options=&lt;string&gt;] [--run-once] [--fake-io] [--scsi=&lt;scsi-device&gt;] [--server=&lt;hostname&gt;] [--export=&lt;string&gt;] [--protocol=&lt;string&gt;] [--clients-per-process=&lt;integer&gt;] [--trunc-io=&lt;integer&gt;] [--stat-check] [--skip-cleanup] [--per-client-results] [--iscsi-portal=&lt;ip-address&gt;] [--iscsi-port=&lt;port&gt;] [--iscsi-target=&lt;iqn name&gt;] [--iscsi-lun=&lt;LUN&gt;] [-? --help] [--usage]</p></div></div><div class="refsect1" lang="en"><a name="id2479674"></a><h2>DESCRIPTION</h2><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>dbench</title><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" title="dbench"><a name="dbench.1"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>dbench &#8212; a benchmark tool</p></div><div class="refsynopsisdiv" title="Synopsis"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">dbench [OPTIONS] &lt;num-procs&gt;</code> </p></div><div class="cmdsynopsis"><p><code class="command">dbench</code>  [-B --backend=&lt;dbench backend&gt;] [-c --loadfile=&lt;filename&gt;] [-D --directory=&lt;string&gt;] [-F --fsync] [-R --target-rate=&lt;double&gt;] [-s --sync] [-S --sync-dir] [-t --timelimit=&lt;integer&gt;] [-T --tcp-options=&lt;string&gt;] [--run-once] [--fake-io] [--scsi=&lt;scsi-device&gt;] [--server=&lt;hostname&gt;] [--export=&lt;string&gt;] [--protocol=&lt;string&gt;] [--clients-per-process=&lt;integer&gt;] [--trunc-io=&lt;integer&gt;] [--stat-check] [--skip-cleanup] [--per-client-results] [--iscsi-device=&lt;iSCSI URL&gt;] [--iscsi-initiatorname=&lt;iSCSI InitiatorName&gt;] [-? --help] [--usage]</p></div></div><div class="refsect1" title="DESCRIPTION"><a name="id326321"></a><h2>DESCRIPTION</h2><p>
       dbench is a utility to benchmark a system based on client workload
       profiles.
-    </p></div><div class="refsect1" lang="en"><a name="id2479685"></a><h2>STANDARD OPTIONS</h2><div class="refsect2" lang="en"><a name="id2479691"></a><h3>-B --backend=&lt;dbench backend&gt;</h3><p>
+    </p></div><div class="refsect1" title="STANDARD OPTIONS"><a name="id326332"></a><h2>STANDARD OPTIONS</h2><div class="refsect2" title="-B --backend=&lt;dbench backend&gt;"><a name="id326338"></a><h3>-B --backend=&lt;dbench backend&gt;</h3><p>
       The backend type specifies which kind of commandset and what kind of
       tests that dbench will perform. The backend type specifies which
       kind of loadfile that can be used.
       </p><p>
       There are currently six types of backends : "fileio", "sockio", "nfs", "scsi", "iscsi" and "smb". The default is "fileio" which uses a smbtorture/BENCH-NBENCH style loadfile.
-      </p></div><div class="refsect2" lang="en"><a name="id2479710"></a><h3>-c --loadfile=&lt;filename&gt;</h3><p>
+      </p></div><div class="refsect2" title="-c --loadfile=&lt;filename&gt;"><a name="id326354"></a><h3>-c --loadfile=&lt;filename&gt;</h3><p>
       This specifies the name of the loadfile to use. The loadfile describes
       the sequence and timing of operations that dbench will issue.
-      </p></div><div class="refsect2" lang="en"><a name="id2479722"></a><h3>-D --directory=&lt;string&gt;</h3><p>
+      </p></div><div class="refsect2" title="-D --directory=&lt;string&gt;"><a name="id326364"></a><h3>-D --directory=&lt;string&gt;</h3><p>
       This controls which directory that dbench will use as the root for when
       running the loadfile. This defaults to "." which refers to the current
       directory for the "fileio" and "sockio" backends and the root of the
       export for the "nfs" backend.
-      </p></div><div class="refsect2" lang="en"><a name="id2479736"></a><h3>-R --target-rate=&lt;double&gt;</h3><p>
+      </p></div><div class="refsect2" title="-R --target-rate=&lt;double&gt;"><a name="id326376"></a><h3>-R --target-rate=&lt;double&gt;</h3><p>
       By default dbench will try to replay the loadfile and keep the same
       rate as the original application the loadfile was captured from.
       Using this option it is possible to run the load file faster/slower
       </p><p>
       By setting this limit to something very large, such as 999999.99 you can
       effectively tell dbench to "run this loadfile as fast as possible".
-      </p></div><div class="refsect2" lang="en"><a name="id2479765"></a><h3>-t --timelimit=&lt;integer&gt;</h3><p>
+      </p></div><div class="refsect2" title="-t --timelimit=&lt;integer&gt;"><a name="id326398"></a><h3>-t --timelimit=&lt;integer&gt;</h3><p>
       How long to run the test for.
-      </p></div><div class="refsect2" lang="en"><a name="id2479774"></a><h3>--run-once</h3><p>
+      </p></div><div class="refsect2" title="--run-once"><a name="id326407"></a><h3>--run-once</h3><p>
       Only run the loadfile once and stop when the end of the loadfile is
       reached.
       </p><p>
       The default for dbench is to wrap the loadfile when the end is
       reached and continue running the loadfile over and over until the
       timelimit is reached.
-      </p></div><div class="refsect2" lang="en"><a name="id2479791"></a><h3>--clients-per-process=&lt;integer&gt;</h3><p>
+      </p></div><div class="refsect2" title="--clients-per-process=&lt;integer&gt;"><a name="id326422"></a><h3>--clients-per-process=&lt;integer&gt;</h3><p>
       By default dbench will fork one child process for each client emulated.
       Using this option dbench will run multiple emulated clients inside
       each process.
       This is useful for testing how performance differs between the case
       of n processes with one thread of I/O each and one process with n threads
       of I/O.
-      </p></div><div class="refsect2" lang="en"><a name="id2479810"></a><h3>--skip-cleanup</h3><p>
+      </p></div><div class="refsect2" title="--skip-cleanup"><a name="id326437"></a><h3>--skip-cleanup</h3><p>
       Do not cleanup and delete all temporary files in the clients work
       directory when the test ends.
-      </p></div><div class="refsect2" lang="en"><a name="id2479821"></a><h3>--per-client-results</h3><p>
+      </p></div><div class="refsect2" title="--per-client-results"><a name="id326447"></a><h3>--per-client-results</h3><p>
       When the test is finished print a latency report for each inidvidual
       client in addition to the aggregated report over all clients.
-      </p></div></div><div class="refsect1" lang="en"><a name="id2479833"></a><h2>FILEIO OPTIONS</h2><div class="refsect2" lang="en"><a name="id2528486"></a><h3>-F --fsync</h3><p>
+      </p></div></div><div class="refsect1" title="FILEIO OPTIONS"><a name="id326459"></a><h2>FILEIO OPTIONS</h2><div class="refsect2" title="-F --fsync"><a name="id326464"></a><h3>-F --fsync</h3><p>
       This option only apply to the "fileio" backend.
       </p><p>
       This will make dbench perform a fsync() to the file after each write
       operation.
-      </p></div><div class="refsect2" lang="en"><a name="id2528500"></a><h3>-s --sync-open</h3><p>
+      </p></div><div class="refsect2" title="-s --sync-open"><a name="id326478"></a><h3>-s --sync-open</h3><p>
       This option only apply to the "fileio" backend.
       </p><p>
       This makes dbench override the loadfile and use O_SYNC for all 
       file open operations.
-      </p></div><div class="refsect2" lang="en"><a name="id2528516"></a><h3>-S --sync-dir</h3><p>
+      </p></div><div class="refsect2" title="-S --sync-dir"><a name="id326492"></a><h3>-S --sync-dir</h3><p>
       This option only apply to the "fileio" backend.
       </p><p>
       Call fsync() on the directory after each "unlink", "rmdir" or "rename"
       operation. This emulates how the linux kernel nfs daemon syncs
       directories after performing directory modifying operations.
-      </p></div><div class="refsect2" lang="en"><a name="id2528533"></a><h3>--fake-io</h3><p>
+      </p></div><div class="refsect2" title="--fake-io"><a name="id326506"></a><h3>--fake-io</h3><p>
       This option only apply to the "fileio" backend.
       </p><p>
       Do not do any file read/write operations at all.
-      </p></div><div class="refsect2" lang="en"><a name="id2528547"></a><h3>--stat-check</h3><p>
+      </p></div><div class="refsect2" title="--stat-check"><a name="id326520"></a><h3>--stat-check</h3><p>
       This option only apply to the "fileio" backend.
       </p><p>
       After each create/mkdir/rmdir/rename operation, immediately try to
@@ -81,9 +81,9 @@
       is correct. I.e. Verify that immediately after we have created an
       object that stat() will succeed and that immediately after we have
       deleted an object that stat() will fail.
-      </p></div></div><div class="refsect1" lang="en"><a name="id2528568"></a><h2>SOCKIO OPTIONS</h2><div class="refsect2" lang="en"><a name="id2528573"></a><h3>-T --tcp-options=&lt;string&gt;</h3><p>
+      </p></div></div><div class="refsect1" title="SOCKIO OPTIONS"><a name="id326536"></a><h2>SOCKIO OPTIONS</h2><div class="refsect2" title="-T --tcp-options=&lt;string&gt;"><a name="id326542"></a><h3>-T --tcp-options=&lt;string&gt;</h3><p>
       This option only apply to the "sockio" backend.
-      </p></div></div><div class="refsect1" lang="en"><a name="id2528585"></a><h2>SMB OPTIONS</h2><div class="refsect2" lang="en"><a name="id2528591"></a><h3>--smb-share=//&lt;hostname&gt;/&lt;share&gt;[/&lt;path&gt;]</h3><p>
+      </p></div></div><div class="refsect1" title="SMB OPTIONS"><a name="id326553"></a><h2>SMB OPTIONS</h2><div class="refsect2" title="--smb-share=//&lt;hostname&gt;/&lt;share&gt;[/&lt;path&gt;]"><a name="id326558"></a><h3>--smb-share=//&lt;hostname&gt;/&lt;share&gt;[/&lt;path&gt;]</h3><p>
       This option only apply to the "smb" backend.
       </p><p>
       This option is mandatory when the "smb" backend is used.
@@ -91,7 +91,7 @@
       This specifies the server and the share to use for the testing. It also contains an optional path to a directory to use.
       </p><p>
        Example: --smb-share=//MY-SERVER/DATA
-      </p></div><div class="refsect2" lang="en"><a name="id2528616"></a><h3>--smb-user=[&lt;domain&gt;/]&lt;user&gt;%&lt;password&gt;</h3><p>
+      </p></div><div class="refsect2" title="--smb-user=[&lt;domain&gt;/]&lt;user&gt;%&lt;password&gt;"><a name="id326580"></a><h3>--smb-user=[&lt;domain&gt;/]&lt;user&gt;%&lt;password&gt;</h3><p>
       This option only apply to the "smb" backend.
       </p><p>
       This option is mandatory when the "smb" backend is used.
       This specifies the username and password to use when authenticationg to the server.
       </p><p>
        Example: --smb-user=Administrator%Password
-      </p></div></div><div class="refsect1" lang="en"><a name="id2528641"></a><h2>NFS OPTIONS</h2><div class="refsect2" lang="en"><a name="id2528647"></a><h3>--server=&lt;hostname&gt;</h3><p>
+      </p></div></div><div class="refsect1" title="NFS OPTIONS"><a name="id326603"></a><h2>NFS OPTIONS</h2><div class="refsect2" title="--server=&lt;hostname&gt;"><a name="id326608"></a><h3>--server=&lt;hostname&gt;</h3><p>
       This option only apply to the "nfs" backend.
       </p><p>
       This option is mandatory when the "nfs" backend is used.
       </p><p>
       This specifies the host-name or ip-address of the server to test.
-      </p></div><div class="refsect2" lang="en"><a name="id2528666"></a><h3>--export=&lt;string&gt;</h3><p>
+      </p></div><div class="refsect2" title="--export=&lt;string&gt;"><a name="id326626"></a><h3>--export=&lt;string&gt;</h3><p>
       This option only apply to the "nfs" backend.
       </p><p>
       This option is mandatory when the "nfs" backend is used.
       </p><p>
       This specifies the nfs-export on the server to do i/o to.
-      </p></div><div class="refsect2" lang="en"><a name="id2528685"></a><h3>--protocol=&lt;string&gt;</h3><p>
+      </p></div><div class="refsect2" title="--protocol=&lt;string&gt;"><a name="id326643"></a><h3>--protocol=&lt;string&gt;</h3><p>
       This option only apply to the "nfs" backend.
       </p><p>
       This specifies whether "tcp" or "udp" is to be used. Default is "tcp".
-      </p></div><div class="refsect2" lang="en"><a name="id2528700"></a><h3>--trunc-io=&lt;integer&gt;</h3><p>
+      </p></div><div class="refsect2" title="--trunc-io=&lt;integer&gt;"><a name="id326656"></a><h3>--trunc-io=&lt;integer&gt;</h3><p>
       This option only apply to the "nfs" backend.
       </p><p>
       Some NFS server may have limitations on how large READ/WRITE I/Os they
       accept preventing some loadfiles from running. Using this option will
       override the length specified in the loadfile and make dbench never
       issuing any READ/WRITE operations larger than this.
-      </p></div></div><div class="refsect1" lang="en"><a name="id2528720"></a><h2>SCSI OPTIONS</h2><div class="refsect2" lang="en"><a name="id2528725"></a><h3>--scsi=&lt;scsi-device&gt;</h3><p>
+      </p></div></div><div class="refsect1" title="SCSI OPTIONS"><a name="id326673"></a><h2>SCSI OPTIONS</h2><div class="refsect2" title="--scsi=&lt;scsi-device&gt;"><a name="id326678"></a><h3>--scsi=&lt;scsi-device&gt;</h3><p>
       This option only apply to the "scsi" backend.
       </p><p>
       This option is mandatory when the "scsi" backend is used.
       </p><p>
       This specifies the device node of the scsi-device we want to run the loadfile on. Example: --scsi=/dev/sda
-      </p></div></div><div class="refsect1" lang="en"><a name="id2528747"></a><h2>iSCSI OPTIONS</h2><p>
+      </p></div></div><div class="refsect1" title="iSCSI OPTIONS"><a name="id326698"></a><h2>iSCSI OPTIONS</h2><p>
     Dbench contains a primitive iSCSI initiator, allowing it to perform I/O
     to some iSCSI targets.
-    </p><div class="refsect2" lang="en"><a name="id2528758"></a><h3>--iscsi-portal=&lt;ip-address&gt;</h3><p>
+    </p><div class="refsect2" title="--iscsi-device=&lt;iSCSI URL&gt;"><a name="id326708"></a><h3>--iscsi-device=&lt;iSCSI URL&gt;</h3><p>
       This option only apply to the "iscsi" backend.
       </p><p>
       This option is mandatory when the "iscsi" backend is used.
       </p><p>
-      This specifies the host-name or ip-address of the target to test.
-      </p></div><div class="refsect2" lang="en"><a name="id2528777"></a><h3>--iscsi-port=&lt;tcp port&gt;</h3><p>
+      This specifies the URL to the target device. URLs are specified as "iscsi://&lt;ip-address&gt;[:&lt;port&gt;]/&lt;target-iqn&gt;/&lt;lun&gt;"
+      </p></div><div class="refsect2" title="--iscsi-initiatorname=&lt;iSCSI InitiatorName&gt;"><a name="id326726"></a><h3>--iscsi-initiatorname=&lt;iSCSI InitiatorName&gt;</h3><p>
       This option only apply to the "iscsi" backend.
       </p><p>
       This option is optional when the "iscsi" backend is used.
-      If not used the tcp port defaults to 3260.
       </p><p>
-      This specifies the tcp port to connect to on the target.
-      </p></div><div class="refsect2" lang="en"><a name="id2528798"></a><h3>--iscsi-target=&lt;iqn name&gt;</h3><p>
-      This option only apply to the "iscsi" backend.
-      </p><p>
-      This option is mandatory when the "iscsi" backend is used.
-      </p><p>
-      This specifies the iscsi iqn name of the target to test.
-      </p></div><div class="refsect2" lang="en"><a name="id2528817"></a><h3>--iscsi-lun=&lt;LUN&gt;</h3><p>
-      This option only apply to the "iscsi" backend.
-      </p><p>
-      This option is mandatory when the "iscsi" backend is used.
-      </p><p>
-      This specifies the LUN of the target to test.
-      </p></div></div><div class="refsect1" lang="en"><a name="id2528837"></a><h2>COPYRIGHT/LICENSE</h2><div class="literallayout"><p><br>
+      This specifies the InitiatorName that dbench will use when connecting to the client.
+      </p></div></div><div class="refsect1" title="COPYRIGHT/LICENSE"><a name="id326745"></a><h2>COPYRIGHT/LICENSE</h2><div class="literallayout"><p><br>
 Copyright (C) Andrew Tridgell 2008<br>
 Copyright (C) Ronnie Sahlberg 2008<br>
 <br>
index 5d39053084d04d864de3ba7d82618d06459ab557..3825c3cdd59270c8980342d994ecb8128892e6de 100644 (file)
                <arg choice="opt">--stat-check</arg>
                <arg choice="opt">--skip-cleanup</arg>
                <arg choice="opt">--per-client-results</arg>
-               <arg choice="opt">--iscsi-portal=&lt;ip-address&gt;</arg>
-               <arg choice="opt">--iscsi-port=&lt;port&gt;</arg>
-               <arg choice="opt">--iscsi-target=&lt;iqn name&gt;</arg>
-               <arg choice="opt">--iscsi-lun=&lt;LUN&gt;</arg>
+               <arg choice="opt">--iscsi-device=&lt;iSCSI URL&gt;</arg>
+               <arg choice="opt">--iscsi-initiatorname=&lt;iSCSI InitiatorName&gt;</arg>
 
                <arg choice="opt">-? --help</arg>
                <arg choice="opt">--usage</arg>
     Dbench contains a primitive iSCSI initiator, allowing it to perform I/O
     to some iSCSI targets.
     </para>
-    <refsect2><title>--iscsi-portal=&lt;ip-address&gt;</title>
+    <refsect2><title>--iscsi-device=&lt;iSCSI URL&gt;</title>
       <para>
       This option only apply to the "iscsi" backend.
       </para>
       </para>
 
       <para>
-      This specifies the host-name or ip-address of the target to test.
+      This specifies the URL to the target device. URLs are specified as "iscsi://&lt;ip-address&gt;[:&lt;port&gt;]/&lt;target-iqn&gt;/&lt;lun&gt;"
       </para>
     </refsect2>
-    <refsect2><title>--iscsi-port=&lt;tcp port&gt;</title>
+    <refsect2><title>--iscsi-initiatorname=&lt;iSCSI InitiatorName&gt;</title>
       <para>
       This option only apply to the "iscsi" backend.
       </para>
 
       <para>
       This option is optional when the "iscsi" backend is used.
-      If not used the tcp port defaults to 3260.
       </para>
 
       <para>
-      This specifies the tcp port to connect to on the target.
-      </para>
-    </refsect2>
-
-    <refsect2><title>--iscsi-target=&lt;iqn name&gt;</title>
-      <para>
-      This option only apply to the "iscsi" backend.
-      </para>
-
-      <para>
-      This option is mandatory when the "iscsi" backend is used.
-      </para>
-
-      <para>
-      This specifies the iscsi iqn name of the target to test.
-      </para>
-    </refsect2>
-
-    <refsect2><title>--iscsi-lun=&lt;LUN&gt;</title>
-      <para>
-      This option only apply to the "iscsi" backend.
-      </para>
-
-      <para>
-      This option is mandatory when the "iscsi" backend is used.
-      </para>
-
-      <para>
-      This specifies the LUN of the target to test.
+      This specifies the InitiatorName that dbench will use when connecting to the client.
       </para>
     </refsect2>
   </refsect1>
diff --git a/iscsi.c b/iscsi.c
index f8e5742faece0f6c96a9796c5c43b5be4093cff9..eab6b3e3fc3bae43ce3927270771674139b628d6 100644 (file)
--- a/iscsi.c
+++ b/iscsi.c
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
-#include "dbench.h"
+#include "config.h"
+
+#if !defined(HAVE_LIBISCSI)
 
+#include "dbench.h"
 #include <stdio.h>
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <stdint.h>
+#include <sys/socket.h>
 #include <arpa/inet.h>
 
 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
 
+static void iscsi_testunitready(struct dbench_op *op);
+static void local_iscsi_readcapacity10(struct dbench_op *op, uint64_t *blocks);
+
+static void iscsi_readcapacity10(struct dbench_op *op)
+{
+       return local_iscsi_readcapacity10(op, NULL);
+}
+
+struct iscsi_device {
+       const char *portal;
+       int port;
+       const char *target;
+
+       int s;
+       uint64_t isid;
+       uint32_t itt;
+       uint32_t cmd_sn;
+       uint32_t exp_stat_sn;
+       uint64_t blocks;
+       int lun;
+       char *initiator_name;
+};
+
+
+static void failed(struct child_struct *child)
+{
+       child->failed = 1;
+       printf("ERROR: child %d failed at line %d\n", child->id, child->line);
+       exit(1);
+}
+
+/* XXX merge with scsi.c */
+static int check_sense(unsigned char sc, const char *expected)
+{
+       if (strcmp(expected, "*") == 0){
+               return 1;
+       }
+       if (strncmp(expected, "0x", 2) == 0) {
+               return sc == strtol(expected, NULL, 16);
+       }
+       return 0;
+}
+
+
 #ifndef SG_DXFER_NONE
 #define SG_DXFER_NONE -1
 #endif
@@ -82,18 +129,6 @@ const char *scsi_status_name(int sc, struct scsi_status_name *names) {
 };
 
 
-struct iscsi_device {
-       const char *portal;
-       const char *target;
-       int s;
-       uint64_t isid;
-       uint64_t blocks;
-       uint32_t itt;
-       uint32_t cmd_sn;
-       uint32_t exp_stat_sn;
-};
-
-
 void set_nonblocking(int fd)
 {
        unsigned v;
@@ -273,10 +308,8 @@ static int wait_for_pdu(struct iscsi_device *sd, char *ish, char *data, unsigned
        return 0;
 }
 
-static int iscsi_login(struct child_struct *child, struct iscsi_device *sd)
+static int iscsi_login(struct iscsi_device *sd)
 {
-       char name[256];
-       char alias[256];
        char ish[48];
        int len;
        struct login_param *login_param;
@@ -296,11 +329,7 @@ static int iscsi_login(struct child_struct *child, struct iscsi_device *sd)
        add_login_param("DataPDUInOrder", "Yes");
        add_login_param("MaxConnections", "1");
        add_login_param("TargetName", discard_const(sd->target));
-       sprintf(alias, "dbench:%d", child->id);
-       add_login_param("InitiatorAlias", alias);
-       sprintf(name, "iqn.2009-09.dbench:%d", child->id);
-       add_login_param("InitiatorName", name);
-
+       add_login_param("InitiatorName", sd->initiator_name);
 
        bzero(ish, 48);
        /* opcode : LOGIN REQUEST (I) */
@@ -359,35 +388,6 @@ static int iscsi_login(struct child_struct *child, struct iscsi_device *sd)
 }
 
 
-
-
-
-
-
-
-
-
-
-/* XXX merge with scsi.c */
-static int check_sense(unsigned char sc, const char *expected)
-{
-       if (strcmp(expected, "*") == 0){
-               return 1;
-       }
-       if (strncmp(expected, "0x", 2) == 0) {
-               return sc == strtol(expected, NULL, 16);
-       }
-       return 0;
-}
-static void failed(struct child_struct *child)
-{
-       child->failed = 1;
-       printf("ERROR: child %d failed at line %d\n", child->id, child->line);
-       exit(1);
-}
-
-
-
 static int do_iscsi_io(struct iscsi_device *sd, unsigned char *cdb, unsigned char cdb_size, int xfer_dir, unsigned int *data_size, char *data, unsigned char *sc, int *sense_key, int *sense_ascq)
 {
        char ish[48];
@@ -419,7 +419,7 @@ static int do_iscsi_io(struct iscsi_device *sd, unsigned char *cdb, unsigned cha
        }
 
        /* lun */
-       ish[9] = options.iscsi_lun;
+       ish[9] = sd->lun;
 
        /* expected data xfer len */
        ish[20]  = ((*data_size)>>24)&0xff;
@@ -475,34 +475,6 @@ need_more_data:
        return 0;
 }
 
-static void iscsi_testunitready(struct dbench_op *op)
-{
-       struct iscsi_device *sd;
-       unsigned char cdb[]={0,0,0,0,0,0};
-       int res;
-       unsigned char sc;
-       int sense_key, sense_ascq;
-       unsigned int data_size=0;
-
-       sd = op->child->private;
-
-       res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_NONE, &data_size, NULL, &sc, &sense_key, &sense_ascq);
-       if(res){
-               printf("SCSI_IO failed\n");
-               failed(op->child);
-       }
-       if (!check_sense(sc, op->status)) {
-               printf("[%d] TESTUNITREADY \"%s\" failed (0x%02x) - expected %s\n", 
-                      op->child->line, op->fname, sc, op->status);
-               if (sc == SCSI_STATUS_CHECK_CONDITION) {
-                      printf("SCSI command failed with CHECK_CONDITION. Sense key:%s(%d) Ascq:%s(0x%04x)\n",
-                            scsi_status_name(sense_key, &scsi_key_names[0]), sense_key, scsi_status_name(sense_ascq, &scsi_ascq_names[0]), sense_ascq);
-               }
-               failed(op->child);
-       }
-       return;
-}
-
 static void iscsi_read10(struct dbench_op *op)
 {
        struct iscsi_device *sd=op->child->private;
@@ -669,50 +641,6 @@ static void iscsi_write10(struct dbench_op *op)
 }
 
 
-static void local_iscsi_readcapacity10(struct dbench_op *op, uint64_t *blocks)
-{
-       struct iscsi_device *sd;
-       unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
-       int res;
-       int lba = op->params[0];
-       int pmi = op->params[1];
-       unsigned int data_size=8;
-       char data[data_size];
-       unsigned char sc;
-       int sense_key, sense_ascq;
-
-       cdb[2] = (lba>>24)&0xff;
-       cdb[3] = (lba>>16)&0xff;
-       cdb[4] = (lba>> 8)&0xff;
-       cdb[5] = (lba    )&0xff;
-
-       cdb[8] = (pmi?1:0);
-
-       sd = op->child->private;
-
-       res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc, &sense_key, &sense_ascq);
-       if(res){
-               printf("SCSI_IO failed\n");
-               failed(op->child);
-       }
-       if (!check_sense(sc, op->status)) {
-               printf("[%d] READCAPACITY10 \"%s\" failed (0x%02x) - expected %s\n", 
-                      op->child->line, op->fname, sc, op->status);
-               if (sc == SCSI_STATUS_CHECK_CONDITION) {
-                      printf("SCSI command failed with CHECK_CONDITION. Sense key:%s(%d) Ascq:%s(0x%04x)\n",
-                            scsi_status_name(sense_key, &scsi_key_names[0]), sense_key, scsi_status_name(sense_ascq, &scsi_ascq_names[0]), sense_ascq);
-               }
-               failed(op->child);
-       }
-
-       if (blocks) {
-               *blocks  = (data[0]&0xff)<<24;
-               *blocks |= (data[1]&0xff)<<16;
-               *blocks |= (data[2]&0xff)<<8;
-               *blocks |= (data[3]&0xff);
-       }
-}
-
 /* <service action> <type> <key> <sa-key>*/
 static void iscsi_prout(struct dbench_op *op)
 {
@@ -774,16 +702,15 @@ static void iscsi_prout(struct dbench_op *op)
        }
 }
 
-static void iscsi_readcapacity10(struct dbench_op *op)
-{
-       return local_iscsi_readcapacity10(op, NULL);
-}
-
 static void iscsi_setup(struct child_struct *child)
 {
        struct iscsi_device *sd;
        struct sockaddr_in sin;
        struct dbench_op fake_op;
+       char *portal;
+       char *port;
+       char *target;
+       char *lun;
 
        sd = malloc(sizeof(struct iscsi_device));
        if (sd == NULL) {
@@ -792,8 +719,38 @@ static void iscsi_setup(struct child_struct *child)
        }
        child->private=sd;
 
-       sd->portal=options.iscsi_portal;
-       sd->target=options.iscsi_target;
+       if (options.iscsi_device == NULL) {
+               printf("Must specify iSCSI URL for the target device\n");
+               return;
+       }
+       if (strncmp(options.iscsi_device, "iscsi://", 8)) {
+               printf("Invalid iSCSI device URL. Syntax is \"iscsi://<ip-address>[:<port>]/<target-iqn>/<lun>\"\n");
+               return;
+       }
+       portal = strdup(&options.iscsi_device[8]);
+       target = strchr(portal, '/');
+       if (target == NULL) {
+               printf("Invalid iSCSI device URL. Syntax is \"iscsi://<ip-address>[:<port>]/<target-iqn>/<lun>\"\n");
+               return;
+       }
+       *target++ = '\0';
+       lun = strchr(target, '/');
+       if (lun == NULL) {
+               printf("Invalid iSCSI device URL. Syntax is \"iscsi://<ip-address>[:<port>]/<target-iqn>/<lun>\"\n");
+               return;
+       }
+       *lun++ = '\0';
+       port = strchr(portal, ':');
+       if (port != NULL) {
+               *port++ = '\0';
+       }
+
+       sd->portal = portal;
+       sd->target = target;
+       sd->port   = port?atoi(port):3260;
+       sd->lun    = atoi(lun);
+       asprintf(&sd->initiator_name, "%s-%d", options.iscsi_initiatorname, child->id);
+
        sd->isid  =0x0000800000000000ULL | child->id; 
        sd->s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sd->s == -1) {
@@ -802,7 +759,7 @@ static void iscsi_setup(struct child_struct *child)
        }
 
        sin.sin_family      = AF_INET;
-       sin.sin_port        = htons(options.iscsi_port);
+       sin.sin_port        = htons(sd->port);
        if (inet_pton(AF_INET, sd->portal, &sin.sin_addr) != 1) {
                printf("Failed to convert \"%s\" into an address\n", sd->portal);
                exit(10);
@@ -816,7 +773,7 @@ static void iscsi_setup(struct child_struct *child)
        sd->itt=0x000a0000;
        sd->cmd_sn=0;
        sd->exp_stat_sn=0;
-       if (iscsi_login(child, sd) != 0) {
+       if (iscsi_login(sd) != 0) {
                printf("Failed to log in to target.\n");
                exit(10);
        }
@@ -848,6 +805,10 @@ static int iscsi_init(void)
        struct sockaddr_in sin;
        struct dbench_op fake_op;
        struct child_struct child;
+       char *portal;
+       char *port;
+       char *target;
+       char *lun;
 
        sd = malloc(sizeof(struct iscsi_device));
        if (sd == NULL) {
@@ -857,9 +818,40 @@ static int iscsi_init(void)
        child.private=sd;
        child.id=99999;
 
-       sd->portal=options.iscsi_portal;
-       sd->target=options.iscsi_target;
-       sd->isid  =0x0000800000000000ULL | child.id; 
+
+       if (options.iscsi_device == NULL) {
+               printf("Must specify iSCSI URL for the target device\n");
+               return -1;
+       }
+       if (strncmp(options.iscsi_device, "iscsi://", 8)) {
+               printf("Invalid iSCSI device URL. Syntax is \"iscsi://<ip-address>[:<port>]/<target-iqn>/<lun>\"\n");
+               return -1;
+       }
+       portal = strdup(&options.iscsi_device[8]);
+       target = strchr(portal, '/');
+       if (target == NULL) {
+               printf("Invalid iSCSI device URL. Syntax is \"iscsi://<ip-address>[:<port>]/<target-iqn>/<lun>\"\n");
+               return -1;
+       }
+       *target++ = '\0';
+       lun = strchr(target, '/');
+       if (lun == NULL) {
+               printf("Invalid iSCSI device URL. Syntax is \"iscsi://<ip-address>[:<port>]/<target-iqn>/<lun>\"\n");
+               return -1;
+       }
+       *lun++ = '\0';
+       port = strchr(portal, ':');
+       if (port != NULL) {
+               *port++ = '\0';
+       }
+
+       sd->portal = portal;
+       sd->target = target;
+       sd->port   = port?atoi(port):3260;
+       sd->lun    = atoi(lun);
+       asprintf(&sd->initiator_name, "%s-%d", options.iscsi_initiatorname, child.id);
+
+       sd->isid  =0x0000800000000000ULL | child.id;
        sd->s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sd->s == -1) {
                printf("could not open socket() errno:%d(%s)\n", errno, strerror(errno));
@@ -867,7 +859,7 @@ static int iscsi_init(void)
        }
 
        sin.sin_family      = AF_INET;
-       sin.sin_port        = htons(options.iscsi_port);
+       sin.sin_port        = htons(sd->port);
        if (inet_pton(AF_INET, sd->portal, &sin.sin_addr) != 1) {
                printf("Failed to convert \"%s\" into an address\n", sd->portal);
                return 1;
@@ -881,7 +873,7 @@ static int iscsi_init(void)
        sd->itt=0x000a0000;
        sd->cmd_sn=0;
        sd->exp_stat_sn=0;
-       if (iscsi_login(&child, sd) != 0) {
+       if (iscsi_login(sd) != 0) {
                printf("Failed to log in to target.\n");
                return 1;
        }
@@ -901,6 +893,76 @@ static int iscsi_init(void)
        return 0;
 }
 
+static void iscsi_testunitready(struct dbench_op *op)
+{
+       struct iscsi_device *sd;
+       unsigned char cdb[]={0,0,0,0,0,0};
+       int res;
+       unsigned char sc;
+       int sense_key, sense_ascq;
+       unsigned int data_size=0;
+
+       sd = op->child->private;
+
+       res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_NONE, &data_size, NULL, &sc, &sense_key, &sense_ascq);
+       if(res){
+               printf("SCSI_IO failed\n");
+               failed(op->child);
+       }
+       if (!check_sense(sc, op->status)) {
+               printf("[%d] TESTUNITREADY \"%s\" failed (0x%02x) - expected %s\n", 
+                      op->child->line, op->fname, sc, op->status);
+               if (sc == SCSI_STATUS_CHECK_CONDITION) {
+                      printf("SCSI command failed with CHECK_CONDITION. Sense key:%s(%d) Ascq:%s(0x%04x)\n",
+                            scsi_status_name(sense_key, &scsi_key_names[0]), sense_key, scsi_status_name(sense_ascq, &scsi_ascq_names[0]), sense_ascq);
+               }
+               failed(op->child);
+       }
+       return;
+}
+
+static void local_iscsi_readcapacity10(struct dbench_op *op, uint64_t *blocks)
+{
+       struct iscsi_device *sd;
+       unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
+       int res;
+       int lba = op->params[0];
+       int pmi = op->params[1];
+       unsigned int data_size=8;
+       char data[data_size];
+       unsigned char sc;
+       int sense_key, sense_ascq;
+
+       cdb[2] = (lba>>24)&0xff;
+       cdb[3] = (lba>>16)&0xff;
+       cdb[4] = (lba>> 8)&0xff;
+       cdb[5] = (lba    )&0xff;
+
+       cdb[8] = (pmi?1:0);
+
+       sd = op->child->private;
+
+       res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc, &sense_key, &sense_ascq);
+       if(res){
+               printf("SCSI_IO failed\n");
+               failed(op->child);
+       }
+       if (!check_sense(sc, op->status)) {
+               printf("[%d] READCAPACITY10 \"%s\" failed (0x%02x) - expected %s\n", 
+                      op->child->line, op->fname, sc, op->status);
+               if (sc == SCSI_STATUS_CHECK_CONDITION) {
+                      printf("SCSI command failed with CHECK_CONDITION. Sense key:%s(%d) Ascq:%s(0x%04x)\n",
+                            scsi_status_name(sense_key, &scsi_key_names[0]), sense_key, scsi_status_name(sense_ascq, &scsi_ascq_names[0]), sense_ascq);
+               }
+               failed(op->child);
+       }
+       if (blocks) {
+               *blocks  = (data[0]&0xff)<<24;
+               *blocks |= (data[1]&0xff)<<16;
+               *blocks |= (data[2]&0xff)<<8;
+               *blocks |= (data[3]&0xff);
+       }
+}
 
 static struct backend_op ops[] = {
        { "TESTUNITREADY",      iscsi_testunitready },
@@ -920,4 +982,4 @@ struct nb_operations iscsi_ops = {
        .ops          = ops
 };
 
-
+#endif
diff --git a/libiscsi.c b/libiscsi.c
new file mode 100644 (file)
index 0000000..f8984c1
--- /dev/null
@@ -0,0 +1,398 @@
+/* 
+   Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2011
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include "config.h"
+
+#if defined(HAVE_LIBISCSI)
+
+#include "dbench.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <iscsi/iscsi.h>
+#include <iscsi/scsi-lowlevel.h>
+
+#define discard_const(ptr) ((void *)((intptr_t)(ptr)))
+
+static void iscsi_testunitready(struct dbench_op *op);
+static void local_iscsi_readcapacity10(struct dbench_op *op, uint64_t *blocks);
+
+static void iscsi_readcapacity10(struct dbench_op *op)
+{
+       return local_iscsi_readcapacity10(op, NULL);
+}
+
+struct iscsi_device {
+       struct iscsi_context *iscsi;
+       uint64_t blocks;
+       int lun;
+       char *initiator_name;
+};
+
+
+static void failed(struct child_struct *child)
+{
+       child->failed = 1;
+       printf("ERROR: child %d failed at line %d\n", child->id, child->line);
+       exit(1);
+}
+
+/* XXX merge with scsi.c */
+static int check_sense(unsigned char sc, const char *expected)
+{
+       if (strcmp(expected, "*") == 0){
+               return 1;
+       }
+       if (strncmp(expected, "0x", 2) == 0) {
+               return sc == strtol(expected, NULL, 16);
+       }
+       return 0;
+}
+
+static void iscsi_synchronizecache10(struct dbench_op *op)
+{
+       struct iscsi_device *sd;
+       struct scsi_task *task;
+       uint32_t lba = op->params[0];
+       uint32_t xferlen = op->params[1];
+       int syncnv = op->params[2];
+       int immed = op->params[3];
+
+       sd = op->child->private;
+
+       if ((task = iscsi_synchronizecache10_sync(sd->iscsi, sd->lun, lba, xferlen, syncnv, immed)) == NULL) {
+               printf("[%d] failed to send SYNCHRONIZECACHE10\n", op->child->line);
+               failed(op->child);
+               return;
+       }
+       if (!check_sense(task->status, op->status)) {
+               if (task->status == SCSI_STATUS_CHECK_CONDITION) {
+                      printf("SCSI command failed with CHECK_CONDITION. Sense key:0x%02x Ascq:0x%04x\n",
+                                   task->sense.key, task->sense.ascq);
+               }
+               failed(op->child);
+               scsi_free_scsi_task(task);
+               return;
+       }
+       scsi_free_scsi_task(task);
+}
+
+static void iscsi_write10(struct dbench_op *op)
+{
+       struct iscsi_device *sd;
+       struct scsi_task *task;
+       uint32_t lba = op->params[0];
+       uint32_t xferlen = op->params[1];       
+       int fua = op->params[2];
+       unsigned int data_size=1024*1024;
+       char data[data_size];
+
+       sd = op->child->private;
+
+       lba = (lba / xferlen) * xferlen;
+
+       /* 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;
+       }
+
+       if ((task = iscsi_write10_sync(sd->iscsi, sd->lun,
+               data, xferlen*512, lba,
+               fua&0x04, fua&0x02,
+               512)) == NULL) {
+               printf("[%d] failed to send WRITE10\n", op->child->line);
+               failed(op->child);
+               return;
+       }
+       if (!check_sense(task->status, op->status)) {
+               if (task->status == SCSI_STATUS_CHECK_CONDITION) {
+                      printf("SCSI command failed with CHECK_CONDITION. Sense key:0x%02x Ascq:0x%04x\n",
+                                   task->sense.key, task->sense.ascq);
+               }
+               failed(op->child);
+               scsi_free_scsi_task(task);
+               return;
+       }
+
+       op->child->bytes += xferlen*512;
+       scsi_free_scsi_task(task);
+}
+
+static void iscsi_read10(struct dbench_op *op)
+{
+       struct iscsi_device *sd;
+       struct scsi_task *task;
+       uint32_t lba = op->params[0];
+       uint32_t xferlen = op->params[1];       
+
+       sd = op->child->private;
+
+       lba = (lba / xferlen) * xferlen;
+
+       /* 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;
+       }
+
+
+       if ((task = iscsi_read10_sync(sd->iscsi, sd->lun, lba, xferlen*512, xferlen)) == NULL) {
+               printf("[%d] failed to send READ10\n", op->child->line);
+               failed(op->child);
+               return;
+       }
+       if (!check_sense(task->status, op->status)) {
+               if (task->status == SCSI_STATUS_CHECK_CONDITION) {
+                      printf("SCSI command failed with CHECK_CONDITION. Sense key:0x%02x Ascq:0x%04x\n",
+                                   task->sense.key, task->sense.ascq);
+               }
+               failed(op->child);
+               scsi_free_scsi_task(task);
+               return;
+       }
+
+       op->child->bytes += xferlen*512;
+       scsi_free_scsi_task(task);
+}
+
+
+static void local_iscsi_readcapacity10(struct dbench_op *op, uint64_t *blocks)
+{
+       struct iscsi_device *sd;
+       struct scsi_task *task;
+       struct scsi_readcapacity10 *rc10;
+
+       sd = op->child->private;
+
+       if ((task = iscsi_readcapacity10_sync(sd->iscsi, sd->lun, op->params[0], op->params[1])) == NULL) {
+               printf("[%d] failed to send READCAPACITY10\n", op->child->line);
+               failed(op->child);
+               return;
+       }
+       if (!check_sense(task->status, op->status)) {
+               if (task->status == SCSI_STATUS_CHECK_CONDITION) {
+                      printf("SCSI command failed with CHECK_CONDITION. Sense key:0x%02x Ascq:0x%04x\n",
+                                   task->sense.key, task->sense.ascq);
+               }
+               failed(op->child);
+               scsi_free_scsi_task(task);
+               return;
+       }
+
+       rc10 = scsi_datain_unmarshall(task);
+       if (rc10 == NULL) {
+               printf("failed to unmarshall readcapacity10 data\n");
+               failed(op->child);
+               scsi_free_scsi_task(task);
+               return;
+       }
+
+       if (blocks) {
+               *blocks  = rc10->lba;
+       }
+
+       scsi_free_scsi_task(task);
+}
+
+static void iscsi_testunitready(struct dbench_op *op)
+{
+       struct iscsi_device *sd;
+       struct scsi_task *task;
+
+       sd = op->child->private;
+
+       if ((task = iscsi_testunitready_sync(sd->iscsi, sd->lun)) == NULL) {
+               printf("[%d] failed to send TESTUNITREADY\n", op->child->line);
+               failed(op->child);
+               return;
+       }
+       if (!check_sense(task->status, op->status)) {
+               if (task->status == SCSI_STATUS_CHECK_CONDITION) {
+                      printf("SCSI command failed with CHECK_CONDITION. Sense key:0x%02x Ascq:0x%04x\n",
+                                   task->sense.key, task->sense.ascq);
+               }
+               failed(op->child);
+               scsi_free_scsi_task(task);
+               return;
+       }
+       scsi_free_scsi_task(task);
+}
+
+
+static void iscsi_cleanup(struct child_struct *child)
+{
+       struct iscsi_device *sd;
+
+       sd=child->private;
+       if (sd->iscsi != NULL) {
+               iscsi_destroy_context(sd->iscsi);
+       }
+       free(sd);
+}
+
+static void iscsi_setup(struct child_struct *child)
+{
+       struct iscsi_device *sd;
+       struct dbench_op fake_op;
+       struct iscsi_url *iscsi_url = NULL;
+
+       sd = malloc(sizeof(struct iscsi_device));
+       if (sd == NULL) {
+               printf("Failed to allocate iscsi device structure\n");
+               return;
+       }
+       child->private=sd;
+       child->id=99999;
+
+       asprintf(&sd->initiator_name, "%s-%d", options.iscsi_initiatorname, child->id);
+
+       sd->iscsi = iscsi_create_context(sd->initiator_name);
+       if (sd->iscsi == NULL) {
+               printf("Failed to create context\n");
+               return;
+       }
+
+       iscsi_url = iscsi_parse_full_url(sd->iscsi, options.iscsi_device);
+       if (iscsi_url == NULL) {
+               fprintf(stderr, "Failed to parse URL: %s\n", 
+                       iscsi_get_error(sd->iscsi));
+               return;
+       }
+
+       sd->lun = iscsi_url->lun;
+
+       iscsi_set_targetname(sd->iscsi, iscsi_url->target);
+       iscsi_set_session_type(sd->iscsi, ISCSI_SESSION_NORMAL);
+       iscsi_set_header_digest(sd->iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
+
+       if (iscsi_url->user != NULL) {
+               if (iscsi_set_initiator_username_pwd(sd->iscsi, iscsi_url->user, iscsi_url->passwd) != 0) {
+                       fprintf(stderr, "Failed to set initiator username and password\n");
+                       return;
+               }
+       }
+
+       if (iscsi_full_connect_sync(sd->iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
+               fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(sd->iscsi));
+               iscsi_destroy_url(iscsi_url);
+               iscsi_destroy_context(sd->iscsi);
+               return;
+       }
+
+       fake_op.child=child;
+       fake_op.status="*";
+       iscsi_testunitready(&fake_op);
+
+       fake_op.params[0]=0;
+       fake_op.params[1]=0;
+       fake_op.status="*";
+       local_iscsi_readcapacity10(&fake_op, &sd->blocks);
+}
+
+static int iscsi_init(void)
+{
+       struct iscsi_device *sd;
+       struct dbench_op fake_op;
+       struct child_struct child;
+       struct iscsi_url *iscsi_url = NULL;
+
+       sd = malloc(sizeof(struct iscsi_device));
+       if (sd == NULL) {
+               printf("Failed to allocate iscsi device structure\n");
+               return -1;
+       }
+       child.private=sd;
+       child.id=99999;
+
+       asprintf(&sd->initiator_name, "%s-%d", options.iscsi_initiatorname, child.id);
+
+       sd->iscsi = iscsi_create_context(sd->initiator_name);
+       if (sd->iscsi == NULL) {
+               printf("Failed to create context\n");
+               return -1;
+       }
+
+       iscsi_url = iscsi_parse_full_url(sd->iscsi, options.iscsi_device);
+       if (iscsi_url == NULL) {
+               fprintf(stderr, "Failed to parse URL: %s\n", 
+                       iscsi_get_error(sd->iscsi));
+               return -1;
+       }
+
+       sd->lun = iscsi_url->lun;
+
+       iscsi_set_targetname(sd->iscsi, iscsi_url->target);
+       iscsi_set_session_type(sd->iscsi, ISCSI_SESSION_NORMAL);
+       iscsi_set_header_digest(sd->iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
+
+       if (iscsi_url->user != NULL) {
+               if (iscsi_set_initiator_username_pwd(sd->iscsi, iscsi_url->user, iscsi_url->passwd) != 0) {
+                       fprintf(stderr, "Failed to set initiator username and password\n");
+                       return -1;
+               }
+       }
+
+       if (iscsi_full_connect_sync(sd->iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
+               fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(sd->iscsi));
+               iscsi_destroy_url(iscsi_url);
+               iscsi_destroy_context(sd->iscsi);
+               return -1;
+       }
+
+       fake_op.child=&child;
+       fake_op.status="*";
+       iscsi_testunitready(&fake_op);
+
+       fake_op.params[0]=0;
+       fake_op.params[1]=0;
+       fake_op.status="*";
+       local_iscsi_readcapacity10(&fake_op, &sd->blocks);
+
+       free(sd);
+
+       return 0;
+}
+
+
+static struct backend_op ops[] = {
+       { "TESTUNITREADY",      iscsi_testunitready },
+       { "READ10",             iscsi_read10 },
+       { "READCAPACITY10",     iscsi_readcapacity10 },
+       { "SYNCHRONIZECACHE10", iscsi_synchronizecache10 },
+       { "WRITE10",            iscsi_write10 },
+       { NULL, NULL}
+};
+
+struct nb_operations iscsi_ops = {
+       .backend_name = "iscsibench",
+       .init         = iscsi_init,
+       .setup        = iscsi_setup,
+       .cleanup      = iscsi_cleanup,
+       .ops          = ops
+};
+
+#endif
+