commit 2648e61716b76bd7deeb2218a5ff7ae0493930ed Author: Ronnie Sahlberg Date: Wed Jul 11 15:41:59 2012 +1000 iscsi support diff --git a/README b/README index 46d8f94..7b8736a 100644 --- a/README +++ b/README @@ -7,6 +7,8 @@ command set. Apart from SCSI parallel interface (SPI) devices, the SCSI command set is used by ATAPI devices (CD/DVDs and tapes), USB mass storage devices, Fibre Channel disks, IEEE 1394 storage devices (that use the "SBP" protocol), SAS, iSCSI and FCoE devices (amongst others). +On some platforms the package can also access iSCSI devices directly +using a built-in iscsi client. See the iSCSI section below for more info. This package originally targeted the Linux SCSI subsystem. Since most operating systems contain a SCSI command pass-through mechanism, many @@ -335,6 +337,44 @@ The more recent utilities that use "getopt_long" only are: sg_wr_mode +iSCSI support +============= +On some platforms (Linux) sg3_utils can be built with iSCSI support. +When built with iSCSI support, the utilities will be able to access iSCSI +devices directly using a built-in iSCSI client, without having to first make +the devices visible to the host. +This is very useful for cases where you have very many iSCSI targets you want +to manage and very many LUNs, in which case it may be impractical to make all +those devices visible to the local host. + +In order to get access to the iSCSI functionality, the sg3_utils package must +be built and linked against the iscsi client library from : + https://github.com/sahlberg/libiscsi +When configuring and building sg3_utils, the build process will detect if +this library is available and if it is build a version of sg3_utils with +iSCSI support. + +With iSCSI support, you can specify a iSCSI URL instead of the /dev/sg* +device that most of the utilities take. + +Example: + sudo sg_inq iscsi://karelin/iqn.ronnie.test/1 +Which means : Use LUN 1 on the target with the name "iqn.ronnie.test" +that is available on network host "karelin". + +The full form of the iSCSI URL is : + iscsi://[[%]@][:]// + +iSCSI Authentication: +The package supports normal iSCSI CHAP authentication to those targets that +require it. +This is done by specifying hte CHAP username and password as part of the iSCSI +URL. + +Example: + sudo sg_inq iscsi://ronnie%secret@karelin/iqn.ronnie.test/1 + + Dangerous code ============== This code: diff --git a/configure.ac b/configure.ac index 355ca84..1916603 100644 --- a/configure.ac +++ b/configure.ac @@ -76,4 +76,34 @@ AC_ARG_ENABLE([win32-spt-direct], AC_DEFINE_UNQUOTED(WIN32_SPT_DIRECT, 1, [enable Win32 SPT Direct], ) ) + +AC_MSG_CHECKING(if libiscsi is available) +ac_save_CFLAGS="$CFLAGS" +ac_save_LIBS="$LIBS" +CFLAGS="" +LIBS="-liscsi" +AC_TRY_RUN([ +/* + * Just see if we can compile/link with libiscsi + */ +#include +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(CONFIG_LIBISCSI, 1, [we have libiscsi support], ) +else + AC_MSG_RESULT(no) + AC_SUBST([libiscsi], ['']) +fi + AC_OUTPUT(Makefile include/Makefile lib/Makefile src/Makefile doc/Makefile) diff --git a/include/sg_pt_iscsi.h b/include/sg_pt_iscsi.h new file mode 100644 index 0000000..f849eb0 --- /dev/null +++ b/include/sg_pt_iscsi.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 Ronnie Sahlberg + * All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the BSD_LICENSE file. + */ + +extern struct sg_context *iscsi; + +#define ISCSI_FAKE_FD 0x7fffffff + +int do_iscsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose); +struct sg_pt_base *construct_iscsi_pt_obj(void); +void clear_iscsi_pt_obj(struct sg_pt_base * vp); +void destruct_iscsi_pt_obj(struct sg_pt_base * vp); +void set_iscsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, int cdb_len); +void set_iscsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, int max_sense_len); +void set_iscsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp, int dxfer_len); +void set_iscsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp, int dxfer_len); +int get_iscsi_pt_resid(const struct sg_pt_base * vp); +int get_iscsi_pt_result_category(const struct sg_pt_base * vp); +int get_iscsi_pt_os_err(const struct sg_pt_base * vp); +int get_iscsi_pt_sense_len(const struct sg_pt_base * vp); +void set_iscsi_pt_packet_id(struct sg_pt_base * vp, int pack_id); +int iscsi_pt_close_device(int device_fd); +char *get_iscsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b); +int get_iscsi_pt_transport_err(const struct sg_pt_base * vp); +char *get_iscsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, char * b); +void set_iscsi_pt_tag(struct sg_pt_base * vp, uint64_t tag); +void set_iscsi_pt_task_management(struct sg_pt_base * vp, int tmf_code); +void set_iscsi_pt_task_attr(struct sg_pt_base * vp, int attribute, int priority); +int get_iscsi_pt_duration_ms(const struct sg_pt_base * vp); +int get_iscsi_pt_status_response(const struct sg_pt_base * vp); +int iscsi_pt_open_device(const char *device_name, int read_only, int verbose); diff --git a/lib/Makefile.am b/lib/Makefile.am index 3d5213e..6990f12 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -8,6 +8,7 @@ libsgutils2_la_SOURCES = \ sg_cmds_extra.c \ sg_cmds_mmc.c \ sg_pt_common.c \ + sg_pt_iscsi.c \ sg_pt_linux.c \ sg_io_linux.c @@ -33,6 +34,7 @@ libsgutils2_la_SOURCES = \ sg_pt_win32.c EXTRA_libsgutils2_la_SOURCES = \ + sg_pt_iscsi.c \ sg_pt_linux.c \ sg_io_linux.c \ sg_pt_freebsd.c \ @@ -55,6 +57,7 @@ libsgutils2_la_SOURCES = \ sg_pt_win32.c EXTRA_libsgutils2_la_SOURCES = \ + sg_pt_iscsi.c \ sg_pt_linux.c \ sg_io_linux.c \ sg_pt_freebsd.c \ @@ -77,6 +80,7 @@ libsgutils2_la_SOURCES = \ sg_pt_freebsd.c EXTRA_libsgutils2_la_SOURCES = \ + sg_pt_iscsi.c \ sg_pt_linux.c \ sg_io_linux.c \ sg_linux_inc.h \ @@ -100,6 +104,7 @@ libsgutils2_la_SOURCES = \ sg_pt_solaris.c EXTRA_libsgutils2_la_SOURCES = \ + sg_pt_iscsi.c \ sg_pt_linux.c \ sg_io_linux.c \ sg_linux_inc.h \ @@ -123,6 +128,7 @@ libsgutils2_la_SOURCES = \ sg_pt_osf1.c EXTRA_libsgutils2_la_SOURCES = \ + sg_pt_iscsi.c \ sg_pt_linux.c \ sg_io_linux.c \ sg_pt_freebsd.c \ @@ -140,7 +146,7 @@ lib_LTLIBRARIES = libsgutils2.la libsgutils2_la_LDFLAGS = -version-info 2:0:0 -libsgutils2_la_LIBADD = @GETOPT_O_FILES@ @os_libs@ +libsgutils2_la_LIBADD = @GETOPT_O_FILES@ @os_libs@ @libiscsi@ libsgutils2_la_DEPENDENCIES = @GETOPT_O_FILES@ diff --git a/lib/sg_pt_iscsi.c b/lib/sg_pt_iscsi.c new file mode 100644 index 0000000..8f09baf --- /dev/null +++ b/lib/sg_pt_iscsi.c @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2010 Ronnie Sahlberg + * All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the BSD_LICENSE file. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef CONFIG_LIBISCSI + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "sg_lib.h" +#include "sg_pt.h" +#include "sg_linux_inc.h" +#include "sg_pt_iscsi.h" + +struct sg_context { + struct iscsi_context *context; + int lun; +}; +struct sg_context *iscsi; + +struct sg_pt_iscsi { + int os_err; + + int xferdir; + const unsigned char *cdb; + int cdb_len; + unsigned char *sense; + int sense_len; + int max_sense_len; + struct iscsi_data datain; + struct iscsi_data dataout; + int device_status; +}; + +struct sg_pt_base { + struct sg_pt_iscsi impl; +}; + +int +do_iscsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose) +{ + struct sg_pt_iscsi * ptp = &vp->impl; + struct scsi_task *task; + struct iscsi_data *data = NULL; + + /* keep compiler happy */ + time_secs = time_secs; + verbose = verbose; + fd = fd; + + task = malloc(sizeof(struct scsi_task)); + bzero(task, sizeof(struct scsi_task)); + + ptp->os_err = 0; + + task->cdb_size = ptp->cdb_len; + memcpy(&task->cdb[0], ptp->cdb, task->cdb_size); + + task->xfer_dir = ptp->xferdir; + switch (task->xfer_dir) { + case SCSI_XFER_NONE: + task->expxferlen = 0; + break; + case SCSI_XFER_READ: + task->expxferlen = ptp->datain.size; + break; + case SCSI_XFER_WRITE: + task->expxferlen = ptp->dataout.size; + data = &ptp->dataout; + break; + } + + if (iscsi_scsi_command_sync(iscsi->context, iscsi->lun, task, data) == NULL) { + printf("error\n"); + scsi_free_scsi_task(task); + ptp->os_err = -1; + return -1; + } + + ptp->device_status = task->status; + if (task->status == SCSI_STATUS_GOOD) { + memcpy(ptp->datain.data, task->datain.data, + task->datain.sizedatain.size? + task->datain.size:ptp->datain.size); + scsi_free_scsi_task(task); + return 0; + } + + if (task->status == SCSI_STATUS_CHECK_CONDITION) { + /* +2 is to strip off the initial "length" and just copy the sense blob itself */ + ptp->sense_len = (ptp->max_sense_len<(task->datain.size-2))?ptp->max_sense_len:(task->datain.size-2); + memcpy(ptp->sense, task->datain.data+2, ptp->sense_len); + scsi_free_scsi_task(task); + return 0; + } + return -1; +} + + +struct sg_pt_base * +construct_iscsi_pt_obj(void) +{ + struct sg_pt_iscsi * ptp; + + ptp = (struct sg_pt_iscsi *) + calloc(1, sizeof(struct sg_pt_iscsi)); + ptp->xferdir = SCSI_XFER_NONE; + return (struct sg_pt_base *)ptp; +} + +void +clear_iscsi_pt_obj(struct sg_pt_base * vp) +{ + struct sg_pt_iscsi * ptp = &vp->impl; + + if (ptp) { + memset(ptp, 0, sizeof(struct sg_pt_iscsi)); + ptp->xferdir = SCSI_XFER_READ; + } +} + +void +destruct_iscsi_pt_obj(struct sg_pt_base * vp) +{ + struct sg_pt_iscsi * ptp = &vp->impl; + + if (ptp) + free(ptp); +} + +void +set_iscsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, + int cdb_len) +{ + struct sg_pt_iscsi * ptp = &vp->impl; + + ptp->cdb = cdb; + ptp->cdb_len = cdb_len; +} + +void +set_iscsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, + int max_sense_len) +{ + struct sg_pt_iscsi * ptp = &vp->impl; + + memset(sense, 0, max_sense_len); + ptp->sense = sense; + ptp->max_sense_len = max_sense_len; +} + +void +set_iscsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp, + int dxfer_len) +{ + struct sg_pt_iscsi * ptp = &vp->impl; + + if (dxfer_len > 0) { + ptp->datain.data = dxferp; + ptp->datain.size = dxfer_len; + ptp->xferdir = SCSI_XFER_READ; + } +} + +void +set_iscsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp, + int dxfer_len) +{ + struct sg_pt_iscsi * ptp = &vp->impl; + + if (dxfer_len > 0) { + ptp->dataout.data = (unsigned char *)dxferp; + ptp->dataout.size = dxfer_len; + ptp->xferdir = SCSI_XFER_WRITE; + } +} + +int +get_iscsi_pt_resid(const struct sg_pt_base * vp) +{ + /* keep compiler happy */ + vp = vp; + + return 0; +} + +int +get_iscsi_pt_result_category(const struct sg_pt_base * vp) +{ + const struct sg_pt_iscsi * ptp = &vp->impl; + + if (ptp->os_err) + return SCSI_PT_RESULT_OS_ERR; + + if (ptp->device_status) + return SCSI_PT_RESULT_SENSE; + else + return SCSI_PT_RESULT_GOOD; +} + +int +get_iscsi_pt_os_err(const struct sg_pt_base * vp) +{ + const struct sg_pt_iscsi * ptp = &vp->impl; + + return ptp->os_err; +} + +int +get_iscsi_pt_sense_len(const struct sg_pt_base * vp) +{ + const struct sg_pt_iscsi * ptp = &vp->impl; + + return ptp->sense_len; +} + +void +set_iscsi_pt_packet_id(struct sg_pt_base * vp, int pack_id) +{ + /* keep compiler happy */ + vp = vp; + pack_id = pack_id; +} + +int +iscsi_pt_close_device(int device_fd) +{ + /* keep compiler happy */ + device_fd = device_fd; + + iscsi_logout_sync(iscsi->context); + iscsi_destroy_context(iscsi->context); + free(iscsi); + iscsi = NULL; + return 0; +} + +char * +get_iscsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) +{ + const struct sg_pt_iscsi * ptp = &vp->impl; + const char * cp; + + cp = safe_strerror(ptp->os_err); + strncpy(b, cp, max_b_len); + if ((int)strlen(cp) >= max_b_len) + b[max_b_len - 1] = '\0'; + return b; +} + +int +get_iscsi_pt_transport_err(const struct sg_pt_base * vp) +{ + /* keep compiler happy */ + vp = vp; + + return 0; +} + +char * +get_iscsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, + char * b) +{ + /* keep compiler happy */ + vp = vp; + max_b_len = max_b_len; + b = b; + + return ""; +} + +void +set_iscsi_pt_tag(struct sg_pt_base * vp, uint64_t tag) +{ + /* keep compiler happy */ + vp = vp; + tag = tag; +} + +void +set_iscsi_pt_task_management(struct sg_pt_base * vp, int tmf_code) +{ + /* keep compiler happy */ + vp = vp; + tmf_code = tmf_code; +} + +void +set_iscsi_pt_task_attr(struct sg_pt_base * vp, int attribute, int priority) +{ + /* keep compiler happy */ + vp = vp; + attribute = attribute; + priority = priority; +} + +int +get_iscsi_pt_duration_ms(const struct sg_pt_base * vp) +{ + /* keep compiler happy */ + vp = vp; + + return 0; +} + + +int +get_iscsi_pt_status_response(const struct sg_pt_base * vp) +{ + /* keep compiler happy */ + vp = vp; + + return 0; +} + +int +iscsi_pt_open_device(const char *device_name, int read_only, int verbose) +{ + char *tmpstr = NULL, *portal, *target, *lun; + + /* keep compiler happy */ + read_only = read_only; + verbose = verbose; + + if (strncmp(device_name, "iscsi://", 8)) { + return -1; + } + + tmpstr = strdup(device_name); + portal = tmpstr+8; + target = index(portal, '/'); + if (!target) { + fprintf(stderr, "Invalid iscsi url : %s\n", device_name); + free(tmpstr); + return -1; + } + *target++ = 0; + lun = index(target, '/'); + if (!lun) { + fprintf(stderr, "Invalid iscsi url : %s\n", device_name); + free(tmpstr); + return -1; + } + *lun++ = 0; + + iscsi = malloc(sizeof(struct sg_context)); + iscsi->context = iscsi_create_context("iqn.2010-12.org.sg3utils"); + if (!iscsi->context) { + fprintf(stderr, "Failed to create iscsi context for url %s\n", device_name); + free(tmpstr); + free(iscsi); + iscsi = NULL; + return -1; + } + + iscsi->lun = atoi(lun); + iscsi_set_targetname(iscsi->context, target); + iscsi_set_session_type(iscsi->context, ISCSI_SESSION_NORMAL); + iscsi_set_header_digest(iscsi->context, ISCSI_HEADER_DIGEST_NONE_CRC32C); + + if (iscsi_full_connect_sync(iscsi->context, portal, iscsi->lun) != 0) { + fprintf(stderr, "iSCSI login failed: %s\n", iscsi_get_error(iscsi->context)); + free(tmpstr); + iscsi_destroy_context(iscsi->context); + free(iscsi); + iscsi = NULL; + return -1; + } + + return ISCSI_FAKE_FD; +} + +#endif diff --git a/lib/sg_pt_linux.c b/lib/sg_pt_linux.c index 0a5216e..6be755e 100644 --- a/lib/sg_pt_linux.c +++ b/lib/sg_pt_linux.c @@ -27,6 +27,10 @@ #include "sg_lib.h" #include "sg_linux_inc.h" +#ifdef CONFIG_LIBISCSI +#include "sg_pt_iscsi.h" +#endif + #define DEF_TIMEOUT 60000 /* 60,000 millisecs (60 seconds) */ static const char * linux_host_bytes[] = { @@ -117,6 +121,12 @@ scsi_pt_open_flags(const char * device_name, int flags, int verbose) { int fd; +#ifdef CONFIG_LIBISCSI + if (!strncmp(device_name, "iscsi://", 8)) { + return iscsi_pt_open_device(device_name, flags, verbose); + } +#endif + if (verbose > 1) { if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; @@ -135,6 +145,12 @@ scsi_pt_close_device(int device_fd) { int res; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return iscsi_pt_close_device(device_fd); + } +#endif + res = close(device_fd); if (res < 0) res = -errno; @@ -147,6 +163,12 @@ construct_scsi_pt_obj() { struct sg_pt_linux_scsi * ptp; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return construct_iscsi_pt_obj(); + } +#endif + ptp = (struct sg_pt_linux_scsi *) calloc(1, sizeof(struct sg_pt_linux_scsi)); if (ptp) { @@ -161,6 +183,12 @@ destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return destruct_iscsi_pt_obj(vp); + } +#endif + if (ptp) free(ptp); } @@ -170,6 +198,12 @@ clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return clear_iscsi_pt_obj(vp); + } +#endif + if (ptp) { memset(ptp, 0, sizeof(struct sg_pt_linux_scsi)); ptp->io_hdr.interface_id = 'S'; @@ -183,6 +217,12 @@ set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_cdb(vp, cdb, cdb_len); + } +#endif + if (ptp->io_hdr.cmdp) ++ptp->in_err; ptp->io_hdr.cmdp = (unsigned char *)cdb; @@ -195,6 +235,12 @@ set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_sense(vp, sense, max_sense_len); + } +#endif + if (ptp->io_hdr.sbp) ++ptp->in_err; memset(sense, 0, max_sense_len); @@ -209,6 +255,12 @@ set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_data_in(vp, dxferp, dxfer_len); + } +#endif + if (ptp->io_hdr.dxferp) ++ptp->in_err; if (dxfer_len > 0) { @@ -225,6 +277,12 @@ set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_data_out(vp, dxferp, dxfer_len); + } +#endif + if (ptp->io_hdr.dxferp) ++ptp->in_err; if (dxfer_len > 0) { @@ -239,6 +297,13 @@ set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_packet_id(vp, pack_id); + return; + } +#endif + ptp->io_hdr.pack_id = pack_id; } @@ -247,6 +312,13 @@ set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_tag(vp, tag); + return; + } +#endif + ++ptp->in_err; tag = tag; /* dummy to silence compiler */ } @@ -257,6 +329,13 @@ set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_task_management(vp, tmf_code); + return; + } +#endif + ++ptp->in_err; tmf_code = tmf_code; /* dummy to silence compiler */ } @@ -266,6 +345,13 @@ set_scsi_pt_task_attr(struct sg_pt_base * vp, int attribute, int priority) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_task_attr(vp, attribute, priority); + return; + } +#endif + ++ptp->in_err; attribute = attribute; /* dummy to silence compiler */ priority = priority; /* dummy to silence compiler */ @@ -303,6 +389,12 @@ do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return do_iscsi_pt(vp, fd, time_secs, verbose); + } +#endif + if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; ptp->os_err = 0; @@ -339,6 +431,12 @@ get_scsi_pt_result_category(const struct sg_pt_base * vp) int dr_st = ptp->io_hdr.driver_status & SG_LIB_DRIVER_MASK; int scsi_st = ptp->io_hdr.status & 0x7e; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_result_category(vp); + } +#endif + if (ptp->os_err) return SCSI_PT_RESULT_OS_ERR; else if (ptp->io_hdr.host_status) @@ -360,6 +458,12 @@ get_scsi_pt_resid(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_resid(vp); + } +#endif + return ptp->io_hdr.resid; } @@ -368,6 +472,12 @@ get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_status_response(vp); + } +#endif + return ptp->io_hdr.status; } @@ -376,6 +486,12 @@ get_scsi_pt_sense_len(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_sense_len(vp); + } +#endif + return ptp->io_hdr.sb_len_wr; } @@ -384,6 +500,12 @@ get_scsi_pt_duration_ms(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_duration_ms(vp); + } +#endif + return ptp->io_hdr.duration; } @@ -392,6 +514,12 @@ get_scsi_pt_transport_err(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_transport_err(vp); + } +#endif + return (ptp->io_hdr.host_status << 8) + ptp->io_hdr.driver_status; } @@ -400,6 +528,12 @@ get_scsi_pt_os_err(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_os_err(vp); + } +#endif + return ptp->os_err; } @@ -416,6 +550,12 @@ get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, const char * driv_cp = "invalid"; const char * sugg_cp = "invalid"; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_transport_err_str(vp, max_b_len, b); + } +#endif + m = max_b_len; n = 0; if (hs) { @@ -451,6 +591,12 @@ get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) const struct sg_pt_linux_scsi * ptp = &vp->impl; const char * cp; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_os_err_str(vp, max_b_len, b); + } +#endif + cp = safe_strerror(ptp->os_err); strncpy(b, cp, max_b_len); if ((int)strlen(cp) >= max_b_len) @@ -567,6 +713,12 @@ scsi_pt_open_flags(const char * device_name, int flags, int verbose) { int fd; +#ifdef CONFIG_LIBISCSI + if (!strncmp(device_name, "iscsi://", 8)) { + return iscsi_pt_open_device(device_name, flags, verbose); + } +#endif + if (! bsg_major_checked) { bsg_major_checked = 1; find_bsg_major(verbose); @@ -589,6 +741,12 @@ scsi_pt_close_device(int device_fd) { int res; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return iscsi_pt_close_device(device_fd); + } +#endif + res = close(device_fd); if (res < 0) res = -errno; @@ -601,6 +759,12 @@ construct_scsi_pt_obj() { struct sg_pt_linux_scsi * ptp; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return construct_iscsi_pt_obj(); + } +#endif + ptp = (struct sg_pt_linux_scsi *) calloc(1, sizeof(struct sg_pt_linux_scsi)); if (ptp) { @@ -620,6 +784,12 @@ destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return destruct_iscsi_pt_obj(vp); + } +#endif + if (ptp) free(ptp); } @@ -629,6 +799,12 @@ clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return clear_iscsi_pt_obj(vp); + } +#endif + if (ptp) { memset(ptp, 0, sizeof(struct sg_pt_linux_scsi)); ptp->io_hdr.guard = 'Q'; @@ -647,6 +823,12 @@ set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_cdb(vp, cdb, cdb_len); + } +#endif + if (ptp->io_hdr.request) ++ptp->in_err; /* C99 has intptr_t instead of long */ @@ -660,6 +842,12 @@ set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_sense(vp, sense, max_sense_len); + } +#endif + if (ptp->io_hdr.response) ++ptp->in_err; memset(sense, 0, max_sense_len); @@ -674,6 +862,12 @@ set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_data_in(vp, dxferp, dxfer_len); + } +#endif + if (ptp->io_hdr.din_xferp) ++ptp->in_err; if (dxfer_len > 0) { @@ -689,6 +883,12 @@ set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp, { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return set_iscsi_pt_data_out(vp, dxferp, dxfer_len); + } +#endif + if (ptp->io_hdr.dout_xferp) ++ptp->in_err; if (dxfer_len > 0) { @@ -702,6 +902,13 @@ set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_packet_id(vp, pack_id); + return; + } +#endif + ptp->io_hdr.spare_in = pack_id; } @@ -710,6 +917,13 @@ set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_tag(vp, tag); + return; + } +#endif + ptp->io_hdr.request_tag = tag; } @@ -719,6 +933,13 @@ set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_task_management(vp, tmf_code); + return; + } +#endif + ptp->io_hdr.subprotocol = 1; /* SCSI task management function */ ptp->tmf_request[0] = (unsigned char)tmf_code; /* assume it fits */ ptp->io_hdr.request = (__u64)(long)(&(ptp->tmf_request[0])); @@ -730,6 +951,12 @@ set_scsi_pt_task_attr(struct sg_pt_base * vp, int attribute, int priority) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + set_iscsi_pt_task_attr(vp, attribute, priority); + return; + } +#endif ptp->io_hdr.request_attr = attribute; ptp->io_hdr.request_priority = priority; } @@ -756,6 +983,12 @@ get_scsi_pt_resid(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_resid(vp); + } +#endif + return ptp->io_hdr.din_resid; } @@ -764,6 +997,12 @@ get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_status_response(vp); + } +#endif + return ptp->io_hdr.device_status; } @@ -772,6 +1011,12 @@ get_scsi_pt_sense_len(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_sense_len(vp); + } +#endif + return ptp->io_hdr.response_len; } @@ -780,6 +1025,12 @@ get_scsi_pt_duration_ms(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_duration_ms(vp); + } +#endif + return ptp->io_hdr.duration; } @@ -788,6 +1039,12 @@ get_scsi_pt_transport_err(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_transport_err(vp); + } +#endif + return ptp->io_hdr.transport_status; } @@ -805,6 +1062,12 @@ get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, const char * driv_cp = "invalid"; const char * sugg_cp = "invalid"; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_transport_err_str(vp, max_b_len, b); + } +#endif + m = max_b_len; n = 0; if (hs) { @@ -841,6 +1104,12 @@ get_scsi_pt_result_category(const struct sg_pt_base * vp) int dr_st = ptp->io_hdr.driver_status & SG_LIB_DRIVER_MASK; int scsi_st = ptp->io_hdr.device_status & 0x7e; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_result_category(vp); + } +#endif + if (ptp->os_err) return SCSI_PT_RESULT_OS_ERR; else if (ptp->io_hdr.transport_status) @@ -862,6 +1131,12 @@ get_scsi_pt_os_err(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_os_err(vp); + } +#endif + return ptp->os_err; } @@ -871,6 +1146,12 @@ get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) const struct sg_pt_linux_scsi * ptp = &vp->impl; const char * cp; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return get_iscsi_pt_os_err_str(vp, max_b_len, b); + } +#endif + cp = safe_strerror(ptp->os_err); strncpy(b, cp, max_b_len); if ((int)strlen(cp) >= max_b_len) @@ -944,6 +1225,12 @@ do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose) { struct sg_pt_linux_scsi * ptp = &vp->impl; +#ifdef CONFIG_LIBISCSI + if (iscsi) { + return do_iscsi_pt(vp, fd, time_secs, verbose); + } +#endif + if (! bsg_major_checked) { bsg_major_checked = 1; find_bsg_major(verbose);