Files
libiscsi/patches/mtx-iscsi.diff
Ronnie Sahlberg 185649144d Update the MTX patch for libiscsi.
MTX sets XFER-direction to "WRITE" even if the xfer length is 0
Catch this condition so that we pass XFER-direction==NONE to libiscsi for this case
2012-08-09 20:46:54 +10:00

308 lines
7.9 KiB
Diff

commit 2b859765244332e95fe960e7ec94b744e02c7c83
Author: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Date: Thu Aug 9 20:44:45 2012 +1000
ISCSI support
Add support for specifying devices using '-f iscsi://<host>/<target>/<lun>
syntax
Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
diff --git a/Makefile.in b/Makefile.in
index 6b967cf..fe81280 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -26,7 +26,7 @@ INSTALL = @INSTALL@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@ -DVERSION="\"$(VERSION)\"" -I$(srcdir) -I.
LDFLAGS = @LDFLAGS@
-LIBS = @LIBS@
+LIBS = @LIBS@ @libiscsi@
USE_OBJCOPY = @USE_OBJCOPY@
INSTALL_DOC = $(INSTALL) -m 644
diff --git a/config.h.in b/config.h.in
index 7282e46..81ce3d4 100644
--- a/config.h.in
+++ b/config.h.in
@@ -30,8 +30,8 @@
#define HAVE_SYS_IOCTL_H 0
#define HAVE_SYS_MTIO_H 0
#define HAVE_DDK_NTDDSCSI_H 0
+#define HAVE_LIBISCSI 0
#define WORDS_BIGENDIAN 0
#endif
-
diff --git a/configure.in b/configure.in
index 10aa09d..b8b79e7 100755
--- a/configure.in
+++ b/configure.in
@@ -110,4 +110,50 @@ AC_FUNC_VPRINTF
dnl Check for files
+dnl Check for libiscsi
+use_libiscsi=""
+AC_ARG_ENABLE([libiscsi],
+ AC_HELP_STRING([--enable-libiscsi], [enable iscsi support]),
+ use_libiscsi="$enableval"
+)
+
+AC_MSG_CHECKING(if libiscsi is available)
+if test "$use_libiscsi" = "yes" ; then
+ AC_MSG_RESULT(enabled)
+ AC_SUBST([libiscsi], ['-liscsi'])
+ AC_DEFINE_UNQUOTED(HAVE_LIBISCSI, 1, [we have libiscsi support], )
+elif test "$use_libiscsi" = "no" ; then
+ AC_MSG_RESULT(disabled)
+ AC_SUBST([libiscsi], [''])
+else
+ac_save_CFLAGS="$CFLAGS"
+ac_save_LIBS="$LIBS"
+CFLAGS=""
+LIBS="-liscsi"
+AC_TRY_RUN([
+/*
+ * Just see if we can compile/link with libiscsi
+ */
+#include <iscsi/iscsi.h>
+int main(int argc, const char *argv[])
+{
+ iscsi_create_context("");
+ 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_SUBST([libiscsi], ['-liscsi'])
+ AC_DEFINE_UNQUOTED(HAVE_LIBISCSI, 1, [we have libiscsi support], )
+else
+ AC_MSG_RESULT(no)
+ AC_SUBST([libiscsi], [''])
+fi
+fi
+
+
AC_OUTPUT(Makefile)
diff --git a/mtxl.h b/mtxl.h
index 073f4fa..84510cc 100644
--- a/mtxl.h
+++ b/mtxl.h
@@ -26,6 +26,10 @@
#ifndef MTXL_H
#define MTXL_H 1
+#if HAVE_LIBISCSI
+#define ISCSI_FD 0x7fffffff
+#endif
+
#include "mtx.h"
#undef min
diff --git a/scsi_linux.c b/scsi_linux.c
index cc14ebf..8a7becb 100644
--- a/scsi_linux.c
+++ b/scsi_linux.c
@@ -58,14 +58,133 @@ $Revision: 193 $
static int pack_id;
static int sg_timeout;
+
+#if HAVE_LIBISCSI
+#include <stdint.h>
+#include <iscsi/iscsi.h>
+#include <iscsi/scsi-lowlevel.h>
+struct iscsi_lun {
+ struct iscsi_context *context;
+ int lun;
+};
+static struct iscsi_lun iscsi_lun;
+
+static int
+do_iscsi_io(Direction_T Direction,
+ CDB_T *CDB,
+ int CDB_Length,
+ void *DataBuffer,
+ int DataBufferLength,
+ RequestSense_T *RequestSense)
+{
+ struct scsi_task *task;
+ struct iscsi_data outdata, *data = NULL;
+
+ task = malloc(sizeof(struct scsi_task));
+ if (task == NULL) {
+ FatalError("Out-of-memory: Failed to allocate iscsi task structure\n");
+ }
+ memset(task, 0, sizeof(struct scsi_task));
+
+ task->cdb_size = CDB_Length;
+ memcpy(&task->cdb[0], CDB, task->cdb_size);
+
+ if (DataBufferLength > 0) {
+ switch (Direction) {
+ case Input:
+ task->xfer_dir = SCSI_XFER_READ;
+ task->expxferlen = DataBufferLength;
+ break;
+ case Output:
+ task->xfer_dir = SCSI_XFER_WRITE;
+ task->expxferlen = DataBufferLength;
+ outdata.size = DataBufferLength;
+ outdata.data = DataBuffer;
+ data = &outdata;
+ break;
+ }
+ } else {
+ task->xfer_dir = SCSI_XFER_NONE;
+ task->expxferlen = 0;
+ }
+
+ if (iscsi_scsi_command_sync(iscsi_lun.context, iscsi_lun.lun, task, data) == NULL) {
+ FatalError("Failed to do iscsi i/o : %s\n", iscsi_get_error(iscsi_lun.context));
+ scsi_free_scsi_task(task);
+ return -1;
+ }
+
+ if (task->status == SCSI_STATUS_GOOD) {
+ if (task->xfer_dir == SCSI_XFER_READ) {
+ memcpy(DataBuffer, task->datain.data, DataBufferLength);
+ }
+ }
+ if (task->status == SCSI_STATUS_CHECK_CONDITION) {
+ memcpy(RequestSense, task->datain.data+2, task->datain.size-2);
+ }
+ scsi_free_scsi_task(task);
+
+ return 0;
+ }
+
+static DEVICE_TYPE OpenISCSI(char *DeviceName)
+{
+ char *portal = NULL;
+ char *target = NULL;
+ char *lun = NULL;
+
+ portal = strdup(DeviceName + 8);
+ if (portal == NULL) {
+ FatalError("Out-of-memory. Failed to strdup %s\n", DeviceName);
+ }
+ target = index(portal, '/');
+ if (target == NULL) {
+ FatalError("Invalid iSCSI URL : %s.\nURL must be specified as \"iscsi://<host>[:<port>]/<target-iqn>/<lun>\"\n", DeviceName);
+ }
+ *target++ = 0;
+
+ lun = index(target, '/');
+ if (lun == NULL) {
+ FatalError("Invalid iSCSI URL : %s.\nURL must be specified as \"iscsi://<host>[:<port>]/<target-iqn>/<lun>\"\n", DeviceName);
+ }
+ *lun++ = 0;
+
+ iscsi_lun.context = iscsi_create_context("iqn.1999-08.net.sourceforge.mtx");
+ if (iscsi_lun.context == NULL) {
+ FatalError("Failed to create iSCSI context for %s. (%s)\n", DeviceName,
+ iscsi_get_error(iscsi_lun.context));
+ }
+ iscsi_set_targetname(iscsi_lun.context, target);
+ iscsi_set_session_type(iscsi_lun.context, ISCSI_SESSION_NORMAL);
+ iscsi_set_header_digest(iscsi_lun.context, ISCSI_HEADER_DIGEST_NONE_CRC32C);
+
+ iscsi_lun.lun = atoi(lun);
+ if (iscsi_full_connect_sync(iscsi_lun.context, portal, iscsi_lun.lun) != 0) {
+ FatalError("Failed to connect to %s. (%s)\n", DeviceName,
+ iscsi_get_error(iscsi_lun.context));
+ iscsi_destroy_context(iscsi_lun.context);
+ iscsi_lun.context = NULL;
+ }
+
+ return ISCSI_FD;
+}
+#endif
+
DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
{
int timeout = SG_SCSI_DEFAULT_TIMEOUT;
#ifdef SG_IO
int k; /* version */
#endif
- int DeviceFD = open(DeviceName, O_RDWR);
+ int DeviceFD;
+
+#if HAVE_LIBISCSI
+ if (!strncmp(DeviceName, "iscsi://", 8)) {
+ return OpenISCSI(DeviceName);
+ }
+#endif
+ DeviceFD = open(DeviceName, O_RDWR);
if (DeviceFD < 0)
FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
@@ -98,6 +217,14 @@ void SCSI_Default_Timeout(void)
void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
{
+#if HAVE_LIBISCSI
+ if (iscsi_lun.context != NULL && DeviceFD == ISCSI_FD) {
+ iscsi_logout_sync(iscsi_lun.context);
+ iscsi_destroy_context(iscsi_lun.context);
+ iscsi_lun.context = NULL;
+ return;
+ }
+#endif
if (close(DeviceFD) < 0)
FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
}
@@ -118,6 +245,16 @@ scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd)
int word2;
} idlun;
+#if HAVE_LIBISCSI
+ if (fd == ISCSI_FD) {
+ /* we only need the lun */
+ retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
+ retval->id = 0;
+ retval->lun = iscsi_lun.lun;
+ return retval;
+ }
+#endif
+
status = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
if (status)
{
@@ -157,6 +294,13 @@ int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
unsigned int status;
sg_io_hdr_t io_hdr;
+#if HAVE_LIBISCSI
+ if (DeviceFD == ISCSI_FD) {
+ return do_iscsi_io(Direction, CDB, CDB_Length,
+ DataBuffer, DataBufferLength,
+ RequestSense);
+ }
+#endif
memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
memset(RequestSense, 0, sizeof(RequestSense_T));
@@ -261,6 +405,13 @@ int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
struct sg_header *Header; /* we actually point this into Command... */
struct sg_header *ResultHeader; /* we point this into ResultBuf... */
+#if HAVE_LIBISCSI
+ if (DeviceFD == ISCSI_FD) {
+ return do_iscsi_io(Direction, CDB, CDB_Length,
+ DataBuffer, DataBufferLength,
+ RequestSense);
+ }
+#endif
/* First, see if we need to set our SCSI timeout to something different */
if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT)
{