--- open-iscsi-2.0.870~rc3.orig/Changelog
+++ open-iscsi-2.0.870~rc3/Changelog
@@ -1,3 +1,12 @@
 open-iscsi-2.0-869.1
 - Fix nop out timer. If the timer wakes up at the exact same time we were
 supposed to check the transport we mistakenly drop the connection.
+
+open-iscsi-2.0-869.2
+- Fix nop out interval. If we send a ping to test the connection, we set
+the next timer for the ping timeout. If we get a response quickly and
+the ping timeout is long we will miss recv tmo test intervals.
+
+This is not fatal. It will only cause detection of connection errors to take
+up to (2 * noop_timeout + noop_interval) seconds to detect problems instead of
+(noop_timeout + noop_interval) seconds.
--- open-iscsi-2.0.870~rc3.orig/debian/README.Debian
+++ open-iscsi-2.0.870~rc3/debian/README.Debian
@@ -1,44 +1,62 @@
-linux-iscsi for Debian
+open-iscsi for Debian
 -----------------------------------
 
-The linux-iscsi package contains the userspace portion the Linux iSCSI project.
-It has a dependency on the linux-iscsi-modules package, which needs to be built from the linux-iscsi-modules-source against the specific kernel version running
-on your system.
-
-Building
---------
-Modules cannot be built against the kernel-headers alone.  You will need
-to extract and configure your kernel tree, then use the make-kpkg command
-(from the kernel-package package) to build a new kernel and modules.
-See the make-kpkg man page, particularly the modules-image section.  The
-following example shows how to build the linux-iscsi-modules package; just
-substitute the appropriate version strings.  Follow these instructions 
-(as root) in order to build the linux-iscsi-modules package for your kernel:
-
-dpkg -i linux-iscsi-modules-source_5.0.0.0.3rc6-363_all.deb
-cd /usr/src
-rm -rf modules/linux-iscsi
-tar jxpvf linux-iscsi-modules-source.tar.bz2
-cd linux-2.6.11.11 (or your appropriate version)
-make-kpkg --added-modules linux-iscsi modules-image
-
-By default, make-kpkg will assume /usr/src/linux-iscsi-modules-source.tar.bz2 
-has been extracted under /usr/src.  However, that also requires building as 
-root.  If you want to do the build as a non-root user, you need to use the 
-MODULE_LOC environment variable.  For example:
-
-cd ~/builds
-export MODULES_LOC=$PWD/modules
-tar jxpvf /usr/src/linux-iscsi-modules-source.tar.bz2
-cd ~/builds/linux-2.6.11.11 (or your appropriate version)
-make-kpkg --added-modules linux-iscsi modules-image
-
-Installing
-----------
+The open-iscsi package contains the userspace portion the Open iSCSI
+project. It depends on iSCSI modules which are already present in
+current (>= 2.6.18) kernels.
+
+WARNING!  Please unmount iSCSI-backed filesystems before upgrading the
+open-iscsi package, as they are not automatically unmounted and the
+restart of iscsid will break the iscsi block devices and prevent any
+outstanding I/O from completing (and require a remount before the
+filesystems will work again).
 
-Once you have built the linux-iscsi-modules package, you can install the
-binaries:
+Automatic login and mount
+-----------------------------------
+
+If you want to automatically connect to all discovered targets, change
+the following line:
+node.startup = manual
+to:
+node.startup = automatic
+
+If you want to automatically mount filesystems on iSCSI volumes,
+change node.startup to automatic as above, and also add _netdev to
+the mount options (in /etc/fstab) for the filesystems you would like
+to mount automatically when open-iscsi is started.
 
-dpkg -i linux-iscsi_5.0.0.0.3rc6-363_i386.deb linux-iscsi-modules-2.6.11.11_5.0.0.0.3rc6-363+10.00.Custom_i386.deb
+Root on iSCSI
+-----------------------------------
 
- -- Chad Tindel <chad.tindel@hp.com>, Mon, 30 May 2005 15:17:53 -0600
+The Debian open-iscsi package now supports root filesystem on iSCSI.  Support
+for this is controlled by the existence of the /etc/iscsi/iscsi.initramfs file.
+There are two ways to include iSCSI boot support in your initramfs:
+
+1) Touch /etc/iscsi/iscsi.initramfs and provide options on the command line.
+   This provides flexibility, but if passwords are used, is not very secure.
+   Available boot line options:
+   	iscsi_initiator, iscsi_target_name, iscsi_target_ip,
+	iscsi_target_port, iscsi_target_group, iscsi_username,
+	iscsi_password, iscsi_in_username, iscsi_in_password
+   See iscsistart --help for a description of each option
+
+2) Provide iSCSI option in /etc/iscsi/iscsi.initramfs.
+   Available options:
+   	ISCSI_INITIATOR, ISCSI_TARGET_NAME, ISCSI_TARGET_IP,
+	ISCSI_TARGET_PORT, ISCSI_TARGET_GROUP, ISCSI_USERNAME
+	ISCSI_PASSWORD, ISCSI_IN_USERNAME, ISCSI_IN_PASSWORD
+
+   Example Syntax:
+
+   ISCSI_TARGET_NAME=iqn.2008-01.com.example:storage.foo
+   ISCSI_TARGET_IP=192.168.1.1
+
+   Remember to set proper permissions if username/passwords are used.
+
+If both facilities are used, command line options overwrite iscsi.initramfs
+options.  Also remember that iSCSI requires a working network device, so
+you'll need to get networking started via an ip= boot option (ex. ip=dhcp).
+You also won't want to restart the device during boot, so set it to manual
+mode in /etc/networking/interfaces.  Leave BOOT=local set in
+/etc/initramfs-tools/initramfs.conf and provide a root=/dev/sd* device as
+the iSCSI disk will look like a local disk.
--- open-iscsi-2.0.870~rc3.orig/debian/changelog
+++ open-iscsi-2.0.870~rc3/debian/changelog
@@ -1,6 +1,140 @@
-linux-iscsi (5.0.0.0.3rc6-363) unstable; urgency=low
+open-iscsi (2.0.870~rc3-0.3~bpo40+1) etch-backports; urgency=low
 
-  * Initial Release.
+  * Rebuild for etch.
 
- -- Chad Tindel <chad.tindel@hp.com>  Mon, 30 May 2005 15:17:53 -0600
+ -- Norbert Tretkowski <nobse@debian.org>  Sat,  8 Nov 2008 10:14:56 +0100
+
+open-iscsi (2.0.870~rc3-0.3) unstable; urgency=low
+
+  * Non-maintainer upload.
+  * Do not exit with return code 1 in init script, because it breaks
+    upgrades and is a policy violation (Closes: #503070)
+
+ -- Patrick Schoenfeld <schoenfeld@debian.org>  Mon, 27 Oct 2008 10:21:17 +0100
+
+open-iscsi (2.0.870~rc3-0.2) unstable; urgency=low
+
+  * Non-maintainer upload.
+  * Drop patch from iscsistart.c which breaks booting from iscsi.
+    (closes: #499508)
+  * Drop patch from version.h which adds an outdated upstream version
+    number.
+
+ -- Norbert Tretkowski <nobse@debian.org>  Fri, 10 Oct 2008 10:46:56 +0200
+
+open-iscsi (2.0.870~rc3-0.1) unstable; urgency=low
+
+  * Non-maintainer upload.
+  * New upstream release
+    - Adds support for Linux 2.6.26 (Closes: #499508)
+  * Fix ">&" redirection bashism in open-iscsi initscript.
+
+ -- Chris Lamb <lamby@debian.org>  Tue, 30 Sep 2008 21:40:27 +0100
+
+open-iscsi (2.0.869.2-2.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Fix bashism in debian/rules (Closes: #484427)
+    - Move upstream URL to Homepage field.
+    - Bump Standards-Version to 3.8.0.
+
+ -- Chris Lamb <chris@chris-lamb.co.uk>  Fri, 11 Jul 2008 23:20:18 +0100
+
+open-iscsi (2.0.869.2-2) unstable; urgency=low
+
+  * Revert if-up.d approach for logging into automatic targets; just
+    start open-iscsi at rcS.d/S45, and mount _netdev filesystems when
+    open-iscsi is started.
+  * Call udevsettle before mounting
+
+ -- Philipp Hug <debian@hug.cx>  Mon, 12 May 2008 12:48:49 +0200
+
+open-iscsi (2.0.869.2-1) unstable; urgency=low
+
+  * New upstream release
+
+ -- Philipp Hug <debian@hug.cx>  Mon, 12 May 2008 11:56:30 +0200
+
+open-iscsi (2.0.869~rc4-1) experimental; urgency=low
+
+  * init script: If /sys is not mounted return without error
+    (Closes: #470434, #423368)
+  * Merged changes by Andrew Moise <chops@demiurgestudios.com>
+  * Adding Andrew as Co-Maintainer
+  * New upstream release (Closes: #474167)
+  * Added flex and bison build-depends
+  * Fixed up init scripts to attempt to handle automatic mounting and
+    unmounting properly (Closes: #423851, #438542)
+  * Added /etc/network/if-up.d/000open-iscsi to start automatic targets
+  * Parameterized /etc/iscsi/initiatorname.iscsi in init script,
+    correcting one place where it still said /etc/initiatorname.iscsi
+  * Updated README.Debian
+  * Include iscsistart for use in initramfs (Closes: #419408)
+  * Add initramfs scripts to make iSCSI root easy
+  * Based on patch by Guido Guenther <agx@sigxcpu.org>
+
+ -- Philipp Hug <debian@hug.cx>  Sat, 12 Apr 2008 15:53:12 +0200
+
+open-iscsi (2.0.865-1) unstable; urgency=low
+
+  * New upstream release
+  * Removed iscsi-iname patch as it's now included in upstream
+  * Moved initiatorname.iscsi to /etc/iscsi/initiatorname.iscsi
+
+ -- Philipp Hug <debian@hug.cx>  Sat, 16 Jun 2007 12:31:05 +0200
+
+open-iscsi (2.0.730-1) unstable; urgency=low
+
+  * Reverted to upstream init script + patches (Closes: #397363 #401579)
+  * Removed libdb dependency
+  * Create /etc/iscsi
+  * Integrated NMU changes from Martin Zobel-Helas
+     + New Upstream Release (Closes: #397636)
+     + Made /var/lib/open-iscsi 0700 (Closes: #398733)
+     + change #define INITIATOR_NAME_FILE to /etc/initiatorname.iscsi
+       in usr/initiator.h
+     + Fix package description (Closes: #380162)
+
+ -- Philipp Hug <debian@hug.cx>  Wed,  6 Dec 2006 20:22:30 +0100
+
+open-iscsi (1.0.485-4) unstable; urgency=low
+
+  * Removed bash-ism from init script
+  * Added hint about autostart to README.Debian
+  * Improved description a bit (Closes: #380162)
+
+ -- Philipp Hug <debian@hug.cx>  Mon, 21 Aug 2006 19:55:40 +0200
+
+open-iscsi (1.0.485-3) unstable; urgency=low
+
+  * Added description to man page
+
+ -- Philipp Hug <debian@hug.cx>  Sun, 23 Jul 2006 19:08:48 +0200
+
+open-iscsi (1.0.485-2) unstable; urgency=low
+
+  * Moved package to unstable
+  * Removed unused section in control
+  * Updated Standards-Version to 3.7.2.1
+  * Added INIT INFO section to init script to make it lsb compliant
+  * Removed unusued lines in rules
+  * Added man page for iscsi-iname
+
+ -- Philipp Hug <debian@hug.cx>  Sat, 22 Jul 2006 19:45:35 +0200
+
+open-iscsi (1.0.485-1) experimental; urgency=low
+
+  * Install iscsid.conf in /etc/iscsid.conf instead of /etc/iscsid.conf-example
+
+ -- Philipp Hug <debian@hug.cx>  Tue, 27 Jun 2006 14:42:20 +0200
+
+open-iscsi (1.0.485-0unreleased) dapper; urgency=low
+
+  * Initial Release (closes: Bug#333695)
+  * Updated init script
+  * Automatically generate iscsi initiator name
+  * Use Debian specific initator name prefix
+  * Put database into /var/lib/open-iscsi
+
+ -- Philipp Hug <debian@hug.cx>  Mon,  6 Mar 2006 19:20:17 +0000
 
--- open-iscsi-2.0.870~rc3.orig/debian/control
+++ open-iscsi-2.0.870~rc3/debian/control
@@ -1,27 +1,23 @@
-Source: linux-iscsi
+Source: open-iscsi
 Section: net
 Priority: optional
-Maintainer: Chad Tindel <chad.tindel@hp.com>
-Build-Depends: debhelper (>= 4.0.0), libdb4.3, libdb4.3-dev
-Standards-Version: 3.6.1
+Maintainer: Philipp Hug <debian@hug.cx>
+Uploaders: Andrew Moise <chops@demiurgestudios.com>
+Build-Depends: debhelper (>= 4.0.0), bzip2, bison, flex
+Standards-Version: 3.8.0
+Homepage: http://www.open-iscsi.org/
 
-Package: linux-iscsi
+Package: open-iscsi
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, linux-iscsi-modules
-Description: high performance, transport independent implementation of RFC3720. 
- linux-iscsi is a high performance, transport independent, implementation of 
- RFC3720.
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: High performance, transport independent iSCSI implementation
+ iSCSI is a network protocol standard that allows the use of the SCSI protocol
+ over TCP/IP networks.  This implementation follows RFC3720.
 
-#Package: linux-iscsi
+#Package: linux-iscsi-modules-source
 #Architecture: all
-#Description: Documentation for linux-iscsi
-#linux-iscsi is a high performance, transport independent, implementation of 
-#RFC3720.
-
-Package: linux-iscsi-modules-source
-Architecture: all
-Depends: ${shlibs:Depends}, ${misc:Depends}, module-assistant, debhelper (>= 4.0.0), bzip2
-Description: Source Code for the Linux iSCSI Kernel Modules
- Along with make-kpkg, this package maybe used to build a linux-iscsi-modules 
- package for a kernel-image package.
+#Depends: ${shlibs:Depends}, ${misc:Depends}, module-assistant, debhelper (>= 4.0.0), bzip2
+#Description: Source Code for the Linux iSCSI Kernel Modules
+# Along with make-kpkg, this package maybe used to build a linux-iscsi-modules 
+# package for a kernel-image package.
 
--- open-iscsi-2.0.870~rc3.orig/debian/control.modules.in
+++ open-iscsi-2.0.870~rc3/debian/control.modules.in
@@ -1,13 +1,13 @@
 Source: linux-iscsi-modules
 Section: net
 Priority: optional
-Maintainer: Chad Tindel <chad.tindel@hp.com>
+Maintainer: Philipp Hug <debian@hug.cx>
 Build-Depends: debhelper (>> 4.1.0), bzip2
 Standards-Version: 3.6.1
 
 Package: linux-iscsi-modules-_KVERS_
 Architecture: any
-Depends: modutils, linux-iscsi
+Depends: modutils, open-iscsi
 Provides: linux-iscsi-modules
 Description: Linux Kernel Driver Modules for Linux iSCSI (kernel _KVERS_)
  This is a Linux driver for iSCSI initiator functionality.
--- open-iscsi-2.0.870~rc3.orig/debian/copyright
+++ open-iscsi-2.0.870~rc3/debian/copyright
@@ -1,9 +1,11 @@
-This package was debianized by Chad Tindel <chad.tindel@hp.com> on
-Mon, 30 May 2005 15:17:53 -0600.
+This package was debianized by Philipp Hug <debian@hug.cx> on
+Tue, 07 Mar 2005 01:22:53 +0100.
 
-It was downloaded from http://sourceforge.net/projects/linux-iscsi
+Based on linux-iscsi debianization from Chad Tindel <chad.tindel@hp.com>
 
-Copyright Holder: Dmitry Yusupov <dima@neterion.com>
+It was downloaded from http://www.open-iscsi.org/
+
+Copyright Holder: Dmitry Yusupov <dima@neterion.com> and others.
 
 License:
 
--- open-iscsi-2.0.870~rc3.orig/debian/dirs
+++ open-iscsi-2.0.870~rc3/debian/dirs
@@ -1,3 +1,9 @@
 usr/bin
 usr/sbin
+var/lib/open-iscsi
 etc/init.d
+etc
+etc/iscsi
+etc/network/if-up.d
+usr/share/initramfs-tools/hooks/
+usr/share/initramfs-tools/scripts/local-top/
--- open-iscsi-2.0.870~rc3.orig/debian/docs
+++ open-iscsi-2.0.870~rc3/debian/docs
@@ -1,4 +1 @@
 README
-COPYING
-THANKS
-TODO
--- open-iscsi-2.0.870~rc3.orig/debian/rules
+++ open-iscsi-2.0.870~rc3/debian/rules
@@ -19,6 +19,7 @@
 
 
 CFLAGS = -Wall -g
+export OPTFLAGS =-DDISCOVERY_FILE=\"/var/lib/open-iscsi/discovery\" -DNODE_FILE=\"/var/lib/open-iscsi/node\"
 
 ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
 	CFLAGS += -O0
@@ -35,13 +36,15 @@
 
 
 #Architecture 
-build: build-arch build-indep
+build: build-arch
 
 build-arch: build-arch-stamp
 build-arch-stamp: configure-stamp 
 
 	# Add here commands to compile the arch part of the package.
+	$(MAKE) -C utils/fwparam_ibft
 	$(MAKE) -C usr
+	$(MAKE) -C utils
 
 	touch build-arch-stamp
 
@@ -55,16 +58,21 @@
 clean:
 	dh_testdir
 	dh_testroot
-	rm -f build-arch-stamp build-indep-stamp #CONFIGURE-STAMP#
+	rm -f build-arch-stamp build-indep-stamp configure-stamp
 
 	# Add here commands to clean up after the build process.
+	$(MAKE) -C utils/fwparam_ibft clean
 	$(MAKE) -C usr clean
+	$(MAKE) -C utils clean
 	rm -rf modules
 
 	dh_clean 
 
-install: install-indep install-arch
+install: install-arch
+# disabled kernel module package for now because source is already in debian stock kernelsy
 install-indep:
+
+disabled-install-indep:
 	dh_testdir
 	dh_testroot
 	dh_clean -k -i 
@@ -79,7 +87,7 @@
 	tar --exclude=debian -c * | (cd modules/linux-iscsi && tar xv)
 
         # copy all relevant debian/ files
-	cp debian/{compat,copyright} modules/linux-iscsi/debian
+	cp debian/compat debian/copyright modules/linux-iscsi/debian
 	cat debian/changelog | sed -e 's/linux-iscsi/linux-iscsi-modules/' > modules/linux-iscsi/debian/changelog
 	cp debian/*.modules.in modules/linux-iscsi/debian
 	install -m755 debian/rules.modules modules/linux-iscsi/debian/rules
@@ -100,12 +108,20 @@
 	dh_installdirs -s
 
 	# Add here commands to install the arch part of the package into 
-	# debian/linux-iscsi.
-	install -m 755 usr/iscsiadm $(CURDIR)/debian/linux-iscsi/usr/bin
-	install -m 755 usr/iscsid $(CURDIR)/debian/linux-iscsi/usr/sbin
-	install -m 644 etc/iscsid.conf $(CURDIR)/debian/linux-iscsi/etc/iscsid.conf.example
-	install -m 755 etc/initd/initd.debian $(CURDIR)/debian/linux-iscsi/etc/init.d/iscsid
-	make clean
+	# debian/open-iscsi.
+	install -m 755 usr/iscsiadm $(CURDIR)/debian/open-iscsi/usr/bin
+	install -m 755 usr/iscsid $(CURDIR)/debian/open-iscsi/usr/sbin
+	install -m 755 usr/iscsistart $(CURDIR)/debian/open-iscsi/usr/sbin
+	install -m 755 utils/iscsi_discovery $(CURDIR)/debian/open-iscsi/usr/sbin
+	install -m 755 utils/iscsi-iname $(CURDIR)/debian/open-iscsi/usr/sbin
+	install -m 644 debian/initiatorname.iscsi $(CURDIR)/debian/open-iscsi/etc/iscsi/initiatorname.iscsi
+	install -m 644 etc/iscsid.conf $(CURDIR)/debian/open-iscsi/etc/iscsi
+
+	# initramfs stuff
+	install -m 755 debian/extra/initramfs.hook \
+		$(CURDIR)/debian/open-iscsi/usr/share/initramfs-tools/hooks/iscsi
+	install -m 755 debian/extra/initramfs.local-top \
+		$(CURDIR)/debian/open-iscsi/usr/share/initramfs-tools/scripts/local-top/iscsi
 
 	dh_install -s
 
@@ -118,22 +134,13 @@
 	dh_installchangelogs 
 	dh_installdocs
 	dh_installexamples
-#	dh_installmenu
-#	dh_installdebconf	
-#	dh_installlogrotate	
-#	dh_installemacsen
-#	dh_installpam
-#	dh_installmime
-#	dh_installinit
-#	dh_installcron
-#	dh_installinfo
+	dh_installinit -u 'start 45 S . stop 81 0 6 .'
+	dh_installinit -u 'stop 80 0 6 .' --no-start --name=umountiscsi.sh
 	dh_installman
 	dh_link
 	dh_strip
 	dh_compress 
 	dh_fixperms
-#	dh_perl
-#	dh_python
 	dh_makeshlibs
 	dh_installdeb
 	dh_shlibdeps
@@ -142,7 +149,7 @@
 	dh_builddeb
 # Build architecture independant packages using the common target.
 binary-indep: build-indep install-indep
-	$(MAKE) -f debian/rules DH_OPTIONS=-i binary-common
+#	$(MAKE) -f debian/rules DH_OPTIONS=-i binary-common
 
 # Build architecture dependant packages using the common target.
 binary-arch: build-arch install-arch
--- open-iscsi-2.0.870~rc3.orig/debian/open-iscsi.postinst
+++ open-iscsi-2.0.870~rc3/debian/open-iscsi.postinst
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+update_initramfs()
+{
+    if [ -x /usr/sbin/update-initramfs ] && \
+       [ -e /etc/initramfs-tools/initramfs.conf ] && \
+       [ -e /etc/iscsi/iscsi.initramfs ]; then
+        update-initramfs -u
+    fi
+}
+
+case "$1" in
+    configure)
+	# Move old configuration from /etc/ into /etc/iscsi/
+	# But only if configuration in /etc/iscsi is untouched
+	
+        if [ -f /etc/initiatorname.iscsi ] ; then
+            if grep -q "^GenerateName=yes" /etc/iscsi/initiatorname.iscsi ; then
+                mv /etc/initiatorname.iscsi /etc/iscsi/initiatorname.iscsi
+		chmod 600 /etc/iscsi/initiatorname.iscsi
+	    fi
+	fi
+	
+	if [ -d /var/lib/open-iscsi ]; then
+		chmod 700   /var/lib/open-iscsi
+	else
+		mkdir /var/lib/open-iscsi
+		chmod 700   /var/lib/open-iscsi
+	fi
+
+	update_initramfs
+    ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+    ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+    ;;
+esac
+
+#DEBHELPER#
+
+exit 0
--- open-iscsi-2.0.870~rc3.orig/debian/initiatorname.iscsi
+++ open-iscsi-2.0.870~rc3/debian/initiatorname.iscsi
@@ -0,0 +1 @@
+GenerateName=yes
--- open-iscsi-2.0.870~rc3.orig/debian/open-iscsi.init
+++ open-iscsi-2.0.870~rc3/debian/open-iscsi.init
@@ -0,0 +1,167 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides:          iscsi
+# Required-Start:    $local_fs
+# Required-Stop:     $remote_fs sendsigs networking
+# Default-Start:     S
+# Default-Stop:      0 6
+# Short-Description: Starts and stops the iSCSI initiator services and logs in to default targets
+### END INIT INFO
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/sbin/iscsid
+ADM=/usr/bin/iscsiadm
+PIDFILE=/var/run/iscsid.pid
+NAMEFILE=/etc/iscsi/initiatorname.iscsi
+
+[ -x "$DAEMON" ] || exit 0
+
+. /lib/lsb/init-functions
+
+if [ ! -d /sys/class/ ]; then
+  log_failure_msg "iSCSI requires a mounted sysfs, not started."
+  exit 0
+fi
+
+nodestartup_re='s/^node\.conn\[0]\.startup[ 	]*=[ 	]*//p'
+
+RETVAL=0
+
+sanitychecks() {
+        # Do sanity checks before we start..
+        if [ ! -e $CONFIGFILE ]; then
+                echo
+                echo "Error: configuration file $CONFIGFILE is missing!"
+                echo "The iSCSI driver has not been correctly installed and cannot start."
+                echo
+                exit 1
+        elif [ -s $PIDFILE ] && kill -0 `head -1 $PIDFILE` >/dev/null ; then
+		echo
+                echo "iSCSI daemon already running"
+                echo
+                exit 0
+        fi
+
+        if [ ! -f $NAMEFILE ] ; then
+            echo
+            echo "Error: InitiatorName file $NAMEFILE is missing!"
+            echo "The iSCSI driver has not been correctly installed and cannot start."
+            echo
+            exit 1
+        fi
+
+        # see if we need to generate a unique iSCSI InitiatorName
+        # this should only happen if the
+        if grep -q "^GenerateName=yes" $NAMEFILE ; then
+            if [ ! -x /usr/sbin/iscsi-iname ] ; then
+                echo "Error: /usr/sbin/iscsi-iname does not exist, driver was not successfully installed"
+                exit 1;
+            fi
+            # Generate a unique InitiatorName and save it
+            INAME=`/usr/sbin/iscsi-iname -p iqn.1993-08.org.debian:01`
+            if [ "$INAME" != "" ] ; then
+                echo "## DO NOT EDIT OR REMOVE THIS FILE!" > $NAMEFILE
+                echo "## If you remove this file, the iSCSI daemon will not start." >> $NAMEFILE
+                echo "## If you change the InitiatorName, existing access control lists" >> $NAMEFILE
+                echo "## may reject this initiator.  The InitiatorName must be unique">> $NAMEFILE
+                echo "## for each iSCSI initiator.  Do NOT duplicate iSCSI InitiatorNames." >> $NAMEFILE
+                printf "InitiatorName=$INAME\n"  >> $NAMEFILE
+                chmod 600 $NAMEFILE
+            else
+                echo "Error: failed to generate an iSCSI InitiatorName, driver cannot start."
+                echo
+                exit 1;
+            fi
+        fi
+
+        # make sure there is a valid InitiatorName for the driver
+        if ! grep -q "^InitiatorName=[^ \t\n]" $NAMEFILE ; then
+            echo
+            echo "Error: $NAMEFILE does not contain a valid InitiatorName."
+            echo "The iSCSI driver has not been correctly installed and cannot start."
+            echo
+            exit 1
+        fi
+}
+
+start() {
+	log_daemon_msg "Starting iSCSI initiator service" "iscsid"
+	sanitychecks
+	modprobe -q iscsi_tcp 2>/dev/null || :
+	modprobe -q ib_iser 2>/dev/null || :
+	start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON
+	RETVAL=$?
+	log_end_msg $RETVAL
+
+	starttargets
+
+	udevsettle
+
+	log_daemon_msg "Mounting network filesystems"
+	MOUNT_RESULT=1
+	if mount -a -O _netdev >/dev/null 2>&1; then
+		MOUNT_RESULT=0
+		break
+	fi
+	log_end_msg $MOUNT_RESULT
+}
+
+starttargets() {
+	log_daemon_msg "Setting up iSCSI targets"
+	echo
+	$ADM -m node --loginall=automatic
+	log_end_msg 0
+}
+
+stoptargets() {
+	log_daemon_msg "Disconnecting iSCSI targets"
+	sync
+	# only logout if daemon is running, iscsiadm hangs otherwise
+        if [ -s $PIDFILE ] && kill -0 `head -1 $PIDFILE` >/dev/null ; then
+		$ADM -m node --logoutall=all
+        fi
+
+	log_end_msg 0
+}
+
+stop() {
+	stoptargets
+	log_daemon_msg "Stopping iSCSI initiator service"
+	start-stop-daemon --stop --quiet --pidfile $PIDFILE --signal KILL --exec $DAEMON
+	rm -f $PIDFILE
+	modprobe -r ib_iser 2>/dev/null
+	modprobe -r iscsi_tcp 2>/dev/null
+	log_end_msg 0
+}
+
+restart() {
+	stop
+	start
+}
+
+restarttargets() {
+	stoptargets
+	starttargets
+}
+
+status() {
+	#XXX FIXME: what to do here?
+	#status iscsid
+	# list active sessions
+	echo Current active iSCSI sessions:
+	$ADM -m session
+}
+
+case "$1" in
+	start|starttargets|stop|stoptargets|restart|restarttargets|status)
+		$1
+		;;
+	force-reload)
+		restart
+		;;
+	*)
+		echo "Usage: $0 {start|stop|restart|force-reload|status}"
+		exit 1
+		;;
+esac
+exit $RETVAL
--- open-iscsi-2.0.870~rc3.orig/debian/iscsi-iname.8
+++ open-iscsi-2.0.870~rc3/debian/iscsi-iname.8
@@ -0,0 +1,19 @@
+.TH "iscsi-iname" "8" "July 2006" "open-iscsi" "Debian Distribution" 
+.PP 
+.SH "NAME" 
+iscsi-iname \- iSCSI node name generation utility
+.PP 
+.SH "SYNOPSIS" 
+.PP 
+iscsi-iname
+.PP 
+.SH "DESCRIPTION"
+.PP
+iscsi-iname generates a unique iSCSI node name on every invocation
+.PP
+.SH "BUGS" 
+Contact Philipp Hug <debian@hug.cx>, for any bugs with this program
+.PP 
+.SH "AUTHOR" 
+This manpage was written by Philipp Hug <debian@hug.cx>, 2006
+.PP 
--- open-iscsi-2.0.870~rc3.orig/debian/iscsistart.8
+++ open-iscsi-2.0.870~rc3/debian/iscsistart.8
@@ -0,0 +1,54 @@
+.TH "iscsistart" "8" "February 2008" "open-iscsi" "Debian Distribution" 
+.PP 
+.SH "NAME" 
+iscsistart \- iSCSI boot utility
+.PP 
+.SH "SYNOPSIS" 
+.PP 
+iscsistart
+.PP 
+.SH "DESCRIPTION"
+.PP
+iscsistart is used for attaching to iSCSI targets during bootup.
+.PP
+.SH "OPTIONS"
+.TP
+\fB\-i\fR, \fB\-\-initiatorname=name\fR
+set InitiatorName to name (Required)
+.TP
+\fB\-t\fR, \fB\-\-targetname=name\fR
+set TargetName to name (Required)
+.TP
+\fB\-g\fR, \fB\-\-tgpt=N\fR
+set target portal group tag to N (Required)
+.TP
+\fB\-a\fR, \fB\-\-address=A.B.C.D\fR
+set IP addres to A.B.C.D (Required)
+.TP
+\fB\-p\fR, \fB\-\-port=N\fR
+set port to N (Default 3260)
+.TP
+\fB\-u\fR, \fB\-\-username=N\fR
+set username to N (optional)
+.TP
+\fB\-w\fR, \fB\-\-password=N\fR
+set password to N (optional)
+.TP
+\fB\-U\fR, \fB\-\-username_in=N\fR
+set incoming username to N (optional)
+.TP
+\fB\-W\fR, \fB\-\-password_in=N\fR
+set incoming password to N (optional)
+.TP
+\fB\-d\fR, \fB\-\-debug debuglevel\fR
+print debugging information 
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+display this help and exit
+.TP
+\fB\-v\fR, \fB\-\-version\fR
+display version and exit
+.PP
+.SH "AUTHOR" 
+This manpage was written by Alex Williamson <alex.williamson@hp.com>, 2008
+.PP 
--- open-iscsi-2.0.870~rc3.orig/debian/manpages
+++ open-iscsi-2.0.870~rc3/debian/manpages
@@ -0,0 +1,5 @@
+doc/iscsi_discovery.8
+doc/iscsid.8
+doc/iscsiadm.8
+debian/iscsistart.8
+debian/iscsi-iname.8
--- open-iscsi-2.0.870~rc3.orig/debian/umountiscsi.sh.init
+++ open-iscsi-2.0.870~rc3/debian/umountiscsi.sh.init
@@ -0,0 +1,51 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides:          stop-open-iscsi.sh
+# Required-Start:
+# Required-Stop:     $remote_fs sendsigs open-iscsi
+# Default-Start:
+# Default-Stop:      0 6
+# Short-Description: Unmounts iSCSI filesystems and stops iSCSI services
+### END INIT INFO
+
+. /lib/init/vars.sh
+
+. /lib/lsb/init-functions
+
+do_stop () {
+    log_daemon_msg "Unmounting iscsi-backed filesystems"
+
+    for HOST_DIR in /sys/devices/platform/host*; do
+	if ! [ -d $HOST_DIR/iscsi_host* ]; then
+	    continue
+	fi
+	for TARGET_DIR in $HOST_DIR/session*/target*/*\:*; do
+	    for BLOCK_FILE in $TARGET_DIR/block\:*; do
+		BLOCK_DEV=`echo "$BLOCK_FILE" | sed 's/.*block\://'`
+		DOS_PARTITIONS="`awk "/^\/dev\/$BLOCK_DEV/ { print \\$2; }" < /proc/mounts`"
+		for DEVICE in $DOS_PARTITIONS; do
+		    log_progress_msg $DEVICE
+		    umount $DEVICE
+		done
+	    done
+	done
+    done
+    log_end_msg 0
+}
+
+case "$1" in
+    start)
+	# No-op
+        ;;
+    restart|reload|force-reload)
+	echo "Error: argument '$1' not supported" >&2
+	exit 3
+	;;
+    stop|"")
+        do_stop
+	;;
+    *)
+        echo "Usage: stop-open-iscsi.sh [start|stop]" >&2
+	exit 3
+	;;
+esac
--- open-iscsi-2.0.870~rc3.orig/debian/extra/initramfs.local-top
+++ open-iscsi-2.0.870~rc3/debian/extra/initramfs.local-top
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+PREREQ=""
+
+prereqs()
+{
+	echo "$PREREQ"
+}
+
+case $1 in
+# get pre-requisites
+prereqs)
+	prereqs
+	exit 0
+	;;
+esac
+
+do_iscsi_login ()
+{
+	# Bring in the main config
+	. /conf/initramfs.conf
+	for conf in conf/conf.d/*; do
+		[ -f ${conf} ] && . ${conf}
+	done
+	. /scripts/functions
+
+	configure_networking
+
+	modprobe iscsi_tcp
+	modprobe crc32c
+
+	if [ -z $ISCSI_INITIATOR ]; then
+		. /etc/initiatorname.iscsi
+		ISCSI_INITIATOR=$InitiatorName
+	fi
+
+	if [ -z $ISCSI_TARGET_PORT ]; then
+		ISCSI_TARGET_PORT=3260
+	fi
+
+	if [ -z $ISCSI_TARGET_GROUP ]; then
+		ISCSI_TARGET_GROUP=1
+	fi
+
+	iscsistart -i $ISCSI_INITIATOR -t $ISCSI_TARGET_NAME	\
+		   -g $ISCSI_TARGET_GROUP -a $ISCSI_TARGET_IP	\
+		   -p $ISCSI_TARGET_PORT $ISCSI_USERNAME	\
+		   $ISCSI_PASSWORD $ISCSI_IN_USERNAME $ISCSI_IN_PASSWORD
+}
+
+parse_iscsi_ops ()
+{
+	. /etc/iscsi.initramfs
+
+	for x in $(cat /proc/cmdline); do
+		case ${x} in
+        	iscsi_initiator=*)
+                	ISCSI_INITIATOR="${x#iscsi_initiator=}"
+                	;;
+        	iscsi_target_name=*)
+                	ISCSI_TARGET_NAME="${x#iscsi_target_name=}"
+                	;;
+        	iscsi_target_ip=*)
+                	ISCSI_TARGET_IP="${x#iscsi_target_ip=}"
+                	;;
+        	iscsi_target_port=*)
+                	ISCSI_TARGET_PORT="${x#iscsi_target_port=}"
+                	;;
+		iscsi_target_group=*)
+			ISCSI_TARGET_GROUP="${x#iscsi_target_group=}"
+			;;
+		iscsi_username=*)
+			ISCSI_USERNAME="-u ${x#iscsi_username=}"
+			;;
+		iscsi_password=*)
+			ISCSI_PASSWORD="-w ${x#iscsi_password=}"
+			;;
+		iscsi_in_username=*)
+			ISCSI_IN_USERNAME="-U ${x#iscsi_in_username=}"
+			;;
+		iscsi_in_password=*)
+			ISCSI_IN_PASSWORD="-W ${x#iscsi_in_password=}"
+			;;
+		esac
+	done
+}
+
+if [ ! -x /sbin/iscsistart ]; then
+	exit 0
+fi
+
+parse_iscsi_ops
+
+if [ -z $ISCSI_TARGET_NAME ] || [ -z $ISCSI_TARGET_IP ]; then
+	exit 0
+fi
+
+do_iscsi_login
+
+exit 0
--- open-iscsi-2.0.870~rc3.orig/debian/extra/initramfs.hook
+++ open-iscsi-2.0.870~rc3/debian/extra/initramfs.hook
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+PREREQ="udev"
+
+prereqs()
+{
+	echo "$PREREQ"
+}
+
+case $1 in
+# get pre-requisites
+prereqs)
+	prereqs
+	exit 0
+	;;
+esac
+
+if [ ! -e /etc/iscsi/iscsi.initramfs ]; then
+	exit 0
+fi
+
+# Hooks for loading iscsi bits into the initramfs
+. /usr/share/initramfs-tools/hook-functions
+
+copy_exec /usr/sbin/iscsistart /sbin
+cp /etc/iscsi/initiatorname.iscsi $DESTDIR/etc
+cp /etc/iscsi/iscsi.initramfs $DESTDIR/etc
+
+for x in crc32c libcrc32c iscsi_tcp libiscsi scsi_transport_iscsi; do
+	manual_add_modules ${x}
+done
--- open-iscsi-2.0.870~rc3.orig/doc/iscsiadm.8
+++ open-iscsi-2.0.870~rc3/doc/iscsiadm.8
@@ -48,12 +48,16 @@
 \fB\-I\fR, \fB\-\-interface\fI[iface]\fR
 The interface argument specifies the iSCSI interface to use for the operation.
 iSCSI interfaces (iface) are defined in /etc/iscsi/ifaces. For hardware
-or the iface config must have the hardware address (iface.hwaddress)
+or offload, the iface config must have the hardware address (iface.hwaddress)
 and the driver/transport_name (iface.transport_name). The iface's name is
 then the filename of the iface config. For software iSCSI, the iface config
 must have either the hardware address (iface.hwaddress), or the network
-layer's interface name (iface.net_ifacename), and it must have the
-driver/transport_name
+layer's interface name (iface.net_ifacename), or the IP address of the
+NIC (iface.ipaddress), and it must have the driver/transport_name
+(iface.transport_name). Note that for software iSCSI using specifying the
+IP address does not bind the session through a specific NIC. We allow the
+network layer to decide which NIC to use, but packets from this host will
+use the address specific.
 
 The available drivers/iscsi_transports are tcp (software iSCSI over TCP/IP),
 iser (software iSCSI over infinniband), or qla4xxx (Qlogic 4XXXX HBAs). The
@@ -63,11 +67,6 @@
 to decide what to do. There is no need to create a iface config with the default
 behavior. If you do not specify a iface, then the default behavior is used.
 
-As mentioned above there is a special iface name default. There are two others
-bnx2i and iser, which does not bind the session to a specific card, but
-will bind the session to either the bnx2i or iser transport. These are
-experimental and the use is not supported as a stable interface yet.
-
 In discovery mode multiple interfaces can be specific by passing in multiple
 -I/--interface instances. For example, 
 
--- open-iscsi-2.0.870~rc3.orig/etc/iface.example
+++ open-iscsi-2.0.870~rc3/etc/iface.example
@@ -4,41 +4,22 @@
 # There must be a seperate iscsi interface config file for each NIC, network
 # interface or port or iscsi HBA you want to bind sessions to.
 #
-# For hardware iscsi, this is created for you when you run iscsiadm.
+# For hardware/offload iscsi, this is created for you when you run iscsiadm.
 # For software iscsi, you must define these files yourself.
 #
 
-# REQUIRED: iface.transport_name
-#
 # Set the iscsi transport/driver to use for the iface by setting
 # iface.transport_name
 # example:
 # iface.transport_name = tcp
 
-# This value is required and valid values for iface.transport_name are:
+# This values is required and valid values for iface.transport_name are:
 # - tcp (Software iSCSI over TCP/IP)
 # - iser (Software iSCSI over infinniband
 # - qla4xxx (Qlogic QLA4XXX HBAs)
-# - bnx2i (Broadcom bnx iSCSI HBAs);
-#
-#OPTIONAL: iface.initiatorname
-# To use a initiator name other than the one set in
-# /etc/iscsi/initiatorname.iscsi for normal sessions set the
-# iface.initiatorname. This is only used for normal sessions.
-# For discovery sessions the /etc/iscsi/initiatorname.iscsi value
-# is used.
-#
-# iface.initiatorname = iqn.2003-04.com.fedora:test
-#
-#
-# REQUIRED to be able to bind a session to a network device:
-#			[iface.net_ifacename | iface.hwaddress]
-#
-# OPTIONAL if you are creating ifaces so you can create multiple sessions
-# using the default behavior where the network layer selects the device.
-#
-# __One__ of the following values are required for binding a session
-# to a specific nic/netdevice.
+
+
+# __One__ of the following values are required for the binding.
 #
 # To bind by network interface name (example: eth0, eth2:2, eth1.3)
 # set iface.net_ifacename
--- open-iscsi-2.0.870~rc3.orig/etc/iscsid.conf
+++ open-iscsi-2.0.870~rc3/etc/iscsid.conf
@@ -107,31 +107,14 @@
 # Retry
 #******
 
-# To specify the number of times iscsid should retry a login
-# if the login attempt fails due to the node.conn[0].timeo.login_timeout
-# expiring modify the following line. Note that if the login fails
-# quickly (before node.conn[0].timeo.login_timeout fires) because the network
-# layer or the target returns an error, iscsid may retry the login more than
-# node.session.initial_login_retry_max times.
-#
-# This retry count along with node.conn[0].timeo.login_timeout
-# determines the maximum amount of time iscsid will try to
-# establish the initial login. node.session.initial_login_retry_max is
-# multiplied by the node.conn[0].timeo.login_timeout to determine the
-# maximum amount.
-#
-# The default node.session.initial_login_retry_max is 8 and
-# node.conn[0].timeo.login_timeout is 15 so we have:
-#
-# node.conn[0].timeo.login_timeout * node.session.initial_login_retry_max =
-#								120 seconds
-#
-# Valid values are any integer value. This only
+# To speficy the number of times iscsiadm should retry a login
+# to the target when we first login, modify the following line.
+# The default is 4. Valid values are any integer value. This only
 # affects the initial login. Setting it to a high value can slow
 # down the iscsi service startup. Setting it to a low value can
 # cause a session to not get logged into, if there are distuptions
 # during startup or if the network is not ready at that time.
-node.session.initial_login_retry_max = 8
+node.session.initial_login_retry_max = 4
 
 ################################
 # session and device queue depth
@@ -225,9 +208,9 @@
 #node.conn[0].iscsi.HeaderDigest = None
 #node.conn[0].iscsi.DataDigest = None
 #
-# The default is to never use DataDigests or HeaderDigests.
-#
-
+# The default is to never use DataDigests and to allow the target to control
+# the setting of the HeaderDigest checking with the initiator requesting
+# a preference of disabling the checking.
 
 #************
 # Workarounds
--- open-iscsi-2.0.870~rc3.orig/include/iscsi_if.h
+++ open-iscsi-2.0.870~rc3/include/iscsi_if.h
@@ -50,7 +50,6 @@
 	ISCSI_UEVENT_TGT_DSCVR		= UEVENT_BASE + 15,
 	ISCSI_UEVENT_SET_HOST_PARAM	= UEVENT_BASE + 16,
 	ISCSI_UEVENT_UNBIND_SESSION	= UEVENT_BASE + 17,
-	ISCSI_UEVENT_CREATE_BOUND_SESSION	= UEVENT_BASE + 18,
 
 	/* up events */
 	ISCSI_KEVENT_RECV_PDU		= KEVENT_BASE + 1,
@@ -79,12 +78,6 @@
 			uint16_t	cmds_max;
 			uint16_t	queue_depth;
 		} c_session;
-		struct msg_create_bound_session {
-			uint64_t	ep_handle;
-			uint32_t	initial_cmdsn;
-			uint16_t	cmds_max;
-			uint16_t	queue_depth;
-		} c_bound_session;
 		struct msg_destroy_session {
 			uint32_t	sid;
 		} d_session;
@@ -213,8 +206,6 @@
 	ISCSI_ERR_DATA_DGST		= ISCSI_ERR_BASE + 15,
 	ISCSI_ERR_PARAM_NOT_FOUND	= ISCSI_ERR_BASE + 16,
 	ISCSI_ERR_NO_SCSI_CMD		= ISCSI_ERR_BASE + 17,
-	ISCSI_ERR_INVALID_HOST		= ISCSI_ERR_BASE + 18,
-	ISCSI_ERR_XMIT_FAILED		= ISCSI_ERR_BASE + 19,
 };
 
 /*
@@ -259,49 +250,42 @@
 
 	ISCSI_PARAM_PING_TMO,
 	ISCSI_PARAM_RECV_TMO,
-
-	ISCSI_PARAM_IFACE_NAME,
-	ISCSI_PARAM_ISID,
-	ISCSI_PARAM_INITIATOR_NAME,
 	/* must always be last */
 	ISCSI_PARAM_MAX,
 };
 
-#define ISCSI_MAX_RECV_DLENGTH		(1ULL << ISCSI_PARAM_MAX_RECV_DLENGTH)
-#define ISCSI_MAX_XMIT_DLENGTH		(1ULL << ISCSI_PARAM_MAX_XMIT_DLENGTH)
-#define ISCSI_HDRDGST_EN		(1ULL << ISCSI_PARAM_HDRDGST_EN)
-#define ISCSI_DATADGST_EN		(1ULL << ISCSI_PARAM_DATADGST_EN)
-#define ISCSI_INITIAL_R2T_EN		(1ULL << ISCSI_PARAM_INITIAL_R2T_EN)
-#define ISCSI_MAX_R2T			(1ULL << ISCSI_PARAM_MAX_R2T)
-#define ISCSI_IMM_DATA_EN		(1ULL << ISCSI_PARAM_IMM_DATA_EN)
-#define ISCSI_FIRST_BURST		(1ULL << ISCSI_PARAM_FIRST_BURST)
-#define ISCSI_MAX_BURST			(1ULL << ISCSI_PARAM_MAX_BURST)
-#define ISCSI_PDU_INORDER_EN		(1ULL << ISCSI_PARAM_PDU_INORDER_EN)
-#define ISCSI_DATASEQ_INORDER_EN	(1ULL << ISCSI_PARAM_DATASEQ_INORDER_EN)
-#define ISCSI_ERL			(1ULL << ISCSI_PARAM_ERL)
-#define ISCSI_IFMARKER_EN		(1ULL << ISCSI_PARAM_IFMARKER_EN)
-#define ISCSI_OFMARKER_EN		(1ULL << ISCSI_PARAM_OFMARKER_EN)
-#define ISCSI_EXP_STATSN		(1ULL << ISCSI_PARAM_EXP_STATSN)
-#define ISCSI_TARGET_NAME		(1ULL << ISCSI_PARAM_TARGET_NAME)
-#define ISCSI_TPGT			(1ULL << ISCSI_PARAM_TPGT)
-#define ISCSI_PERSISTENT_ADDRESS	(1ULL << ISCSI_PARAM_PERSISTENT_ADDRESS)
-#define ISCSI_PERSISTENT_PORT		(1ULL << ISCSI_PARAM_PERSISTENT_PORT)
-#define ISCSI_SESS_RECOVERY_TMO		(1ULL << ISCSI_PARAM_SESS_RECOVERY_TMO)
-#define ISCSI_CONN_PORT			(1ULL << ISCSI_PARAM_CONN_PORT)
-#define ISCSI_CONN_ADDRESS		(1ULL << ISCSI_PARAM_CONN_ADDRESS)
-#define ISCSI_USERNAME			(1ULL << ISCSI_PARAM_USERNAME)
-#define ISCSI_USERNAME_IN		(1ULL << ISCSI_PARAM_USERNAME_IN)
-#define ISCSI_PASSWORD			(1ULL << ISCSI_PARAM_PASSWORD)
-#define ISCSI_PASSWORD_IN		(1ULL << ISCSI_PARAM_PASSWORD_IN)
-#define ISCSI_FAST_ABORT		(1ULL << ISCSI_PARAM_FAST_ABORT)
-#define ISCSI_ABORT_TMO			(1ULL << ISCSI_PARAM_ABORT_TMO)
-#define ISCSI_LU_RESET_TMO		(1ULL << ISCSI_PARAM_LU_RESET_TMO)
-#define ISCSI_HOST_RESET_TMO		(1ULL << ISCSI_PARAM_HOST_RESET_TMO)
-#define ISCSI_PING_TMO			(1ULL << ISCSI_PARAM_PING_TMO)
-#define ISCSI_RECV_TMO			(1ULL << ISCSI_PARAM_RECV_TMO)
-#define ISCSI_IFACE_NAME		(1ULL << ISCSI_PARAM_IFACE_NAME)
-#define ISCSI_ISID			(1ULL << ISCSI_PARAM_ISID)
-#define ISCSI_INITIATOR_NAME		(1ULL << ISCSI_PARAM_INITIATOR_NAME)
+#define ISCSI_MAX_RECV_DLENGTH		(1 << ISCSI_PARAM_MAX_RECV_DLENGTH)
+#define ISCSI_MAX_XMIT_DLENGTH		(1 << ISCSI_PARAM_MAX_XMIT_DLENGTH)
+#define ISCSI_HDRDGST_EN		(1 << ISCSI_PARAM_HDRDGST_EN)
+#define ISCSI_DATADGST_EN		(1 << ISCSI_PARAM_DATADGST_EN)
+#define ISCSI_INITIAL_R2T_EN		(1 << ISCSI_PARAM_INITIAL_R2T_EN)
+#define ISCSI_MAX_R2T			(1 << ISCSI_PARAM_MAX_R2T)
+#define ISCSI_IMM_DATA_EN		(1 << ISCSI_PARAM_IMM_DATA_EN)
+#define ISCSI_FIRST_BURST		(1 << ISCSI_PARAM_FIRST_BURST)
+#define ISCSI_MAX_BURST			(1 << ISCSI_PARAM_MAX_BURST)
+#define ISCSI_PDU_INORDER_EN		(1 << ISCSI_PARAM_PDU_INORDER_EN)
+#define ISCSI_DATASEQ_INORDER_EN	(1 << ISCSI_PARAM_DATASEQ_INORDER_EN)
+#define ISCSI_ERL			(1 << ISCSI_PARAM_ERL)
+#define ISCSI_IFMARKER_EN		(1 << ISCSI_PARAM_IFMARKER_EN)
+#define ISCSI_OFMARKER_EN		(1 << ISCSI_PARAM_OFMARKER_EN)
+#define ISCSI_EXP_STATSN		(1 << ISCSI_PARAM_EXP_STATSN)
+#define ISCSI_TARGET_NAME		(1 << ISCSI_PARAM_TARGET_NAME)
+#define ISCSI_TPGT			(1 << ISCSI_PARAM_TPGT)
+#define ISCSI_PERSISTENT_ADDRESS	(1 << ISCSI_PARAM_PERSISTENT_ADDRESS)
+#define ISCSI_PERSISTENT_PORT		(1 << ISCSI_PARAM_PERSISTENT_PORT)
+#define ISCSI_SESS_RECOVERY_TMO		(1 << ISCSI_PARAM_SESS_RECOVERY_TMO)
+#define ISCSI_CONN_PORT			(1 << ISCSI_PARAM_CONN_PORT)
+#define ISCSI_CONN_ADDRESS		(1 << ISCSI_PARAM_CONN_ADDRESS)
+#define ISCSI_USERNAME			(1 << ISCSI_PARAM_USERNAME)
+#define ISCSI_USERNAME_IN		(1 << ISCSI_PARAM_USERNAME_IN)
+#define ISCSI_PASSWORD			(1 << ISCSI_PARAM_PASSWORD)
+#define ISCSI_PASSWORD_IN		(1 << ISCSI_PARAM_PASSWORD_IN)
+#define ISCSI_FAST_ABORT		(1 << ISCSI_PARAM_FAST_ABORT)
+#define ISCSI_ABORT_TMO			(1 << ISCSI_PARAM_ABORT_TMO)
+#define ISCSI_LU_RESET_TMO		(1 << ISCSI_PARAM_LU_RESET_TMO)
+#define ISCSI_HOST_RESET_TMO		(1 << ISCSI_PARAM_HOST_RESET_TMO)
+#define ISCSI_PING_TMO			(1 << ISCSI_PARAM_PING_TMO)
+#define ISCSI_RECV_TMO			(1 << ISCSI_PARAM_RECV_TMO)
 
 /* iSCSI HBA params */
 enum iscsi_host_param {
@@ -312,13 +296,20 @@
 	ISCSI_HOST_PARAM_MAX,
 };
 
-#define ISCSI_HOST_HWADDRESS		(1ULL << ISCSI_HOST_PARAM_HWADDRESS)
-#define ISCSI_HOST_INITIATOR_NAME	(1ULL << ISCSI_HOST_PARAM_INITIATOR_NAME)
-#define ISCSI_HOST_NETDEV_NAME		(1ULL << ISCSI_HOST_PARAM_NETDEV_NAME)
-#define ISCSI_HOST_IPADDRESS		(1ULL << ISCSI_HOST_PARAM_IPADDRESS)
+#define ISCSI_HOST_HWADDRESS		(1 << ISCSI_HOST_PARAM_HWADDRESS)
+#define ISCSI_HOST_INITIATOR_NAME	(1 << ISCSI_HOST_PARAM_INITIATOR_NAME)
+#define ISCSI_HOST_NETDEV_NAME		(1 << ISCSI_HOST_PARAM_NETDEV_NAME)
+#define ISCSI_HOST_IPADDRESS		(1 << ISCSI_HOST_PARAM_IPADDRESS)
 
 #define iscsi_ptr(_handle) ((void*)(unsigned long)_handle)
 #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr)
+#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
+
+/**
+ * iscsi_hostdata - get LLD hostdata from scsi_host
+ * @_hostdata: pointer to scsi host's hostdata
+ **/
+#define iscsi_hostdata(_hostdata) ((void*)_hostdata + sizeof(unsigned long))
 
 /*
  * These flags presents iSCSI Data-Path capabilities.
--- open-iscsi-2.0.870~rc3.orig/include/iscsi_proto.h
+++ open-iscsi-2.0.870~rc3/include/iscsi_proto.h
@@ -127,7 +127,6 @@
 
 #define ISCSI_AHSTYPE_CDB		1
 #define ISCSI_AHSTYPE_RLENGTH		2
-#define ISCSI_CDB_SIZE			16
 
 /* iSCSI PDU Header */
 struct iscsi_cmd {
@@ -141,7 +140,7 @@
 	__be32 data_length;
 	__be32 cmdsn;
 	__be32 exp_statsn;
-	uint8_t cdb[ISCSI_CDB_SIZE];	/* SCSI Command Block */
+	uint8_t cdb[16];	/* SCSI Command Block */
 	/* Additional Data (Command Dependent) */
 };
 
@@ -170,8 +169,7 @@
 	__be16 ahslength;	/* CDB length - 15, including reserved byte */
 	uint8_t ahstype;
 	uint8_t reserved;
-	/* 4-byte aligned extended CDB spillover */
-	uint8_t ecdb[260 - ISCSI_CDB_SIZE];
+	uint8_t ecdb[260 - 16];	/* 4-byte aligned extended CDB spillover */
 };
 
 /* SCSI Response Header */
--- open-iscsi-2.0.870~rc3.orig/kernel/2.6.14-19_compat.patch
+++ open-iscsi-2.0.870~rc3/kernel/2.6.14-19_compat.patch
@@ -1,329 +1,16 @@
-diff --git a/iscsi_tcp.c b/iscsi_tcp.c
-index d074146..4a01066 100644
---- a/iscsi_tcp.c
-+++ b/iscsi_tcp.c
-@@ -426,6 +426,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment,
- 
- 	debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
- 		  offset, size);
-+
-+	/*
-+	 * older kernels could send use_sg=0 for commands like sgio
-+	 * or scsi-ml commands.
-+	 */
-+	if (!sg_count) {
-+		iscsi_segment_init_linear(segment, (void *)sg_list + offset,
-+					  size, done, hash);
-+		return 0;
-+	}
-+
- 	__iscsi_segment_init(segment, size, done, hash);
- 	for_each_sg(sg_list, sg, sg_count, i) {
- 		debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
-@@ -534,7 +545,7 @@ iscsi_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
- 	struct iscsi_tcp_task *tcp_task = task->dd_data;
- 	struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
- 	int datasn = be32_to_cpu(rhdr->datasn);
--	unsigned total_in_length = scsi_in(task->sc)->length;
-+	unsigned total_in_length = scsi_bufflen(task->sc);
- 
- 	iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
- 	if (tcp_conn->in.datalen == 0)
-@@ -660,11 +671,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- 			    r2t->data_length, session->max_burst);
- 
- 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
--	if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
-+	if (r2t->data_offset + r2t->data_length > scsi_bufflen(task->sc)) {
- 		iscsi_conn_printk(KERN_ERR, conn,
- 				  "invalid R2T with data len %u at offset %u "
- 				  "and total length %d\n", r2t->data_length,
--				  r2t->data_offset, scsi_out(task->sc)->length);
-+				  r2t->data_offset, scsi_bufflen(task->sc));
- 		__kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- 			    sizeof(void*));
- 		return ISCSI_ERR_DATALEN;
-@@ -764,7 +775,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- 		if (tcp_conn->in.datalen) {
- 			struct iscsi_tcp_task *tcp_task = task->dd_data;
- 			struct hash_desc *rx_hash = NULL;
--			struct scsi_data_buffer *sdb = scsi_in(task->sc);
- 
- 			/*
- 			 * Setup copy of Data-In into the Scsi_Cmnd
-@@ -782,8 +792,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- 				  tcp_task->data_offset,
- 				  tcp_conn->in.datalen);
- 			rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
--						   sdb->table.sgl,
--						   sdb->table.nents,
-+						   scsi_sglist(task->sc),
-+						   scsi_sg_count(task->sc),
- 						   tcp_task->data_offset,
- 						   tcp_conn->in.datalen,
- 						   iscsi_tcp_process_data_in,
-@@ -1352,8 +1362,8 @@ iscsi_tcp_task_init(struct iscsi_task *task)
- 		return 0;
- 
- 	/* If we have immediate data, attach a payload */
--	err = iscsi_tcp_send_data_prep(conn, scsi_out(sc)->table.sgl,
--				       scsi_out(sc)->table.nents,
-+	err = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+				       scsi_sg_count(sc),
- 				       0, task->imm_count);
- 	if (err)
- 		return err;
-@@ -1376,7 +1386,6 @@ iscsi_tcp_task_xmit(struct iscsi_task *task)
- 	struct iscsi_conn *conn = task->conn;
- 	struct iscsi_tcp_task *tcp_task = task->dd_data;
- 	struct scsi_cmnd *sc = task->sc;
--	struct scsi_data_buffer *sdb;
- 	int rc = 0;
- 
- flush:
-@@ -1396,7 +1405,6 @@ flush:
- 	if (sc->sc_data_direction != DMA_TO_DEVICE)
- 		return 0;
- 
--	sdb = scsi_out(sc);
- 	if (task->unsol_count != 0) {
- 		struct iscsi_data *hdr = &tcp_task->unsol_dtask.hdr;
- 
-@@ -1411,8 +1419,8 @@ flush:
- 				task->itt, tcp_task->sent, task->data_count);
- 
- 		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
--		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
--					      sdb->table.nents, tcp_task->sent,
-+		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+					      scsi_sg_count(sc), tcp_task->sent,
- 					      task->data_count);
- 		if (rc)
- 			goto fail;
-@@ -1458,8 +1466,8 @@ flush:
- 		iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr,
- 					sizeof(struct iscsi_hdr));
- 
--		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
--					      sdb->table.nents,
-+		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+					      scsi_sg_count(sc),
- 					      r2t->data_offset + r2t->sent,
- 					      r2t->data_count);
- 		if (rc)
-@@ -1847,7 +1855,11 @@ iscsi_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
- 	shost->max_lun = iscsi_max_lun;
- 	shost->max_id = 0;
- 	shost->max_channel = 0;
-+#ifndef SCSI_MAX_VARLEN_CDB_SIZE
-+	shost->max_cmd_len = 16;
-+#else
- 	shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE;
-+#endif
- 
- 	if (iscsi_host_add(shost, NULL))
- 		goto free_host;
-@@ -1900,6 +1912,9 @@ static int iscsi_tcp_slave_configure(struct scsi_device *sdev)
- }
- 
- static struct scsi_host_template iscsi_sht = {
-+#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,24)
-+	.use_sg_chaining	= ENABLE_SG_CHAINING,
-+#endif
- 	.module			= THIS_MODULE,
- 	.name			= "iSCSI Initiator over TCP/IP",
- 	.queuecommand           = iscsi_queuecommand,
-diff --git a/iscsi_tcp.h b/iscsi_tcp.h
-index 68423e8..1796c96 100644
---- a/iscsi_tcp.h
-+++ b/iscsi_tcp.h
-@@ -24,6 +24,8 @@
- 
- #include "libiscsi.h"
- 
-+#include "open_iscsi_compat.h"
-+
- struct crypto_hash;
- struct socket;
- struct iscsi_tcp_conn;
-diff --git a/libiscsi.c b/libiscsi.c
-index f3b845f..cfafb60 100644
---- a/libiscsi.c
-+++ b/libiscsi.c
-@@ -24,7 +24,10 @@
- #include <linux/types.h>
- #include <linux/kfifo.h>
- #include <linux/delay.h>
-+#include <linux/version.h>
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
- #include <linux/log2.h>
-+#endif
- #include <asm/unaligned.h>
- #include <net/tcp.h>
- #include <scsi/scsi_cmnd.h>
-@@ -187,7 +190,7 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
- 						  sizeof(rlen_ahdr->reserved));
- 	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
- 	rlen_ahdr->reserved = 0;
--	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
-+	rlen_ahdr->read_length = cpu_to_be32(scsi_bufflen(sc));
- 
- 	debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
- 		   "rlen_ahdr->ahslength(%d)\n",
-@@ -242,7 +245,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- 			return rc;
- 	}
- 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
--		unsigned out_len = scsi_out(sc)->length;
-+		unsigned out_len = scsi_bufflen(sc);
- 		hdr->data_length = cpu_to_be32(out_len);
- 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
- 		/*
-@@ -286,7 +289,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- 	} else {
- 		hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- 		zero_data(hdr->dlength);
--		hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
-+		hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
- 
- 		if (sc->sc_data_direction == DMA_FROM_DEVICE)
- 			hdr->flags |= ISCSI_FLAG_CMD_READ;
-@@ -314,7 +317,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- 		   "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ?
- 		   "write" : "read", conn->id, sc, sc->cmnd[0], task->itt,
- 		   scsi_bufflen(sc),
--		   scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
-+		   scsi_bidi_cmnd(sc) ? scsi_bufflen(sc) : 0,
- 		   session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
- 	return 0;
- }
-@@ -407,12 +410,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
- 		conn->session->tt->cleanup_task(conn, task);
- 
- 	sc->result = err;
--	if (!scsi_bidi_cmnd(sc))
--		scsi_set_resid(sc, scsi_bufflen(sc));
--	else {
--		scsi_out(sc)->resid = scsi_out(sc)->length;
--		scsi_in(sc)->resid = scsi_in(sc)->length;
--	}
-+	scsi_set_resid(sc, scsi_bufflen(sc));
- 
- 	if (conn->task == task)
- 		conn->task = NULL;
-@@ -587,7 +585,7 @@ invalid_datalen:
- 			goto out;
- 		}
- 
--		senselen = get_unaligned_be16(data);
-+		senselen = be16_to_cpu(get_unaligned((__be16 *) data));
- 		if (datalen < senselen)
- 			goto invalid_datalen;
- 
-@@ -603,8 +601,8 @@ invalid_datalen:
- 
- 		if (scsi_bidi_cmnd(sc) && res_count > 0 &&
- 				(rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
--				 res_count <= scsi_in(sc)->length))
--			scsi_in(sc)->resid = res_count;
-+				 res_count <= scsi_bufflen(sc)))
-+			scsi_set_resid(sc, res_count);
- 		else
- 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- 	}
-@@ -653,8 +651,8 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- 
- 		if (res_count > 0 &&
- 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
--		     res_count <= scsi_in(sc)->length))
--			scsi_in(sc)->resid = res_count;
-+		     res_count <= scsi_bufflen(sc)))
-+			scsi_set_resid(sc, res_count);
- 		else
- 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- 	}
-@@ -1151,10 +1149,9 @@ again:
- 	return rc;
- }
- 
--static void iscsi_xmitworker(struct work_struct *work)
-+static void iscsi_xmitworker(void *data)
- {
--	struct iscsi_conn *conn =
--		container_of(work, struct iscsi_conn, xmitwork);
-+	struct iscsi_conn *conn = data;
- 	int rc;
- 	/*
- 	 * serialize Xmit worker on a per-connection basis.
-@@ -1297,12 +1294,7 @@ reject:
- fault:
- 	spin_unlock(&session->lock);
- 	debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
--	if (!scsi_bidi_cmnd(sc))
--		scsi_set_resid(sc, scsi_bufflen(sc));
--	else {
--		scsi_out(sc)->resid = scsi_out(sc)->length;
--		scsi_in(sc)->resid = scsi_in(sc)->length;
--	}
-+	scsi_set_resid(sc, scsi_bufflen(sc));
- 	done(sc);
- 	spin_lock(host->host_lock);
- 	return 0;
-@@ -1906,8 +1898,9 @@ struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
- 	shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size);
- 	if (!shost)
- 		return NULL;
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
- 	shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
--
-+#endif
- 	if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) {
- 		if (qdepth != 0)
- 			printk(KERN_ERR "iscsi: invalid queue depth of %d. "
-@@ -2123,7 +2116,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
- 	INIT_LIST_HEAD(&conn->mgmtqueue);
- 	INIT_LIST_HEAD(&conn->xmitqueue);
- 	INIT_LIST_HEAD(&conn->requeue);
--	INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
-+	INIT_WORK(&conn->xmitwork, iscsi_xmitworker, conn);
- 
- 	/* allocate login_task used for the login/text sequences */
- 	spin_lock_bh(&session->lock);
-diff --git a/libiscsi.h b/libiscsi.h
-index cfc5fa6..ede08ef 100644
---- a/libiscsi.h
-+++ b/libiscsi.h
-@@ -25,13 +25,15 @@
- 
- #include <linux/types.h>
- #include <linux/wait.h>
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
- #include <linux/mutex.h>
--#include <linux/timer.h>
--#include <linux/workqueue.h>
-+#endif
- 
- #include "iscsi_proto.h"
- #include "iscsi_if.h"
- 
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct scsi_host_template;
- struct scsi_device;
-diff --git a/open_iscsi_compat.h b/open_iscsi_compat.h
+diff --git a/iscsi_compat.h b/iscsi_compat.h
 new file mode 100644
-index 0000000..ecd48df
+index 0000000..965157a
 --- /dev/null
-+++ b/open_iscsi_compat.h
-@@ -0,0 +1,303 @@
++++ b/iscsi_compat.h
+@@ -0,0 +1,192 @@
 +#include <linux/version.h>
 +#include <linux/kernel.h>
 +#include <scsi/scsi.h>
 +#include <scsi/scsi_cmnd.h>
 +
-+#ifndef OPEN_ISCSI_COMPAT
-+#define OPEN_ISCSI_COMPAT
++#ifndef ISCSI_COMPAT
++#define ISCSI_COMPAT
 +
 +#ifndef SCAN_WILD_CARD
 +#define SCAN_WILD_CARD  ~0
@@ -369,6 +56,9 @@
 +
 +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
 +
++#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
++	netlink_kernel_create(uint, input)
++
 +#define gfp_t unsigned
 +
 +void *kzalloc(size_t size, gfp_t flags)
@@ -380,30 +70,6 @@
 +
 +#endif
 +
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
-+
-+static inline int fls64(__u64 x)
-+{
-+	__u32 h = x >> 32;
-+	if (h)
-+		return fls(h) + 32;
-+	return fls(x);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
-+
-+static inline unsigned fls_long(unsigned long l)
-+{
-+	if (sizeof(l) == 4)
-+		return fls(l);
-+	return fls64(l);
-+}
-+
-+#endif
-+
-+
 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
 +
 +#include "linux/crypto.h"
@@ -469,91 +135,20 @@
 +
 +#endif
 +
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
-+#ifdef RHEL_RELEASE_VERSION
-+#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,2)
-+static inline int is_power_of_2(unsigned long n)
-+{
-+	return (n != 0 && ((n & (n - 1)) == 0));
-+}
-+#endif
-+#else
-+/* not a redhat kernel */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++
 +static inline int is_power_of_2(unsigned long n)
 +{
 +	return (n != 0 && ((n & (n - 1)) == 0));
 +}
 +#endif
-+#endif
 +
 +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
-+{
-+	return (struct nlmsghdr *)skb->data;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+#ifdef RHEL_RELEASE_VERSION
-+#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,2)
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+	return (void *)shost->hostdata;
-+}
-+#endif
-+#else
-+/* not a redhat kernel */
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+	return (void *)shost->hostdata;
-+}
-+#endif
-+
-+/*
-+ * Note: We do not support bidi for the compat modules if the kernel
-+ * does not have support.
-+ */
-+#define scsi_sg_count(cmd) ((cmd)->use_sg)
-+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
-+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
-+
-+#ifdef RHEL_RELEASE_VERSION
-+#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,2)
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+	cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+	return cmd->resid;
-+}
-+#endif
-+#else
-+/* not a redhat kernel */
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+	cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+	return cmd->resid;
-+}
-+#endif
++#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
++	netlink_kernel_create(uint, groups, input, mod)
 +
 +#endif
 +
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+static inline unsigned long rounddown_pow_of_two(unsigned long n)
-+{
-+	return 1UL << (fls_long(n) - 1);
-+}
-+
-+
 +static inline struct scatterlist *sg_next(struct scatterlist *sg)
 +{
 +	if (!sg) {
@@ -580,48 +175,139 @@
 +{
 +	memset(sgl, 0, sizeof(*sgl) * nents);
 +}
-+#endif
 +
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
++#define scsi_sg_count(cmd) ((cmd)->use_sg)
++#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
++#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
 +
-+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
++static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
 +{
-+	return 0;
++	cmd->resid = resid;
 +}
 +
-+#define netlink_kernel_release(_nls) \
-+	sock_release(_nls->sk_socket)
++static inline int scsi_get_resid(struct scsi_cmnd *cmd)
++{
++	return cmd->resid;
++}
 +
++static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
++{
++	return (struct nlmsghdr *)skb->data;
++}
 +
 +#endif
+diff --git a/iscsi_tcp.c b/iscsi_tcp.c
+index 0d21d87..16908b6 100644
+--- a/iscsi_tcp.c
++++ b/iscsi_tcp.c
+@@ -43,6 +43,7 @@
+ #include "scsi_transport_iscsi.h"
+ 
+ #include "iscsi_tcp.h"
++#include "iscsi_compat.h"
+ 
+ MODULE_AUTHOR("Dmitry Yusupov <dmitry_yus@yahoo.com>, "
+ 	      "Alex Aizman <itn780@yahoo.com>");
+@@ -422,6 +423,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment,
+ 
+ 	debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
+ 		  offset, size);
 +
++	/*
++	 * older kernels could send use_sg=0 for commands like sgio
++	 * or scsi-ml commands.
++	 */
++	if (!sg_count) {
++		iscsi_segment_init_linear(segment, (void *)sg_list + offset,
++					  size, done, hash);
++		return 0;
++	}
 +
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+	netlink_kernel_create(uint, input)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+	netlink_kernel_create(uint, groups, input, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+	netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+	netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
+ 	__iscsi_segment_init(segment, size, done, hash);
+ 	for_each_sg(sg_list, sg, sg_count, i) {
+ 		debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
+diff --git a/iscsi_tcp.h b/iscsi_tcp.h
+index 950d75f..662ddab 100644
+--- a/iscsi_tcp.h
++++ b/iscsi_tcp.h
+@@ -24,6 +24,7 @@
+ 
+ #include "libiscsi.h"
+ 
++#include "iscsi_compat.h"
+ struct crypto_hash;
+ struct socket;
+ struct iscsi_tcp_conn;
+diff --git a/libiscsi.c b/libiscsi.c
+index 31b6477..e89b92a 100644
+--- a/libiscsi.c
++++ b/libiscsi.c
+@@ -24,7 +24,10 @@
+ #include <linux/types.h>
+ #include <linux/kfifo.h>
+ #include <linux/delay.h>
++#include <linux/version.h>
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
+ #include <linux/log2.h>
 +#endif
-+
-+
+ #include <asm/unaligned.h>
+ #include <net/tcp.h>
+ #include <scsi/scsi_cmnd.h>
+@@ -971,10 +974,9 @@ again:
+ 	return rc;
+ }
+ 
+-static void iscsi_xmitworker(struct work_struct *work)
++static void iscsi_xmitworker(void *data)
+ {
+-	struct iscsi_conn *conn =
+-		container_of(work, struct iscsi_conn, xmitwork);
++	struct iscsi_conn *conn = data;
+ 	int rc;
+ 	/*
+ 	 * serialize Xmit worker on a per-connection basis.
+@@ -1732,7 +1734,9 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
+ 	shost->max_cmd_len = iscsit->max_cmd_len;
+ 	shost->transportt = scsit;
+ 	shost->transportt->create_work_queue = 1;
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
+ 	shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
++#endif
+ 	*hostno = shost->host_no;
+ 
+ 	session = iscsi_hostdata(shost->hostdata);
+@@ -1882,7 +1886,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
+ 	INIT_LIST_HEAD(&conn->mgmtqueue);
+ 	INIT_LIST_HEAD(&conn->xmitqueue);
+ 	INIT_LIST_HEAD(&conn->requeue);
+-	INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
++	INIT_WORK(&conn->xmitwork, iscsi_xmitworker, conn);
+ 
+ 	/* allocate login_mtask used for the login/text sequences */
+ 	spin_lock_bh(&session->lock);
+diff --git a/libiscsi.h b/libiscsi.h
+index 6f10518..61be101 100644
+--- a/libiscsi.h
++++ b/libiscsi.h
+@@ -24,12 +24,14 @@
+ #define LIBISCSI_H
+ 
+ #include <linux/types.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
+ #include <linux/mutex.h>
+-#include <linux/timer.h>
+-#include <linux/workqueue.h>
 +#endif
+ #include "iscsi_proto.h"
+ #include "iscsi_if.h"
+ 
++#include "iscsi_compat.h"
++
+ struct scsi_transport_template;
+ struct scsi_device;
+ struct Scsi_Host;
 diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c
-index 852b016..8aa9888 100644
+index e8f8cf1..3c7878d 100644
 --- a/scsi_transport_iscsi.c
 +++ b/scsi_transport_iscsi.c
 @@ -21,7 +21,10 @@
@@ -635,115 +321,16 @@
  #include <net/tcp.h>
  #include <scsi/scsi.h>
  #include <scsi/scsi_host.h>
-@@ -41,13 +44,13 @@ struct iscsi_internal {
- 	struct scsi_transport_template t;
- 	struct iscsi_transport *iscsi_transport;
- 	struct list_head list;
--	struct device dev;
-+	struct class_device cdev;
- 
--	struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
-+	struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
- 	struct transport_container conn_cont;
--	struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
-+	struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
- 	struct transport_container session_cont;
--	struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
-+	struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
- };
- 
- static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
-@@ -64,12 +67,12 @@ static DEFINE_SPINLOCK(iscsi_transport_lock);
- #define to_iscsi_internal(tmpl) \
- 	container_of(tmpl, struct iscsi_internal, t)
- 
--#define dev_to_iscsi_internal(_dev) \
--	container_of(_dev, struct iscsi_internal, dev)
-+#define cdev_to_iscsi_internal(_cdev) \
-+	container_of(_cdev, struct iscsi_internal, cdev)
- 
--static void iscsi_transport_release(struct device *dev)
-+static void iscsi_transport_release(struct class_device *cdev)
- {
--	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- 	kfree(priv);
- }
- 
-@@ -79,33 +82,31 @@ static void iscsi_transport_release(struct device *dev)
-  */
- static struct class iscsi_transport_class = {
- 	.name = "iscsi_transport",
--	.dev_release = iscsi_transport_release,
-+	.release = iscsi_transport_release,
- };
- 
- static ssize_t
--show_transport_handle(struct device *dev, struct device_attribute *attr,
--		      char *buf)
-+show_transport_handle(struct class_device *cdev, char *buf)
- {
--	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- 	return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
- }
--static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-+static CLASS_DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
- 
- #define show_transport_attr(name, format)				\
- static ssize_t								\
--show_transport_##name(struct device *dev, 				\
--		      struct device_attribute *attr,char *buf)		\
-+show_transport_##name(struct class_device *cdev, char *buf)		\
- {									\
--	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);	\
-+	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);	\
- 	return sprintf(buf, format"\n", priv->iscsi_transport->name);	\
- }									\
--static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
- 
- show_transport_attr(caps, "0x%x");
- 
- static struct attribute *iscsi_transport_attrs[] = {
--	&dev_attr_handle.attr,
--	&dev_attr_caps.attr,
-+	&class_device_attr_handle.attr,
-+	&class_device_attr_caps.attr,
- 	NULL,
- };
- 
-@@ -113,6 +114,7 @@ static struct attribute_group iscsi_transport_group = {
- 	.attrs = iscsi_transport_attrs,
- };
- 
-+#if 0
- /*
-  * iSCSI endpoint attrs
-  */
-@@ -237,9 +239,10 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
- 	return ep;
- }
- EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
-+#endif
- 
- static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
--			    struct device *cdev)
-+			    struct class_device *cdev)
- {
- 	struct Scsi_Host *shost = dev_to_shost(dev);
- 	struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -258,7 +261,7 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
- }
+@@ -29,6 +32,7 @@
+ #include <scsi/scsi_transport.h>
+ #include "scsi_transport_iscsi.h"
+ #include "iscsi_if.h"
++#include "iscsi_compat.h"
  
- static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
--			     struct device *cdev)
-+			     struct class_device *cdev)
- {
- 	struct Scsi_Host *shost = dev_to_shost(dev);
- 	struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -498,10 +501,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
- 				     iscsi_user_scan_session);
+ #define ISCSI_SESSION_ATTRS 19
+ #define ISCSI_CONN_ATTRS 13
+@@ -322,10 +326,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
+ 	return 0;
  }
  
 -static void iscsi_scan_session(struct work_struct *work)
@@ -753,9 +340,9 @@
 -			container_of(work, struct iscsi_cls_session, scan_work);
 +	struct iscsi_cls_session *session = data;
  	struct Scsi_Host *shost = iscsi_session_to_shost(session);
- 	struct iscsi_cls_host *ihost = shost->shost_data;
- 	struct iscsi_scan_data scan_data;
-@@ -514,11 +516,9 @@ static void iscsi_scan_session(struct work_struct *work)
+ 	struct iscsi_host *ihost = shost->shost_data;
+ 	unsigned long flags;
+@@ -343,11 +346,9 @@ done:
  	atomic_dec(&ihost->nr_scans);
  }
  
@@ -769,7 +356,7 @@
  	unsigned long flags;
  
  	iscsi_cls_session_printk(KERN_INFO, session,
-@@ -544,11 +544,9 @@ static void session_recovery_timedout(struct work_struct *work)
+@@ -373,11 +374,9 @@ static void session_recovery_timedout(struct work_struct *work)
  	scsi_target_unblock(&session->dev);
  }
  
@@ -781,9 +368,9 @@
 -				     unblock_work);
 +	struct iscsi_cls_session *session = data;
  	struct Scsi_Host *shost = iscsi_session_to_shost(session);
- 	struct iscsi_cls_host *ihost = shost->shost_data;
+ 	struct iscsi_host *ihost = shost->shost_data;
  	unsigned long flags;
-@@ -568,10 +566,12 @@ static void __iscsi_unblock_session(struct work_struct *work)
+@@ -397,10 +396,12 @@ static void __iscsi_unblock_session(struct work_struct *work)
  	 * the async scanning code (drivers like iscsi_tcp do login and
  	 * scanning from userspace).
  	 */
@@ -796,7 +383,7 @@
  }
  
  /**
-@@ -591,11 +591,9 @@ void iscsi_unblock_session(struct iscsi_cls_session *session)
+@@ -420,11 +421,9 @@ void iscsi_unblock_session(struct iscsi_cls_session *session)
  }
  EXPORT_SYMBOL_GPL(iscsi_unblock_session);
  
@@ -810,7 +397,7 @@
  	unsigned long flags;
  
  	spin_lock_irqsave(&session->lock, flags);
-@@ -612,11 +610,9 @@ void iscsi_block_session(struct iscsi_cls_session *session)
+@@ -441,11 +440,9 @@ void iscsi_block_session(struct iscsi_cls_session *session)
  }
  EXPORT_SYMBOL_GPL(iscsi_block_session);
  
@@ -822,14 +409,15 @@
 -				     unbind_work);
 +	struct iscsi_cls_session *session = data;
  	struct Scsi_Host *shost = iscsi_session_to_shost(session);
- 	struct iscsi_cls_host *ihost = shost->shost_data;
- 	unsigned long flags;
-@@ -659,12 +655,12 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
+ 	struct iscsi_host *ihost = shost->shost_data;
+ 
+@@ -484,13 +481,13 @@ iscsi_alloc_session(struct Scsi_Host *shost,
  	session->transport = transport;
  	session->recovery_tmo = 120;
  	session->state = ISCSI_SESSION_FREE;
 -	INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
 +	INIT_WORK(&session->recovery_work, session_recovery_timedout, session);
+ 	INIT_LIST_HEAD(&session->host_list);
  	INIT_LIST_HEAD(&session->sess_list);
 -	INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
 -	INIT_WORK(&session->block_work, __iscsi_block_session);
@@ -842,7 +430,7 @@
  	spin_lock_init(&session->lock);
  
  	/* this is released in the dev's release function */
-@@ -824,7 +820,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session)
+@@ -619,7 +616,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session)
  	scsi_target_unblock(&session->dev);
  	/* flush running scans then delete devices */
  	flush_workqueue(ihost->scan_workq);
@@ -851,51 +439,8 @@
  
  	/* hw iscsi may not have removed all connections from session */
  	err = device_for_each_child(&session->dev, NULL,
-@@ -1308,6 +1304,8 @@ static int
- iscsi_if_transport_ep(struct iscsi_transport *transport,
- 		      struct iscsi_uevent *ev, int msg_type)
- {
-+	return -ENOSYS;
-+#if 0
- 	struct iscsi_endpoint *ep;
- 	struct sockaddr *dst_addr;
- 	int rc = 0;
-@@ -1348,6 +1346,8 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
- 		break;
- 	}
- 	return rc;
-+
-+#endif
- }
- 
- static int
-@@ -1429,6 +1429,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- 					      ev->u.c_session.queue_depth);
- 		break;
- 	case ISCSI_UEVENT_CREATE_BOUND_SESSION:
-+		err = -ENOSYS;
-+		break;
-+#if 0
- 		ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
- 		if (!ep) {
- 			err = -EINVAL;
-@@ -1440,6 +1443,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- 					ev->u.c_bound_session.cmds_max,
- 					ev->u.c_bound_session.queue_depth);
- 		break;
-+#endif
- 	case ISCSI_UEVENT_DESTROY_SESSION:
- 		session = iscsi_session_lookup(ev->u.d_session.sid);
- 		if (session)
-@@ -1522,55 +1526,70 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- }
- 
- /*
-- * Get message from skb.  Each message is processed by iscsi_if_recv_msg.
-- * Malformed skbs with wrong lengths or invalid creds are not processed.
-+ * Get message from skb (based on rtnetlink_rcv_skb).  Each message is
-+ * processed by iscsi_if_recv_msg.  Malformed skbs with wrong lengths or
-+ * invalid creds are discarded silently.
+@@ -1294,45 +1291,56 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+  * Malformed skbs with wrong lengths or invalid creds are not processed.
   */
  static void
 -iscsi_if_rx(struct sk_buff *skb)
@@ -984,220 +529,40 @@
  	}
  	mutex_unlock(&rx_queue_mutex);
  }
- 
-+#define iscsi_cdev_to_conn(_cdev) \
-+	iscsi_dev_to_conn(_cdev->dev)
-+
- #define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store)		\
--struct device_attribute dev_attr_##_prefix##_##_name =	\
-+struct class_device_attribute class_device_attr_##_prefix##_##_name =	\
- 	__ATTR(_name,_mode,_show,_store)
- 
- /*
-@@ -1578,10 +1597,9 @@ struct device_attribute dev_attr_##_prefix##_##_name =	\
-  */
- #define iscsi_conn_attr_show(param)					\
- static ssize_t								\
--show_conn_param_##param(struct device *dev, 				\
--			struct device_attribute *attr, char *buf)	\
-+show_conn_param_##param(struct class_device *cdev, char *buf)		\
- {									\
--	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent);	\
-+	struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev);		\
- 	struct iscsi_transport *t = conn->transport;			\
- 	return t->get_conn_param(conn, param, buf);			\
- }
-@@ -1605,16 +1623,17 @@ iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
- iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
- iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
- 
-+#define iscsi_cdev_to_session(_cdev) \
-+	iscsi_dev_to_session(_cdev->dev)
-+
- /*
-  * iSCSI session attrs
-  */
- #define iscsi_session_attr_show(param, perm)				\
- static ssize_t								\
--show_session_param_##param(struct device *dev,				\
--			   struct device_attribute *attr, char *buf)	\
-+show_session_param_##param(struct class_device *cdev, char *buf)	\
- {									\
--	struct iscsi_cls_session *session = 				\
--		iscsi_dev_to_session(dev->parent);			\
-+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
- 	struct iscsi_transport *t = session->transport;			\
- 									\
- 	if (perm && !capable(CAP_SYS_ADMIN))				\
-@@ -1648,10 +1667,9 @@ iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
- iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
- 
- static ssize_t
--show_priv_session_state(struct device *dev, struct device_attribute *attr,
--			char *buf)
-+show_priv_session_state(struct class_device *cdev, char *buf)
- {
--	struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
-+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);
- 	return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
- }
- static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-@@ -1659,11 +1677,9 @@ static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
- 
- #define iscsi_priv_session_attr_show(field, format)			\
- static ssize_t								\
--show_priv_session_##field(struct device *dev, 				\
--			  struct device_attribute *attr, char *buf)	\
-+show_priv_session_##field(struct class_device *cdev, char *buf)		\
- {									\
--	struct iscsi_cls_session *session = 				\
--			iscsi_dev_to_session(dev->parent);		\
-+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\
- 	return sprintf(buf, format"\n", session->field);		\
- }
- 
-@@ -1678,10 +1694,9 @@ iscsi_priv_session_attr(recovery_tmo, "%d");
-  */
- #define iscsi_host_attr_show(param)					\
- static ssize_t								\
--show_host_param_##param(struct device *dev, 				\
--			struct device_attribute *attr, char *buf)	\
-+show_host_param_##param(struct class_device *cdev, char *buf)		\
- {									\
--	struct Scsi_Host *shost = transport_class_to_shost(dev);	\
-+	struct Scsi_Host *shost = transport_class_to_shost(cdev);	\
- 	struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
- 	return priv->iscsi_transport->get_host_param(shost, param, buf); \
- }
-@@ -1698,7 +1713,7 @@ iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
- 
- #define SETUP_PRIV_SESSION_RD_ATTR(field)				\
- do {									\
--	priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
-+	priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
- 	count++;							\
- } while (0)
- 
-@@ -1706,7 +1721,7 @@ do {									\
- #define SETUP_SESSION_RD_ATTR(field, param_flag)			\
- do {									\
- 	if (tt->param_mask & param_flag) {				\
--		priv->session_attrs[count] = &dev_attr_sess_##field; \
-+		priv->session_attrs[count] = &class_device_attr_sess_##field; \
- 		count++;						\
- 	}								\
- } while (0)
-@@ -1714,7 +1729,7 @@ do {									\
- #define SETUP_CONN_RD_ATTR(field, param_flag)				\
- do {									\
- 	if (tt->param_mask & param_flag) {				\
--		priv->conn_attrs[count] = &dev_attr_conn_##field; \
-+		priv->conn_attrs[count] = &class_device_attr_conn_##field; \
- 		count++;						\
- 	}								\
- } while (0)
-@@ -1722,7 +1737,7 @@ do {									\
- #define SETUP_HOST_RD_ATTR(field, param_flag)				\
- do {									\
- 	if (tt->host_param_mask & param_flag) {				\
--		priv->host_attrs[count] = &dev_attr_host_##field; \
-+		priv->host_attrs[count] = &class_device_attr_host_##field; \
- 		count++;						\
- 	}								\
- } while (0)
-@@ -1811,19 +1826,21 @@ iscsi_register_transport(struct iscsi_transport *tt)
+@@ -1576,7 +1584,10 @@ iscsi_register_transport(struct iscsi_transport *tt)
  	INIT_LIST_HEAD(&priv->list);
  	priv->daemon_pid = -1;
  	priv->iscsi_transport = tt;
++
 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
  	priv->t.user_scan = iscsi_user_scan;
 +#endif
- 	if (!(tt->caps & CAP_DATA_PATH_OFFLOAD))
- 		priv->t.create_work_queue = 1;
- 
--	priv->dev.class = &iscsi_transport_class;
--	snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name);
--	err = device_register(&priv->dev);
-+	priv->cdev.class = &iscsi_transport_class;
-+	snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
-+	err = class_device_register(&priv->cdev);
- 	if (err)
- 		goto free_priv;
- 
--	err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
-+	err = sysfs_create_group(&priv->cdev.kobj, &iscsi_transport_group);
- 	if (err)
--		goto unregister_dev;
-+		goto unregister_cdev;
- 
- 	/* host parameters */
- 	priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
-@@ -1902,9 +1919,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
- 	printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
- 	return &priv->t;
- 
--unregister_dev:
--	device_unregister(&priv->dev);
--	return NULL;
-+unregister_cdev:
-+	class_device_unregister(&priv->cdev);
- free_priv:
- 	kfree(priv);
- 	return NULL;
-@@ -1931,8 +1947,8 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
- 	transport_container_unregister(&priv->session_cont);
- 	transport_container_unregister(&priv->t.host_attrs);
- 
--	sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
--	device_unregister(&priv->dev);
-+	sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
-+	class_device_unregister(&priv->cdev);
- 	mutex_unlock(&rx_queue_mutex);
  
+ 	priv->cdev.class = &iscsi_transport_class;
+ 	snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
+@@ -1738,7 +1749,7 @@ static __init int iscsi_transport_init(void)
  	return 0;
-@@ -1952,13 +1968,14 @@ static __init int iscsi_transport_init(void)
- 	if (err)
- 		return err;
- 
-+#if 0
- 	err = class_register(&iscsi_endpoint_class);
- 	if (err)
- 		goto unregister_transport_class;
--
-+#endif
- 	err = transport_class_register(&iscsi_host_class);
- 	if (err)
--		goto unregister_endpoint_class;
-+		goto unregister_transport_class;
- 
- 	err = transport_class_register(&iscsi_connection_class);
- 	if (err)
-@@ -1989,8 +2006,10 @@ unregister_conn_class:
- 	transport_class_unregister(&iscsi_connection_class);
- unregister_host_class:
- 	transport_class_unregister(&iscsi_host_class);
-+#if 0
- unregister_endpoint_class:
- 	class_unregister(&iscsi_endpoint_class);
-+#endif
- unregister_transport_class:
- 	class_unregister(&iscsi_transport_class);
- 	return err;
-@@ -2003,7 +2022,9 @@ static void __exit iscsi_transport_exit(void)
+ 
+ release_nls:
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ unregister_session_class:
+ 	transport_class_unregister(&iscsi_session_class);
+ unregister_conn_class:
+@@ -1753,7 +1764,7 @@ unregister_transport_class:
+ static void __exit iscsi_transport_exit(void)
+ {
+ 	destroy_workqueue(iscsi_eh_timer_workq);
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
  	transport_class_unregister(&iscsi_connection_class);
  	transport_class_unregister(&iscsi_session_class);
  	transport_class_unregister(&iscsi_host_class);
-+#if 0
- 	class_unregister(&iscsi_endpoint_class);
-+#endif
- 	class_unregister(&iscsi_transport_class);
- }
- 
 diff --git a/scsi_transport_iscsi.h b/scsi_transport_iscsi.h
-index b65c96a..15b1f0e 100644
+index 3492abe..faa435c 100644
 --- a/scsi_transport_iscsi.h
 +++ b/scsi_transport_iscsi.h
-@@ -25,9 +25,14 @@
+@@ -25,8 +25,12 @@
  
  #include <linux/device.h>
  #include <linux/list.h>
@@ -1206,20 +571,18 @@
  #include <linux/mutex.h>
 +#endif
  #include "iscsi_if.h"
++#include "iscsi_compat.h"
  
-+#include "open_iscsi_compat.h"
-+
  struct scsi_transport_template;
  struct iscsi_transport;
- struct iscsi_endpoint;
-@@ -175,7 +180,7 @@ struct iscsi_cls_session {
+@@ -184,7 +188,7 @@ struct iscsi_cls_session {
  
  	/* recovery fields */
  	int recovery_tmo;
 -	struct delayed_work recovery_work;
 +	struct work_struct recovery_work;
  
- 	unsigned int target_id;
+ 	int target_id;
  
 -- 
 1.5.4.1
--- open-iscsi-2.0.870~rc3.orig/kernel/2.6.20-21_compat.patch
+++ open-iscsi-2.0.870~rc3/kernel/2.6.20-21_compat.patch
@@ -1,448 +1,48 @@
-diff --git a/iscsi_tcp.c b/iscsi_tcp.c
-index d074146..4a01066 100644
---- a/iscsi_tcp.c
-+++ b/iscsi_tcp.c
-@@ -426,6 +426,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment,
- 
- 	debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
- 		  offset, size);
-+
-+	/*
-+	 * older kernels could send use_sg=0 for commands like sgio
-+	 * or scsi-ml commands.
-+	 */
-+	if (!sg_count) {
-+		iscsi_segment_init_linear(segment, (void *)sg_list + offset,
-+					  size, done, hash);
-+		return 0;
-+	}
-+
- 	__iscsi_segment_init(segment, size, done, hash);
- 	for_each_sg(sg_list, sg, sg_count, i) {
- 		debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
-@@ -534,7 +545,7 @@ iscsi_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
- 	struct iscsi_tcp_task *tcp_task = task->dd_data;
- 	struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
- 	int datasn = be32_to_cpu(rhdr->datasn);
--	unsigned total_in_length = scsi_in(task->sc)->length;
-+	unsigned total_in_length = scsi_bufflen(task->sc);
- 
- 	iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
- 	if (tcp_conn->in.datalen == 0)
-@@ -660,11 +671,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- 			    r2t->data_length, session->max_burst);
- 
- 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
--	if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
-+	if (r2t->data_offset + r2t->data_length > scsi_bufflen(task->sc)) {
- 		iscsi_conn_printk(KERN_ERR, conn,
- 				  "invalid R2T with data len %u at offset %u "
- 				  "and total length %d\n", r2t->data_length,
--				  r2t->data_offset, scsi_out(task->sc)->length);
-+				  r2t->data_offset, scsi_bufflen(task->sc));
- 		__kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- 			    sizeof(void*));
- 		return ISCSI_ERR_DATALEN;
-@@ -764,7 +775,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- 		if (tcp_conn->in.datalen) {
- 			struct iscsi_tcp_task *tcp_task = task->dd_data;
- 			struct hash_desc *rx_hash = NULL;
--			struct scsi_data_buffer *sdb = scsi_in(task->sc);
- 
- 			/*
- 			 * Setup copy of Data-In into the Scsi_Cmnd
-@@ -782,8 +792,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- 				  tcp_task->data_offset,
- 				  tcp_conn->in.datalen);
- 			rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
--						   sdb->table.sgl,
--						   sdb->table.nents,
-+						   scsi_sglist(task->sc),
-+						   scsi_sg_count(task->sc),
- 						   tcp_task->data_offset,
- 						   tcp_conn->in.datalen,
- 						   iscsi_tcp_process_data_in,
-@@ -1352,8 +1362,8 @@ iscsi_tcp_task_init(struct iscsi_task *task)
- 		return 0;
- 
- 	/* If we have immediate data, attach a payload */
--	err = iscsi_tcp_send_data_prep(conn, scsi_out(sc)->table.sgl,
--				       scsi_out(sc)->table.nents,
-+	err = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+				       scsi_sg_count(sc),
- 				       0, task->imm_count);
- 	if (err)
- 		return err;
-@@ -1376,7 +1386,6 @@ iscsi_tcp_task_xmit(struct iscsi_task *task)
- 	struct iscsi_conn *conn = task->conn;
- 	struct iscsi_tcp_task *tcp_task = task->dd_data;
- 	struct scsi_cmnd *sc = task->sc;
--	struct scsi_data_buffer *sdb;
- 	int rc = 0;
- 
- flush:
-@@ -1396,7 +1405,6 @@ flush:
- 	if (sc->sc_data_direction != DMA_TO_DEVICE)
- 		return 0;
- 
--	sdb = scsi_out(sc);
- 	if (task->unsol_count != 0) {
- 		struct iscsi_data *hdr = &tcp_task->unsol_dtask.hdr;
- 
-@@ -1411,8 +1419,8 @@ flush:
- 				task->itt, tcp_task->sent, task->data_count);
- 
- 		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
--		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
--					      sdb->table.nents, tcp_task->sent,
-+		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+					      scsi_sg_count(sc), tcp_task->sent,
- 					      task->data_count);
- 		if (rc)
- 			goto fail;
-@@ -1458,8 +1466,8 @@ flush:
- 		iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr,
- 					sizeof(struct iscsi_hdr));
- 
--		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
--					      sdb->table.nents,
-+		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+					      scsi_sg_count(sc),
- 					      r2t->data_offset + r2t->sent,
- 					      r2t->data_count);
- 		if (rc)
-@@ -1847,7 +1855,11 @@ iscsi_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
- 	shost->max_lun = iscsi_max_lun;
- 	shost->max_id = 0;
- 	shost->max_channel = 0;
-+#ifndef SCSI_MAX_VARLEN_CDB_SIZE
-+	shost->max_cmd_len = 16;
-+#else
- 	shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE;
-+#endif
- 
- 	if (iscsi_host_add(shost, NULL))
- 		goto free_host;
-@@ -1900,6 +1912,9 @@ static int iscsi_tcp_slave_configure(struct scsi_device *sdev)
- }
- 
- static struct scsi_host_template iscsi_sht = {
-+#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,24)
-+	.use_sg_chaining	= ENABLE_SG_CHAINING,
-+#endif
- 	.module			= THIS_MODULE,
- 	.name			= "iSCSI Initiator over TCP/IP",
- 	.queuecommand           = iscsi_queuecommand,
-diff --git a/iscsi_tcp.h b/iscsi_tcp.h
-index 68423e8..1796c96 100644
---- a/iscsi_tcp.h
-+++ b/iscsi_tcp.h
-@@ -24,6 +24,8 @@
- 
- #include "libiscsi.h"
- 
-+#include "open_iscsi_compat.h"
-+
- struct crypto_hash;
- struct socket;
- struct iscsi_tcp_conn;
-diff --git a/libiscsi.c b/libiscsi.c
-index f3b845f..80da87f 100644
---- a/libiscsi.c
-+++ b/libiscsi.c
-@@ -187,7 +187,7 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
- 						  sizeof(rlen_ahdr->reserved));
- 	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
- 	rlen_ahdr->reserved = 0;
--	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
-+	rlen_ahdr->read_length = cpu_to_be32(scsi_bufflen(sc));
- 
- 	debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
- 		   "rlen_ahdr->ahslength(%d)\n",
-@@ -242,7 +242,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- 			return rc;
- 	}
- 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
--		unsigned out_len = scsi_out(sc)->length;
-+		unsigned out_len = scsi_bufflen(sc);
- 		hdr->data_length = cpu_to_be32(out_len);
- 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
- 		/*
-@@ -286,7 +286,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- 	} else {
- 		hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- 		zero_data(hdr->dlength);
--		hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
-+		hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
- 
- 		if (sc->sc_data_direction == DMA_FROM_DEVICE)
- 			hdr->flags |= ISCSI_FLAG_CMD_READ;
-@@ -314,7 +314,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- 		   "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ?
- 		   "write" : "read", conn->id, sc, sc->cmnd[0], task->itt,
- 		   scsi_bufflen(sc),
--		   scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
-+		   scsi_bidi_cmnd(sc) ? scsi_bufflen(sc) : 0,
- 		   session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
- 	return 0;
- }
-@@ -407,12 +407,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
- 		conn->session->tt->cleanup_task(conn, task);
- 
- 	sc->result = err;
--	if (!scsi_bidi_cmnd(sc))
--		scsi_set_resid(sc, scsi_bufflen(sc));
--	else {
--		scsi_out(sc)->resid = scsi_out(sc)->length;
--		scsi_in(sc)->resid = scsi_in(sc)->length;
--	}
-+	scsi_set_resid(sc, scsi_bufflen(sc));
- 
- 	if (conn->task == task)
- 		conn->task = NULL;
-@@ -587,7 +582,7 @@ invalid_datalen:
- 			goto out;
- 		}
- 
--		senselen = get_unaligned_be16(data);
-+		senselen = be16_to_cpu(get_unaligned((__be16 *) data));
- 		if (datalen < senselen)
- 			goto invalid_datalen;
- 
-@@ -603,8 +598,8 @@ invalid_datalen:
- 
- 		if (scsi_bidi_cmnd(sc) && res_count > 0 &&
- 				(rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
--				 res_count <= scsi_in(sc)->length))
--			scsi_in(sc)->resid = res_count;
-+				 res_count <= scsi_bufflen(sc)))
-+			scsi_set_resid(sc, res_count);
- 		else
- 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- 	}
-@@ -653,8 +648,8 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- 
- 		if (res_count > 0 &&
- 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
--		     res_count <= scsi_in(sc)->length))
--			scsi_in(sc)->resid = res_count;
-+		     res_count <= scsi_bufflen(sc)))
-+			scsi_set_resid(sc, res_count);
- 		else
- 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- 	}
-@@ -1297,12 +1292,7 @@ reject:
- fault:
- 	spin_unlock(&session->lock);
- 	debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
--	if (!scsi_bidi_cmnd(sc))
--		scsi_set_resid(sc, scsi_bufflen(sc));
--	else {
--		scsi_out(sc)->resid = scsi_out(sc)->length;
--		scsi_in(sc)->resid = scsi_in(sc)->length;
--	}
-+	scsi_set_resid(sc, scsi_bufflen(sc));
- 	done(sc);
- 	spin_lock(host->host_lock);
- 	return 0;
-diff --git a/libiscsi.h b/libiscsi.h
-index cfc5fa6..64508d8 100644
---- a/libiscsi.h
-+++ b/libiscsi.h
-@@ -32,6 +32,8 @@
- #include "iscsi_proto.h"
- #include "iscsi_if.h"
- 
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct scsi_host_template;
- struct scsi_device;
-diff --git a/open_iscsi_compat.h b/open_iscsi_compat.h
+diff --git a/iscsi_2.6.22_compat.h b/iscsi_2.6.22_compat.h
 new file mode 100644
-index 0000000..8bd48d1
+index 0000000..2ba7deb
 --- /dev/null
-+++ b/open_iscsi_compat.h
-@@ -0,0 +1,246 @@
++++ b/iscsi_2.6.22_compat.h
+@@ -0,0 +1,85 @@
 +#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <scsi/scsi.h>
 +#include <scsi/scsi_cmnd.h>
 +
-+#ifndef OPEN_ISCSI_COMPAT
-+#define OPEN_ISCSI_COMPAT
-+
-+#ifndef SCAN_WILD_CARD
-+#define SCAN_WILD_CARD  ~0
-+#endif
-+
-+#ifndef NIPQUAD_FMT
-+#define NIPQUAD_FMT "%u.%u.%u.%u"
-+#endif
-+
-+#ifndef NIP6_FMT
-+#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-+#endif
-+
-+#ifndef DEFINE_MUTEX
-+
-+/* mutex changes from 2.6.16-rc1 and up */
-+#define DEFINE_MUTEX DECLARE_MUTEX
-+#define mutex_lock down
-+#define mutex_unlock up
-+#define mutex semaphore
-+#define mutex_init init_MUTEX
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12)
-+
-+void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun)
-+{
-+	int i;
-+
-+	memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
-+
-+	for (i = 0; i < sizeof(lun); i += 2) {
-+		scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
-+		scsilun->scsi_lun[i+1] = lun & 0xFF;
-+		lun = lun >> 16;
-+	}
-+}
-+
-+#define __nlmsg_put(skb, daemon_pid, seq, type, len, flags) \
-+	__nlmsg_put(skb, daemon_pid, 0, 0, len)
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define gfp_t unsigned
-+
-+void *kzalloc(size_t size, gfp_t flags)
-+{
-+	void *ret = kmalloc(size, flags);
-+	if (ret)
-+		memset(ret, 0, size);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+
-+#include "linux/crypto.h"
-+
-+#define CRYPTO_ALG_ASYNC		0x00000080
-+struct hash_desc
-+{
-+	struct crypto_tfm *tfm;
-+	u32 flags;
-+};
-+
-+static inline int crypto_hash_init(struct hash_desc *desc)
-+{
-+	crypto_digest_init(desc->tfm);
-+	return 0;
-+}
-+
-+static inline int crypto_hash_digest(struct hash_desc *desc,
-+				     struct scatterlist *sg,
-+				     unsigned int nbytes, u8 *out)
-+{
-+	crypto_digest_digest(desc->tfm, sg, 1, out);
-+	return nbytes;
-+}
-+
-+static inline int crypto_hash_update(struct hash_desc *desc,
-+				     struct scatterlist *sg,
-+				     unsigned int nbytes)
-+{
-+	crypto_digest_update(desc->tfm, sg, 1);
-+	return nbytes;
-+}
-+
-+static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
-+{
-+	crypto_digest_final(desc->tfm, out);
-+	return 0;
-+}
-+
-+static inline struct crypto_tfm *crypto_alloc_hash(const char *alg_name,
-+						    u32 type, u32 mask)
-+{
-+	struct crypto_tfm *ret = crypto_alloc_tfm(alg_name ,type);
-+	return ret ? ret : ERR_PTR(-ENOMEM);
-+}
-+
-+static inline void crypto_free_hash(struct crypto_tfm *tfm)
-+{
-+	crypto_free_tfm(tfm);
-+}
-+
-+int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
-+			int *addrlen)
-+{
-+	return sock->ops->getname(sock, addr, addrlen, 0);
-+}
-+
-+int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
-+			int *addrlen)
-+{
-+	return sock->ops->getname(sock, addr, addrlen, 1);
-+}
-+
-+#endif
++#ifndef ISCSI_2622_COMPAT_H
++#define ISCSI_2622_COMPAT_H
 +
 +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
 +
-+static inline int is_power_of_2(unsigned long n)
++static inline __attribute__((const))
++bool is_power_of_2(unsigned long n)
 +{
-+	return (n != 0 && ((n & (n - 1)) == 0));
++        return (n != 0 && ((n & (n - 1)) == 0));
 +}
 +#endif
 +
 +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
 +
++#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
++	netlink_kernel_create(uint, groups, input, mod)
++
 +static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
 +{
 +	return (struct nlmsghdr *)skb->data;
 +}
 +
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+	return (void *)shost->hostdata;
-+}
++#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
 +
-+/*
-+ * Note: We do not support bidi for the compat modules if the kernel
-+ * does not have support.
-+ */
-+#define scsi_sg_count(cmd) ((cmd)->use_sg)
-+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
-+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
++#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
++	netlink_kernel_create(uint, groups, input, cb_mutex, mod)
 +
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+	cmd->resid = resid;
-+}
++#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
 +
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+	return cmd->resid;
-+}
++#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
++	netlink_kernel_create(uint, groups, input, cb_mutex, mod)
 +
 +#endif
 +
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+static inline unsigned long rounddown_pow_of_two(unsigned long n)
-+{
-+	return 1UL << (fls_long(n) - 1);
-+}
 +
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
 +
 +static inline struct scatterlist *sg_next(struct scatterlist *sg)
 +{
@@ -472,192 +72,93 @@
 +}
 +#endif
 +
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
++#define scsi_sg_count(cmd) ((cmd)->use_sg)
++#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
++#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
 +
-+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
++static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
 +{
-+	return 0;
++	cmd->resid = resid;
 +}
 +
-+#define netlink_kernel_release(_nls) \
-+	sock_release(_nls->sk_socket)
-+
-+
++static inline int scsi_get_resid(struct scsi_cmnd *cmd)
++{
++	return cmd->resid;
++}
 +#endif
 +
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+	netlink_kernel_create(uint, input)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+	netlink_kernel_create(uint, groups, input, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+	netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+	netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
 +#endif
+diff --git a/iscsi_tcp.c b/iscsi_tcp.c
+index 0d21d87..b24e533 100644
+--- a/iscsi_tcp.c
++++ b/iscsi_tcp.c
+@@ -422,6 +422,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment,
+ 
+ 	debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
+ 		  offset, size);
 +
++	/*
++	 * older kernels could send use_sg=0 for commands like sgio
++	 * or scsi-ml commands.
++	 */
++	if (!sg_count) {
++		iscsi_segment_init_linear(segment, (void *)sg_list + offset,
++					  size, done, hash);
++		return 0;
++	}
 +
+ 	__iscsi_segment_init(segment, size, done, hash);
+ 	for_each_sg(sg_list, sg, sg_count, i) {
+ 		debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
+@@ -1936,6 +1947,9 @@ static struct scsi_host_template iscsi_sht = {
+ 	.eh_device_reset_handler= iscsi_eh_device_reset,
+ 	.eh_host_reset_handler	= iscsi_eh_host_reset,
+ 	.use_clustering         = DISABLE_CLUSTERING,
++#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,24)
++	.use_sg_chaining	= ENABLE_SG_CHAINING,
 +#endif
-diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c
-index 852b016..f4270b2 100644
---- a/scsi_transport_iscsi.c
-+++ b/scsi_transport_iscsi.c
-@@ -41,13 +41,13 @@ struct iscsi_internal {
- 	struct scsi_transport_template t;
- 	struct iscsi_transport *iscsi_transport;
- 	struct list_head list;
--	struct device dev;
-+	struct class_device cdev;
- 
--	struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
-+	struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
- 	struct transport_container conn_cont;
--	struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
-+	struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
- 	struct transport_container session_cont;
--	struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
-+	struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
- };
- 
- static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
-@@ -64,12 +64,12 @@ static DEFINE_SPINLOCK(iscsi_transport_lock);
- #define to_iscsi_internal(tmpl) \
- 	container_of(tmpl, struct iscsi_internal, t)
- 
--#define dev_to_iscsi_internal(_dev) \
--	container_of(_dev, struct iscsi_internal, dev)
-+#define cdev_to_iscsi_internal(_cdev) \
-+	container_of(_cdev, struct iscsi_internal, cdev)
- 
--static void iscsi_transport_release(struct device *dev)
-+static void iscsi_transport_release(struct class_device *cdev)
- {
--	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- 	kfree(priv);
- }
- 
-@@ -79,33 +79,31 @@ static void iscsi_transport_release(struct device *dev)
-  */
- static struct class iscsi_transport_class = {
- 	.name = "iscsi_transport",
--	.dev_release = iscsi_transport_release,
-+	.release = iscsi_transport_release,
- };
- 
- static ssize_t
--show_transport_handle(struct device *dev, struct device_attribute *attr,
--		      char *buf)
-+show_transport_handle(struct class_device *cdev, char *buf)
- {
--	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- 	return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
- }
--static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-+static CLASS_DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
- 
- #define show_transport_attr(name, format)				\
- static ssize_t								\
--show_transport_##name(struct device *dev, 				\
--		      struct device_attribute *attr,char *buf)		\
-+show_transport_##name(struct class_device *cdev, char *buf)		\
- {									\
--	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);	\
-+	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);	\
- 	return sprintf(buf, format"\n", priv->iscsi_transport->name);	\
- }									\
--static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
- 
- show_transport_attr(caps, "0x%x");
- 
- static struct attribute *iscsi_transport_attrs[] = {
--	&dev_attr_handle.attr,
--	&dev_attr_caps.attr,
-+	&class_device_attr_handle.attr,
-+	&class_device_attr_caps.attr,
- 	NULL,
- };
- 
-@@ -113,6 +111,7 @@ static struct attribute_group iscsi_transport_group = {
- 	.attrs = iscsi_transport_attrs,
- };
+ 	.slave_configure        = iscsi_tcp_slave_configure,
+ 	.proc_name		= "iscsi_tcp",
+ 	.this_id		= -1,
+diff --git a/iscsi_tcp.h b/iscsi_tcp.h
+index 950d75f..a7bc56f 100644
+--- a/iscsi_tcp.h
++++ b/iscsi_tcp.h
+@@ -24,6 +24,7 @@
  
-+#if 0
- /*
-  * iSCSI endpoint attrs
-  */
-@@ -237,9 +236,10 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
- 	return ep;
- }
- EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
-+#endif
+ #include "libiscsi.h"
  
- static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
--			    struct device *cdev)
-+			    struct class_device *cdev)
- {
- 	struct Scsi_Host *shost = dev_to_shost(dev);
- 	struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -258,7 +258,7 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
- }
++#include "iscsi_2.6.22_compat.h"
+ struct crypto_hash;
+ struct socket;
+ struct iscsi_tcp_conn;
+diff --git a/libiscsi.h b/libiscsi.h
+index 6f10518..995852f 100644
+--- a/libiscsi.h
++++ b/libiscsi.h
+@@ -30,6 +30,8 @@
+ #include "iscsi_proto.h"
+ #include "iscsi_if.h"
  
- static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
--			     struct device *cdev)
-+			     struct class_device *cdev)
- {
- 	struct Scsi_Host *shost = dev_to_shost(dev);
- 	struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -1308,6 +1308,8 @@ static int
- iscsi_if_transport_ep(struct iscsi_transport *transport,
- 		      struct iscsi_uevent *ev, int msg_type)
- {
-+	return -ENOSYS;
-+#if 0
- 	struct iscsi_endpoint *ep;
- 	struct sockaddr *dst_addr;
- 	int rc = 0;
-@@ -1348,6 +1350,8 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
- 		break;
- 	}
- 	return rc;
++#include "iscsi_2.6.22_compat.h"
 +
-+#endif
- }
+ struct scsi_transport_template;
+ struct scsi_device;
+ struct Scsi_Host;
+diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c
+index e8f8cf1..0ab82de 100644
+--- a/scsi_transport_iscsi.c
++++ b/scsi_transport_iscsi.c
+@@ -29,6 +29,7 @@
+ #include <scsi/scsi_transport.h>
+ #include "scsi_transport_iscsi.h"
+ #include "iscsi_if.h"
++#include "iscsi_2.6.22_compat.h"
  
- static int
-@@ -1429,6 +1433,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- 					      ev->u.c_session.queue_depth);
- 		break;
- 	case ISCSI_UEVENT_CREATE_BOUND_SESSION:
-+		err = -ENOSYS;
-+		break;
-+#if 0
- 		ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
- 		if (!ep) {
- 			err = -EINVAL;
-@@ -1440,6 +1447,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- 					ev->u.c_bound_session.cmds_max,
- 					ev->u.c_bound_session.queue_depth);
- 		break;
-+#endif
- 	case ISCSI_UEVENT_DESTROY_SESSION:
- 		session = iscsi_session_lookup(ev->u.d_session.sid);
- 		if (session)
-@@ -1522,55 +1530,70 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ #define ISCSI_SESSION_ATTRS 19
+ #define ISCSI_CONN_ATTRS 13
+@@ -1290,49 +1291,61 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
  }
  
  /*
@@ -754,222 +255,24 @@
  	}
  	mutex_unlock(&rx_queue_mutex);
  }
- 
-+#define iscsi_cdev_to_conn(_cdev) \
-+	iscsi_dev_to_conn(_cdev->dev)
-+
- #define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store)		\
--struct device_attribute dev_attr_##_prefix##_##_name =	\
-+struct class_device_attribute class_device_attr_##_prefix##_##_name =	\
- 	__ATTR(_name,_mode,_show,_store)
- 
- /*
-@@ -1578,10 +1601,9 @@ struct device_attribute dev_attr_##_prefix##_##_name =	\
-  */
- #define iscsi_conn_attr_show(param)					\
- static ssize_t								\
--show_conn_param_##param(struct device *dev, 				\
--			struct device_attribute *attr, char *buf)	\
-+show_conn_param_##param(struct class_device *cdev, char *buf)		\
- {									\
--	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent);	\
-+	struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev);		\
- 	struct iscsi_transport *t = conn->transport;			\
- 	return t->get_conn_param(conn, param, buf);			\
- }
-@@ -1605,16 +1627,17 @@ iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
- iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
- iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
- 
-+#define iscsi_cdev_to_session(_cdev) \
-+	iscsi_dev_to_session(_cdev->dev)
-+
- /*
-  * iSCSI session attrs
-  */
- #define iscsi_session_attr_show(param, perm)				\
- static ssize_t								\
--show_session_param_##param(struct device *dev,				\
--			   struct device_attribute *attr, char *buf)	\
-+show_session_param_##param(struct class_device *cdev, char *buf)	\
- {									\
--	struct iscsi_cls_session *session = 				\
--		iscsi_dev_to_session(dev->parent);			\
-+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
- 	struct iscsi_transport *t = session->transport;			\
- 									\
- 	if (perm && !capable(CAP_SYS_ADMIN))				\
-@@ -1648,10 +1671,9 @@ iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
- iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
- 
- static ssize_t
--show_priv_session_state(struct device *dev, struct device_attribute *attr,
--			char *buf)
-+show_priv_session_state(struct class_device *cdev, char *buf)
- {
--	struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
-+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);
- 	return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
- }
- static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-@@ -1659,11 +1681,9 @@ static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
- 
- #define iscsi_priv_session_attr_show(field, format)			\
- static ssize_t								\
--show_priv_session_##field(struct device *dev, 				\
--			  struct device_attribute *attr, char *buf)	\
-+show_priv_session_##field(struct class_device *cdev, char *buf)		\
- {									\
--	struct iscsi_cls_session *session = 				\
--			iscsi_dev_to_session(dev->parent);		\
-+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\
- 	return sprintf(buf, format"\n", session->field);		\
- }
- 
-@@ -1678,10 +1698,9 @@ iscsi_priv_session_attr(recovery_tmo, "%d");
-  */
- #define iscsi_host_attr_show(param)					\
- static ssize_t								\
--show_host_param_##param(struct device *dev, 				\
--			struct device_attribute *attr, char *buf)	\
-+show_host_param_##param(struct class_device *cdev, char *buf)		\
- {									\
--	struct Scsi_Host *shost = transport_class_to_shost(dev);	\
-+	struct Scsi_Host *shost = transport_class_to_shost(cdev);	\
- 	struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
- 	return priv->iscsi_transport->get_host_param(shost, param, buf); \
- }
-@@ -1698,7 +1717,7 @@ iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
- 
- #define SETUP_PRIV_SESSION_RD_ATTR(field)				\
- do {									\
--	priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
-+	priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
- 	count++;							\
- } while (0)
- 
-@@ -1706,7 +1725,7 @@ do {									\
- #define SETUP_SESSION_RD_ATTR(field, param_flag)			\
- do {									\
- 	if (tt->param_mask & param_flag) {				\
--		priv->session_attrs[count] = &dev_attr_sess_##field; \
-+		priv->session_attrs[count] = &class_device_attr_sess_##field; \
- 		count++;						\
- 	}								\
- } while (0)
-@@ -1714,7 +1733,7 @@ do {									\
- #define SETUP_CONN_RD_ATTR(field, param_flag)				\
- do {									\
- 	if (tt->param_mask & param_flag) {				\
--		priv->conn_attrs[count] = &dev_attr_conn_##field; \
-+		priv->conn_attrs[count] = &class_device_attr_conn_##field; \
- 		count++;						\
- 	}								\
- } while (0)
-@@ -1722,7 +1741,7 @@ do {									\
- #define SETUP_HOST_RD_ATTR(field, param_flag)				\
- do {									\
- 	if (tt->host_param_mask & param_flag) {				\
--		priv->host_attrs[count] = &dev_attr_host_##field; \
-+		priv->host_attrs[count] = &class_device_attr_host_##field; \
- 		count++;						\
- 	}								\
- } while (0)
-@@ -1815,15 +1834,15 @@ iscsi_register_transport(struct iscsi_transport *tt)
- 	if (!(tt->caps & CAP_DATA_PATH_OFFLOAD))
- 		priv->t.create_work_queue = 1;
- 
--	priv->dev.class = &iscsi_transport_class;
--	snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name);
--	err = device_register(&priv->dev);
-+	priv->cdev.class = &iscsi_transport_class;
-+	snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
-+	err = class_device_register(&priv->cdev);
- 	if (err)
- 		goto free_priv;
- 
--	err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
-+	err = sysfs_create_group(&priv->cdev.kobj, &iscsi_transport_group);
- 	if (err)
--		goto unregister_dev;
-+		goto unregister_cdev;
- 
- 	/* host parameters */
- 	priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
-@@ -1902,9 +1921,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
- 	printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
- 	return &priv->t;
- 
--unregister_dev:
--	device_unregister(&priv->dev);
--	return NULL;
-+unregister_cdev:
-+	class_device_unregister(&priv->cdev);
- free_priv:
- 	kfree(priv);
- 	return NULL;
-@@ -1931,8 +1949,8 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
- 	transport_container_unregister(&priv->session_cont);
- 	transport_container_unregister(&priv->t.host_attrs);
- 
--	sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
--	device_unregister(&priv->dev);
-+	sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
-+	class_device_unregister(&priv->cdev);
- 	mutex_unlock(&rx_queue_mutex);
- 
+@@ -1738,7 +1751,7 @@ static __init int iscsi_transport_init(void)
  	return 0;
-@@ -1952,13 +1970,14 @@ static __init int iscsi_transport_init(void)
- 	if (err)
- 		return err;
  
-+#if 0
- 	err = class_register(&iscsi_endpoint_class);
- 	if (err)
- 		goto unregister_transport_class;
--
-+#endif
- 	err = transport_class_register(&iscsi_host_class);
- 	if (err)
--		goto unregister_endpoint_class;
-+		goto unregister_transport_class;
- 
- 	err = transport_class_register(&iscsi_connection_class);
- 	if (err)
-@@ -1989,8 +2008,10 @@ unregister_conn_class:
- 	transport_class_unregister(&iscsi_connection_class);
- unregister_host_class:
- 	transport_class_unregister(&iscsi_host_class);
-+#if 0
- unregister_endpoint_class:
- 	class_unregister(&iscsi_endpoint_class);
-+#endif
- unregister_transport_class:
- 	class_unregister(&iscsi_transport_class);
- 	return err;
-@@ -2003,7 +2024,9 @@ static void __exit iscsi_transport_exit(void)
+ release_nls:
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ unregister_session_class:
+ 	transport_class_unregister(&iscsi_session_class);
+ unregister_conn_class:
+@@ -1753,7 +1766,7 @@ unregister_transport_class:
+ static void __exit iscsi_transport_exit(void)
+ {
+ 	destroy_workqueue(iscsi_eh_timer_workq);
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
  	transport_class_unregister(&iscsi_connection_class);
  	transport_class_unregister(&iscsi_session_class);
  	transport_class_unregister(&iscsi_host_class);
-+#if 0
- 	class_unregister(&iscsi_endpoint_class);
-+#endif
- 	class_unregister(&iscsi_transport_class);
- }
- 
-diff --git a/scsi_transport_iscsi.h b/scsi_transport_iscsi.h
-index b65c96a..9919c0d 100644
---- a/scsi_transport_iscsi.h
-+++ b/scsi_transport_iscsi.h
-@@ -28,6 +28,8 @@
- #include <linux/mutex.h>
- #include "iscsi_if.h"
- 
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct iscsi_transport;
- struct iscsi_endpoint;
 -- 
 1.5.4.1
 
--- open-iscsi-2.0.870~rc3.orig/kernel/2.6.24_compat.patch
+++ open-iscsi-2.0.870~rc3/kernel/2.6.24_compat.patch
@@ -1,881 +1,44 @@
 diff --git a/iscsi_tcp.c b/iscsi_tcp.c
-index d074146..4a01066 100644
+index 0d21d87..ed5cdfa 100644
 --- a/iscsi_tcp.c
 +++ b/iscsi_tcp.c
-@@ -426,6 +426,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment,
- 
- 	debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
- 		  offset, size);
-+
-+	/*
-+	 * older kernels could send use_sg=0 for commands like sgio
-+	 * or scsi-ml commands.
-+	 */
-+	if (!sg_count) {
-+		iscsi_segment_init_linear(segment, (void *)sg_list + offset,
-+					  size, done, hash);
-+		return 0;
-+	}
-+
- 	__iscsi_segment_init(segment, size, done, hash);
- 	for_each_sg(sg_list, sg, sg_count, i) {
- 		debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
-@@ -534,7 +545,7 @@ iscsi_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
- 	struct iscsi_tcp_task *tcp_task = task->dd_data;
- 	struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
- 	int datasn = be32_to_cpu(rhdr->datasn);
--	unsigned total_in_length = scsi_in(task->sc)->length;
-+	unsigned total_in_length = scsi_bufflen(task->sc);
- 
- 	iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
- 	if (tcp_conn->in.datalen == 0)
-@@ -660,11 +671,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- 			    r2t->data_length, session->max_burst);
- 
- 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
--	if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
-+	if (r2t->data_offset + r2t->data_length > scsi_bufflen(task->sc)) {
- 		iscsi_conn_printk(KERN_ERR, conn,
- 				  "invalid R2T with data len %u at offset %u "
- 				  "and total length %d\n", r2t->data_length,
--				  r2t->data_offset, scsi_out(task->sc)->length);
-+				  r2t->data_offset, scsi_bufflen(task->sc));
- 		__kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- 			    sizeof(void*));
- 		return ISCSI_ERR_DATALEN;
-@@ -764,7 +775,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- 		if (tcp_conn->in.datalen) {
- 			struct iscsi_tcp_task *tcp_task = task->dd_data;
- 			struct hash_desc *rx_hash = NULL;
--			struct scsi_data_buffer *sdb = scsi_in(task->sc);
- 
- 			/*
- 			 * Setup copy of Data-In into the Scsi_Cmnd
-@@ -782,8 +792,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- 				  tcp_task->data_offset,
- 				  tcp_conn->in.datalen);
- 			rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
--						   sdb->table.sgl,
--						   sdb->table.nents,
-+						   scsi_sglist(task->sc),
-+						   scsi_sg_count(task->sc),
- 						   tcp_task->data_offset,
- 						   tcp_conn->in.datalen,
- 						   iscsi_tcp_process_data_in,
-@@ -1352,8 +1362,8 @@ iscsi_tcp_task_init(struct iscsi_task *task)
- 		return 0;
- 
- 	/* If we have immediate data, attach a payload */
--	err = iscsi_tcp_send_data_prep(conn, scsi_out(sc)->table.sgl,
--				       scsi_out(sc)->table.nents,
-+	err = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+				       scsi_sg_count(sc),
- 				       0, task->imm_count);
- 	if (err)
- 		return err;
-@@ -1376,7 +1386,6 @@ iscsi_tcp_task_xmit(struct iscsi_task *task)
- 	struct iscsi_conn *conn = task->conn;
- 	struct iscsi_tcp_task *tcp_task = task->dd_data;
- 	struct scsi_cmnd *sc = task->sc;
--	struct scsi_data_buffer *sdb;
- 	int rc = 0;
- 
- flush:
-@@ -1396,7 +1405,6 @@ flush:
- 	if (sc->sc_data_direction != DMA_TO_DEVICE)
- 		return 0;
- 
--	sdb = scsi_out(sc);
- 	if (task->unsol_count != 0) {
- 		struct iscsi_data *hdr = &tcp_task->unsol_dtask.hdr;
- 
-@@ -1411,8 +1419,8 @@ flush:
- 				task->itt, tcp_task->sent, task->data_count);
- 
- 		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
--		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
--					      sdb->table.nents, tcp_task->sent,
-+		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+					      scsi_sg_count(sc), tcp_task->sent,
- 					      task->data_count);
- 		if (rc)
- 			goto fail;
-@@ -1458,8 +1466,8 @@ flush:
- 		iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr,
- 					sizeof(struct iscsi_hdr));
- 
--		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
--					      sdb->table.nents,
-+		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+					      scsi_sg_count(sc),
- 					      r2t->data_offset + r2t->sent,
- 					      r2t->data_count);
- 		if (rc)
-@@ -1847,7 +1855,11 @@ iscsi_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
- 	shost->max_lun = iscsi_max_lun;
- 	shost->max_id = 0;
- 	shost->max_channel = 0;
-+#ifndef SCSI_MAX_VARLEN_CDB_SIZE
-+	shost->max_cmd_len = 16;
-+#else
- 	shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE;
-+#endif
- 
- 	if (iscsi_host_add(shost, NULL))
- 		goto free_host;
-@@ -1900,6 +1912,9 @@ static int iscsi_tcp_slave_configure(struct scsi_device *sdev)
- }
+@@ -26,6 +26,7 @@
+  *	Zhenyu Wang
+  */
  
- static struct scsi_host_template iscsi_sht = {
++#include <linux/version.h>
+ #include <linux/types.h>
+ #include <linux/list.h>
+ #include <linux/inet.h>
+@@ -1936,6 +1937,9 @@ static struct scsi_host_template iscsi_sht = {
+ 	.eh_device_reset_handler= iscsi_eh_device_reset,
+ 	.eh_host_reset_handler	= iscsi_eh_host_reset,
+ 	.use_clustering         = DISABLE_CLUSTERING,
 +#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,24)
 +	.use_sg_chaining	= ENABLE_SG_CHAINING,
 +#endif
- 	.module			= THIS_MODULE,
- 	.name			= "iSCSI Initiator over TCP/IP",
- 	.queuecommand           = iscsi_queuecommand,
-diff --git a/iscsi_tcp.h b/iscsi_tcp.h
-index 68423e8..1796c96 100644
---- a/iscsi_tcp.h
-+++ b/iscsi_tcp.h
-@@ -24,6 +24,8 @@
- 
- #include "libiscsi.h"
- 
-+#include "open_iscsi_compat.h"
-+
- struct crypto_hash;
- struct socket;
- struct iscsi_tcp_conn;
-diff --git a/libiscsi.c b/libiscsi.c
-index f3b845f..80da87f 100644
---- a/libiscsi.c
-+++ b/libiscsi.c
-@@ -187,7 +187,7 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
- 						  sizeof(rlen_ahdr->reserved));
- 	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
- 	rlen_ahdr->reserved = 0;
--	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
-+	rlen_ahdr->read_length = cpu_to_be32(scsi_bufflen(sc));
- 
- 	debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
- 		   "rlen_ahdr->ahslength(%d)\n",
-@@ -242,7 +242,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- 			return rc;
- 	}
- 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
--		unsigned out_len = scsi_out(sc)->length;
-+		unsigned out_len = scsi_bufflen(sc);
- 		hdr->data_length = cpu_to_be32(out_len);
- 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
- 		/*
-@@ -286,7 +286,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- 	} else {
- 		hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- 		zero_data(hdr->dlength);
--		hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
-+		hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
- 
- 		if (sc->sc_data_direction == DMA_FROM_DEVICE)
- 			hdr->flags |= ISCSI_FLAG_CMD_READ;
-@@ -314,7 +314,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- 		   "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ?
- 		   "write" : "read", conn->id, sc, sc->cmnd[0], task->itt,
- 		   scsi_bufflen(sc),
--		   scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
-+		   scsi_bidi_cmnd(sc) ? scsi_bufflen(sc) : 0,
- 		   session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
- 	return 0;
- }
-@@ -407,12 +407,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
- 		conn->session->tt->cleanup_task(conn, task);
- 
- 	sc->result = err;
--	if (!scsi_bidi_cmnd(sc))
--		scsi_set_resid(sc, scsi_bufflen(sc));
--	else {
--		scsi_out(sc)->resid = scsi_out(sc)->length;
--		scsi_in(sc)->resid = scsi_in(sc)->length;
--	}
-+	scsi_set_resid(sc, scsi_bufflen(sc));
- 
- 	if (conn->task == task)
- 		conn->task = NULL;
-@@ -587,7 +582,7 @@ invalid_datalen:
- 			goto out;
- 		}
- 
--		senselen = get_unaligned_be16(data);
-+		senselen = be16_to_cpu(get_unaligned((__be16 *) data));
- 		if (datalen < senselen)
- 			goto invalid_datalen;
- 
-@@ -603,8 +598,8 @@ invalid_datalen:
- 
- 		if (scsi_bidi_cmnd(sc) && res_count > 0 &&
- 				(rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
--				 res_count <= scsi_in(sc)->length))
--			scsi_in(sc)->resid = res_count;
-+				 res_count <= scsi_bufflen(sc)))
-+			scsi_set_resid(sc, res_count);
- 		else
- 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- 	}
-@@ -653,8 +648,8 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- 
- 		if (res_count > 0 &&
- 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
--		     res_count <= scsi_in(sc)->length))
--			scsi_in(sc)->resid = res_count;
-+		     res_count <= scsi_bufflen(sc)))
-+			scsi_set_resid(sc, res_count);
- 		else
- 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- 	}
-@@ -1297,12 +1292,7 @@ reject:
- fault:
- 	spin_unlock(&session->lock);
- 	debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
--	if (!scsi_bidi_cmnd(sc))
--		scsi_set_resid(sc, scsi_bufflen(sc));
--	else {
--		scsi_out(sc)->resid = scsi_out(sc)->length;
--		scsi_in(sc)->resid = scsi_in(sc)->length;
--	}
-+	scsi_set_resid(sc, scsi_bufflen(sc));
- 	done(sc);
- 	spin_lock(host->host_lock);
- 	return 0;
-diff --git a/libiscsi.h b/libiscsi.h
-index cfc5fa6..64508d8 100644
---- a/libiscsi.h
-+++ b/libiscsi.h
-@@ -32,6 +32,8 @@
- #include "iscsi_proto.h"
- #include "iscsi_if.h"
- 
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct scsi_host_template;
- struct scsi_device;
-diff --git a/open_iscsi_compat.h b/open_iscsi_compat.h
-new file mode 100644
-index 0000000..8bd48d1
---- /dev/null
-+++ b/open_iscsi_compat.h
-@@ -0,0 +1,246 @@
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <scsi/scsi.h>
-+#include <scsi/scsi_cmnd.h>
-+
-+#ifndef OPEN_ISCSI_COMPAT
-+#define OPEN_ISCSI_COMPAT
-+
-+#ifndef SCAN_WILD_CARD
-+#define SCAN_WILD_CARD  ~0
-+#endif
-+
-+#ifndef NIPQUAD_FMT
-+#define NIPQUAD_FMT "%u.%u.%u.%u"
-+#endif
-+
-+#ifndef NIP6_FMT
-+#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-+#endif
-+
-+#ifndef DEFINE_MUTEX
-+
-+/* mutex changes from 2.6.16-rc1 and up */
-+#define DEFINE_MUTEX DECLARE_MUTEX
-+#define mutex_lock down
-+#define mutex_unlock up
-+#define mutex semaphore
-+#define mutex_init init_MUTEX
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12)
-+
-+void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun)
-+{
-+	int i;
-+
-+	memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
-+
-+	for (i = 0; i < sizeof(lun); i += 2) {
-+		scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
-+		scsilun->scsi_lun[i+1] = lun & 0xFF;
-+		lun = lun >> 16;
-+	}
-+}
-+
-+#define __nlmsg_put(skb, daemon_pid, seq, type, len, flags) \
-+	__nlmsg_put(skb, daemon_pid, 0, 0, len)
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define gfp_t unsigned
-+
-+void *kzalloc(size_t size, gfp_t flags)
-+{
-+	void *ret = kmalloc(size, flags);
-+	if (ret)
-+		memset(ret, 0, size);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+
-+#include "linux/crypto.h"
-+
-+#define CRYPTO_ALG_ASYNC		0x00000080
-+struct hash_desc
-+{
-+	struct crypto_tfm *tfm;
-+	u32 flags;
-+};
-+
-+static inline int crypto_hash_init(struct hash_desc *desc)
-+{
-+	crypto_digest_init(desc->tfm);
-+	return 0;
-+}
-+
-+static inline int crypto_hash_digest(struct hash_desc *desc,
-+				     struct scatterlist *sg,
-+				     unsigned int nbytes, u8 *out)
-+{
-+	crypto_digest_digest(desc->tfm, sg, 1, out);
-+	return nbytes;
-+}
-+
-+static inline int crypto_hash_update(struct hash_desc *desc,
-+				     struct scatterlist *sg,
-+				     unsigned int nbytes)
-+{
-+	crypto_digest_update(desc->tfm, sg, 1);
-+	return nbytes;
-+}
-+
-+static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
-+{
-+	crypto_digest_final(desc->tfm, out);
-+	return 0;
-+}
-+
-+static inline struct crypto_tfm *crypto_alloc_hash(const char *alg_name,
-+						    u32 type, u32 mask)
-+{
-+	struct crypto_tfm *ret = crypto_alloc_tfm(alg_name ,type);
-+	return ret ? ret : ERR_PTR(-ENOMEM);
-+}
-+
-+static inline void crypto_free_hash(struct crypto_tfm *tfm)
-+{
-+	crypto_free_tfm(tfm);
-+}
-+
-+int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
-+			int *addrlen)
-+{
-+	return sock->ops->getname(sock, addr, addrlen, 0);
-+}
-+
-+int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
-+			int *addrlen)
-+{
-+	return sock->ops->getname(sock, addr, addrlen, 1);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
-+
-+static inline int is_power_of_2(unsigned long n)
-+{
-+	return (n != 0 && ((n & (n - 1)) == 0));
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
-+{
-+	return (struct nlmsghdr *)skb->data;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+	return (void *)shost->hostdata;
-+}
-+
-+/*
-+ * Note: We do not support bidi for the compat modules if the kernel
-+ * does not have support.
-+ */
-+#define scsi_sg_count(cmd) ((cmd)->use_sg)
-+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
-+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
-+
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+	cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+	return cmd->resid;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+static inline unsigned long rounddown_pow_of_two(unsigned long n)
-+{
-+	return 1UL << (fls_long(n) - 1);
-+}
-+
-+
-+static inline struct scatterlist *sg_next(struct scatterlist *sg)
-+{
-+	if (!sg) {
-+		BUG();
-+		return NULL;
-+	}
-+	return sg + 1;
-+}
-+
-+#define for_each_sg(sglist, sg, nr, __i)        \
-+	for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
-+
-+#define sg_page(_sg) _sg->page
-+
-+static inline void sg_set_page(struct scatterlist *sg, struct page *page,
-+				unsigned int len, unsigned int offset)
-+{
-+	sg->page = page;
-+	sg->offset = offset;
-+	sg->length = len;
-+}
-+
-+static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
-+{
-+	memset(sgl, 0, sizeof(*sgl) * nents);
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
-+
-+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
-+{
-+	return 0;
-+}
-+
-+#define netlink_kernel_release(_nls) \
-+	sock_release(_nls->sk_socket)
-+
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+	netlink_kernel_create(uint, input)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+	netlink_kernel_create(uint, groups, input, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+	netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+	netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#endif
-+
-+
-+#endif
+ 	.slave_configure        = iscsi_tcp_slave_configure,
+ 	.proc_name		= "iscsi_tcp",
+ 	.this_id		= -1,
 diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c
-index 852b016..28c4d9f 100644
+index e8f8cf1..7c19201 100644
 --- a/scsi_transport_iscsi.c
 +++ b/scsi_transport_iscsi.c
-@@ -41,13 +41,13 @@ struct iscsi_internal {
- 	struct scsi_transport_template t;
- 	struct iscsi_transport *iscsi_transport;
- 	struct list_head list;
--	struct device dev;
-+	struct class_device cdev;
- 
--	struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
-+	struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
- 	struct transport_container conn_cont;
--	struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
-+	struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
- 	struct transport_container session_cont;
--	struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
-+	struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
- };
- 
- static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
-@@ -64,12 +64,12 @@ static DEFINE_SPINLOCK(iscsi_transport_lock);
- #define to_iscsi_internal(tmpl) \
- 	container_of(tmpl, struct iscsi_internal, t)
- 
--#define dev_to_iscsi_internal(_dev) \
--	container_of(_dev, struct iscsi_internal, dev)
-+#define cdev_to_iscsi_internal(_cdev) \
-+	container_of(_cdev, struct iscsi_internal, cdev)
- 
--static void iscsi_transport_release(struct device *dev)
-+static void iscsi_transport_release(struct class_device *cdev)
- {
--	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- 	kfree(priv);
- }
- 
-@@ -79,33 +79,31 @@ static void iscsi_transport_release(struct device *dev)
-  */
- static struct class iscsi_transport_class = {
- 	.name = "iscsi_transport",
--	.dev_release = iscsi_transport_release,
-+	.release = iscsi_transport_release,
- };
- 
- static ssize_t
--show_transport_handle(struct device *dev, struct device_attribute *attr,
--		      char *buf)
-+show_transport_handle(struct class_device *cdev, char *buf)
- {
--	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- 	return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
- }
--static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-+static CLASS_DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
- 
- #define show_transport_attr(name, format)				\
- static ssize_t								\
--show_transport_##name(struct device *dev, 				\
--		      struct device_attribute *attr,char *buf)		\
-+show_transport_##name(struct class_device *cdev, char *buf)		\
- {									\
--	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);	\
-+	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);	\
- 	return sprintf(buf, format"\n", priv->iscsi_transport->name);	\
- }									\
--static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
- 
- show_transport_attr(caps, "0x%x");
- 
- static struct attribute *iscsi_transport_attrs[] = {
--	&dev_attr_handle.attr,
--	&dev_attr_caps.attr,
-+	&class_device_attr_handle.attr,
-+	&class_device_attr_caps.attr,
- 	NULL,
- };
- 
-@@ -113,6 +111,7 @@ static struct attribute_group iscsi_transport_group = {
- 	.attrs = iscsi_transport_attrs,
- };
- 
-+#if 0
- /*
-  * iSCSI endpoint attrs
-  */
-@@ -237,9 +236,10 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
- 	return ep;
- }
- EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
-+#endif
- 
- static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
--			    struct device *cdev)
-+			    struct class_device *cdev)
- {
- 	struct Scsi_Host *shost = dev_to_shost(dev);
- 	struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -258,7 +258,7 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
- }
- 
- static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
--			     struct device *cdev)
-+			     struct class_device *cdev)
- {
- 	struct Scsi_Host *shost = dev_to_shost(dev);
- 	struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -1308,6 +1308,8 @@ static int
- iscsi_if_transport_ep(struct iscsi_transport *transport,
- 		      struct iscsi_uevent *ev, int msg_type)
- {
-+	return -ENOSYS;
-+#if 0
- 	struct iscsi_endpoint *ep;
- 	struct sockaddr *dst_addr;
- 	int rc = 0;
-@@ -1348,6 +1350,8 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
- 		break;
- 	}
- 	return rc;
-+
-+#endif
- }
- 
- static int
-@@ -1429,6 +1433,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- 					      ev->u.c_session.queue_depth);
- 		break;
- 	case ISCSI_UEVENT_CREATE_BOUND_SESSION:
-+		err = -ENOSYS;
-+		break;
-+#if 0
- 		ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
- 		if (!ep) {
- 			err = -EINVAL;
-@@ -1440,6 +1447,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- 					ev->u.c_bound_session.cmds_max,
- 					ev->u.c_bound_session.queue_depth);
- 		break;
-+#endif
- 	case ISCSI_UEVENT_DESTROY_SESSION:
- 		session = iscsi_session_lookup(ev->u.d_session.sid);
- 		if (session)
-@@ -1569,8 +1577,11 @@ iscsi_if_rx(struct sk_buff *skb)
- 	mutex_unlock(&rx_queue_mutex);
- }
- 
-+#define iscsi_cdev_to_conn(_cdev) \
-+	iscsi_dev_to_conn(_cdev->dev)
-+
- #define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store)		\
--struct device_attribute dev_attr_##_prefix##_##_name =	\
-+struct class_device_attribute class_device_attr_##_prefix##_##_name =	\
- 	__ATTR(_name,_mode,_show,_store)
- 
- /*
-@@ -1578,10 +1589,9 @@ struct device_attribute dev_attr_##_prefix##_##_name =	\
-  */
- #define iscsi_conn_attr_show(param)					\
- static ssize_t								\
--show_conn_param_##param(struct device *dev, 				\
--			struct device_attribute *attr, char *buf)	\
-+show_conn_param_##param(struct class_device *cdev, char *buf)		\
- {									\
--	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent);	\
-+	struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev);		\
- 	struct iscsi_transport *t = conn->transport;			\
- 	return t->get_conn_param(conn, param, buf);			\
- }
-@@ -1605,16 +1615,17 @@ iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
- iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
- iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
- 
-+#define iscsi_cdev_to_session(_cdev) \
-+	iscsi_dev_to_session(_cdev->dev)
-+
- /*
-  * iSCSI session attrs
-  */
- #define iscsi_session_attr_show(param, perm)				\
- static ssize_t								\
--show_session_param_##param(struct device *dev,				\
--			   struct device_attribute *attr, char *buf)	\
-+show_session_param_##param(struct class_device *cdev, char *buf)	\
- {									\
--	struct iscsi_cls_session *session = 				\
--		iscsi_dev_to_session(dev->parent);			\
-+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
- 	struct iscsi_transport *t = session->transport;			\
- 									\
- 	if (perm && !capable(CAP_SYS_ADMIN))				\
-@@ -1648,10 +1659,9 @@ iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
- iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
- 
- static ssize_t
--show_priv_session_state(struct device *dev, struct device_attribute *attr,
--			char *buf)
-+show_priv_session_state(struct class_device *cdev, char *buf)
- {
--	struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
-+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);
- 	return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
- }
- static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-@@ -1659,11 +1669,9 @@ static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
- 
- #define iscsi_priv_session_attr_show(field, format)			\
- static ssize_t								\
--show_priv_session_##field(struct device *dev, 				\
--			  struct device_attribute *attr, char *buf)	\
-+show_priv_session_##field(struct class_device *cdev, char *buf)		\
- {									\
--	struct iscsi_cls_session *session = 				\
--			iscsi_dev_to_session(dev->parent);		\
-+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\
- 	return sprintf(buf, format"\n", session->field);		\
- }
- 
-@@ -1678,10 +1686,9 @@ iscsi_priv_session_attr(recovery_tmo, "%d");
-  */
- #define iscsi_host_attr_show(param)					\
- static ssize_t								\
--show_host_param_##param(struct device *dev, 				\
--			struct device_attribute *attr, char *buf)	\
-+show_host_param_##param(struct class_device *cdev, char *buf)		\
- {									\
--	struct Scsi_Host *shost = transport_class_to_shost(dev);	\
-+	struct Scsi_Host *shost = transport_class_to_shost(cdev);	\
- 	struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
- 	return priv->iscsi_transport->get_host_param(shost, param, buf); \
- }
-@@ -1698,7 +1705,7 @@ iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
- 
- #define SETUP_PRIV_SESSION_RD_ATTR(field)				\
- do {									\
--	priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
-+	priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
- 	count++;							\
- } while (0)
- 
-@@ -1706,7 +1713,7 @@ do {									\
- #define SETUP_SESSION_RD_ATTR(field, param_flag)			\
- do {									\
- 	if (tt->param_mask & param_flag) {				\
--		priv->session_attrs[count] = &dev_attr_sess_##field; \
-+		priv->session_attrs[count] = &class_device_attr_sess_##field; \
- 		count++;						\
- 	}								\
- } while (0)
-@@ -1714,7 +1721,7 @@ do {									\
- #define SETUP_CONN_RD_ATTR(field, param_flag)				\
- do {									\
- 	if (tt->param_mask & param_flag) {				\
--		priv->conn_attrs[count] = &dev_attr_conn_##field; \
-+		priv->conn_attrs[count] = &class_device_attr_conn_##field; \
- 		count++;						\
- 	}								\
- } while (0)
-@@ -1722,7 +1729,7 @@ do {									\
- #define SETUP_HOST_RD_ATTR(field, param_flag)				\
- do {									\
- 	if (tt->host_param_mask & param_flag) {				\
--		priv->host_attrs[count] = &dev_attr_host_##field; \
-+		priv->host_attrs[count] = &class_device_attr_host_##field; \
- 		count++;						\
- 	}								\
- } while (0)
-@@ -1815,15 +1822,15 @@ iscsi_register_transport(struct iscsi_transport *tt)
- 	if (!(tt->caps & CAP_DATA_PATH_OFFLOAD))
- 		priv->t.create_work_queue = 1;
- 
--	priv->dev.class = &iscsi_transport_class;
--	snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name);
--	err = device_register(&priv->dev);
-+	priv->cdev.class = &iscsi_transport_class;
-+	snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
-+	err = class_device_register(&priv->cdev);
- 	if (err)
- 		goto free_priv;
- 
--	err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
-+	err = sysfs_create_group(&priv->cdev.kobj, &iscsi_transport_group);
- 	if (err)
--		goto unregister_dev;
-+		goto unregister_cdev;
- 
- 	/* host parameters */
- 	priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
-@@ -1902,9 +1909,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
- 	printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
- 	return &priv->t;
- 
--unregister_dev:
--	device_unregister(&priv->dev);
--	return NULL;
-+unregister_cdev:
-+	class_device_unregister(&priv->cdev);
- free_priv:
- 	kfree(priv);
- 	return NULL;
-@@ -1931,8 +1937,8 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
- 	transport_container_unregister(&priv->session_cont);
- 	transport_container_unregister(&priv->t.host_attrs);
- 
--	sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
--	device_unregister(&priv->dev);
-+	sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
-+	class_device_unregister(&priv->cdev);
- 	mutex_unlock(&rx_queue_mutex);
- 
+@@ -1738,7 +1738,7 @@ static __init int iscsi_transport_init(void)
  	return 0;
-@@ -1952,13 +1958,14 @@ static __init int iscsi_transport_init(void)
- 	if (err)
- 		return err;
- 
-+#if 0
- 	err = class_register(&iscsi_endpoint_class);
- 	if (err)
- 		goto unregister_transport_class;
--
-+#endif
- 	err = transport_class_register(&iscsi_host_class);
- 	if (err)
--		goto unregister_endpoint_class;
-+		goto unregister_transport_class;
  
- 	err = transport_class_register(&iscsi_connection_class);
- 	if (err)
-@@ -1989,8 +1996,10 @@ unregister_conn_class:
- 	transport_class_unregister(&iscsi_connection_class);
- unregister_host_class:
- 	transport_class_unregister(&iscsi_host_class);
-+#if 0
- unregister_endpoint_class:
- 	class_unregister(&iscsi_endpoint_class);
-+#endif
- unregister_transport_class:
- 	class_unregister(&iscsi_transport_class);
- 	return err;
-@@ -2003,7 +2012,9 @@ static void __exit iscsi_transport_exit(void)
+ release_nls:
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ unregister_session_class:
+ 	transport_class_unregister(&iscsi_session_class);
+ unregister_conn_class:
+@@ -1753,7 +1753,7 @@ unregister_transport_class:
+ static void __exit iscsi_transport_exit(void)
+ {
+ 	destroy_workqueue(iscsi_eh_timer_workq);
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
  	transport_class_unregister(&iscsi_connection_class);
  	transport_class_unregister(&iscsi_session_class);
  	transport_class_unregister(&iscsi_host_class);
-+#if 0
- 	class_unregister(&iscsi_endpoint_class);
-+#endif
- 	class_unregister(&iscsi_transport_class);
- }
- 
-diff --git a/scsi_transport_iscsi.h b/scsi_transport_iscsi.h
-index b65c96a..9919c0d 100644
---- a/scsi_transport_iscsi.h
-+++ b/scsi_transport_iscsi.h
-@@ -28,6 +28,8 @@
- #include <linux/mutex.h>
- #include "iscsi_if.h"
- 
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct iscsi_transport;
- struct iscsi_endpoint;
--- 
-1.5.4.1
-
--- open-iscsi-2.0.870~rc3.orig/kernel/Makefile
+++ open-iscsi-2.0.870~rc3/kernel/Makefile
@@ -51,8 +51,7 @@
 14to19_patch=2.6.14-19_compat.patch
 20to21_patch=2.6.20-21_compat.patch
 24_patch=2.6.24_compat.patch
-26_patch=2.6.26_compat.patch
-all_patches=14to21_patch 20to21_patch 24_patch 26_patch
+all_patches=14to21_patch 20to21_patch 24_patch
 cur_patched=cur_patched
 
 ## fun stuff for maintaining multiple versions
@@ -63,7 +62,6 @@
 KSUBLEVEL = $(shell cat $(KSRC)/Makefile | awk -F= '/^SUBLEVEL =/ {print $$2}' | \
 		sed 's/^[ \t]*//;s/[ \t]*$$//')
 
-
 KERNEL_TARGET=linux_2_6_$(KSUBLEVEL)
 kernel_check: $(KERNEL_TARGET)
 
@@ -89,11 +87,7 @@
 
 linux_2_6_24: has_24_patch
 
-linux_2_6_25: has_24_patch
-
-linux_2_6_26: has_26_patch
-
-linux_2_6_27: $(unpatch_code)
+linux_2_6_25: $(unpatch_code)
 
 do_unpatch_code:
 	echo "Un-patching source code for use with linux-2.6.14 and up ..."
@@ -122,7 +116,7 @@
 	ln -s $@ $(cur_patched)
 
 has_24_patch: $(24_patch)
-	echo "Patching source code for linux-2.6.24-25 ..."
+	echo "Patching source code for linux-2.6.24 ..."
 	if [ -e $(cur_patched) ]; then \
 		make -C . clean; \
 	fi
@@ -130,16 +124,6 @@
 	cp $(24_patch) $@
 	ln -s $@ $(cur_patched)
 
-has_26_patch: $(26_patch)
-	echo "Patching source code for linux-2.6.26 ..."
-	if [ -e $(cur_patched) ]; then \
-		make -C . clean; \
-	fi
-	patch -p1 < $(26_patch)
-	cp $(26_patch) $@
-	ln -s $@ $(cur_patched)
-
-
 # ============ END code for kernel_check and source patching =================
 
 clean: $(unpatch_code)
--- open-iscsi-2.0.870~rc3.orig/kernel/iscsi_tcp.c
+++ open-iscsi-2.0.870~rc3/kernel/iscsi_tcp.c
@@ -64,10 +64,6 @@
 #define BUG_ON(expr)
 #endif
 
-static struct scsi_transport_template *iscsi_tcp_scsi_transport;
-static struct scsi_host_template iscsi_sht;
-static struct iscsi_transport iscsi_tcp_transport;
-
 static unsigned int iscsi_max_lun = 512;
 module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
 
@@ -498,64 +494,78 @@
  * must be called with session lock
  */
 static void
-iscsi_tcp_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task)
+iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
-	struct iscsi_tcp_task *tcp_task = task->dd_data;
+	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 	struct iscsi_r2t_info *r2t;
 
-	/* nothing to do for mgmt tasks */
-	if (!task->sc)
-		return;
-
-	/* flush task's r2t queues */
-	while (__kfifo_get(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
-		__kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
+	/* flush ctask's r2t queues */
+	while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) {
+		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
 			    sizeof(void*));
-		debug_scsi("iscsi_tcp_cleanup_task pending r2t dropped\n");
+		debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n");
 	}
 
-	r2t = tcp_task->r2t;
+	r2t = tcp_ctask->r2t;
 	if (r2t != NULL) {
-		__kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
+		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
 			    sizeof(void*));
-		tcp_task->r2t = NULL;
+		tcp_ctask->r2t = NULL;
 	}
 }
 
 /**
- * iscsi_data_in - SCSI Data-In Response processing
+ * iscsi_data_rsp - SCSI Data-In Response processing
  * @conn: iscsi connection
- * @task: scsi command task
+ * @ctask: scsi command task
  **/
 static int
-iscsi_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
+iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-	struct iscsi_tcp_task *tcp_task = task->dd_data;
+	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 	struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
+	struct iscsi_session *session = conn->session;
+	struct scsi_cmnd *sc = ctask->sc;
 	int datasn = be32_to_cpu(rhdr->datasn);
-	unsigned total_in_length = scsi_in(task->sc)->length;
 
-	iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
+	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
 	if (tcp_conn->in.datalen == 0)
 		return 0;
 
-	if (tcp_task->exp_datasn != datasn) {
-		debug_tcp("%s: task->exp_datasn(%d) != rhdr->datasn(%d)\n",
-		          __func__, tcp_task->exp_datasn, datasn);
+	if (tcp_ctask->exp_datasn != datasn) {
+		debug_tcp("%s: ctask->exp_datasn(%d) != rhdr->datasn(%d)\n",
+		          __FUNCTION__, tcp_ctask->exp_datasn, datasn);
 		return ISCSI_ERR_DATASN;
 	}
 
-	tcp_task->exp_datasn++;
+	tcp_ctask->exp_datasn++;
 
-	tcp_task->data_offset = be32_to_cpu(rhdr->offset);
-	if (tcp_task->data_offset + tcp_conn->in.datalen > total_in_length) {
+	tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
+	if (tcp_ctask->data_offset + tcp_conn->in.datalen > scsi_bufflen(sc)) {
 		debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n",
-		          __func__, tcp_task->data_offset,
-		          tcp_conn->in.datalen, total_in_length);
+		          __FUNCTION__, tcp_ctask->data_offset,
+		          tcp_conn->in.datalen, scsi_bufflen(sc));
 		return ISCSI_ERR_DATA_OFFSET;
 	}
 
+	if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
+		sc->result = (DID_OK << 16) | rhdr->cmd_status;
+		conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
+		if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
+		                   ISCSI_FLAG_DATA_OVERFLOW)) {
+			int res_count = be32_to_cpu(rhdr->residual_count);
+
+			if (res_count > 0 &&
+			    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+			     res_count <= scsi_bufflen(sc)))
+				scsi_set_resid(sc, res_count);
+			else
+				sc->result = (DID_BAD_TARGET << 16) |
+					rhdr->cmd_status;
+		}
+	}
+
 	conn->datain_pdus_cnt++;
 	return 0;
 }
@@ -563,7 +573,7 @@
 /**
  * iscsi_solicit_data_init - initialize first Data-Out
  * @conn: iscsi connection
- * @task: scsi command task
+ * @ctask: scsi command task
  * @r2t: R2T info
  *
  * Notes:
@@ -573,7 +583,7 @@
  *	This function is called with connection lock taken.
  **/
 static void
-iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_task *task,
+iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
 			struct iscsi_r2t_info *r2t)
 {
 	struct iscsi_data *hdr;
@@ -584,8 +594,8 @@
 	hdr->datasn = cpu_to_be32(r2t->solicit_datasn);
 	r2t->solicit_datasn++;
 	hdr->opcode = ISCSI_OP_SCSI_DATA_OUT;
-	memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun));
-	hdr->itt = task->hdr->itt;
+	memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
+	hdr->itt = ctask->hdr->itt;
 	hdr->exp_statsn = r2t->exp_statsn;
 	hdr->offset = cpu_to_be32(r2t->data_offset);
 	if (r2t->data_length > conn->max_xmit_dlength) {
@@ -605,14 +615,14 @@
 /**
  * iscsi_r2t_rsp - iSCSI R2T Response processing
  * @conn: iscsi connection
- * @task: scsi command task
+ * @ctask: scsi command task
  **/
 static int
-iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
+iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
 	struct iscsi_r2t_info *r2t;
 	struct iscsi_session *session = conn->session;
-	struct iscsi_tcp_task *tcp_task = task->dd_data;
+	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 	struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr;
 	int r2tsn = be32_to_cpu(rhdr->r2tsn);
@@ -625,23 +635,23 @@
 		return ISCSI_ERR_DATALEN;
 	}
 
-	if (tcp_task->exp_datasn != r2tsn){
-		debug_tcp("%s: task->exp_datasn(%d) != rhdr->r2tsn(%d)\n",
-		          __func__, tcp_task->exp_datasn, r2tsn);
+	if (tcp_ctask->exp_datasn != r2tsn){
+		debug_tcp("%s: ctask->exp_datasn(%d) != rhdr->r2tsn(%d)\n",
+		          __FUNCTION__, tcp_ctask->exp_datasn, r2tsn);
 		return ISCSI_ERR_R2TSN;
 	}
 
 	/* fill-in new R2T associated with the task */
 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
 
-	if (!task->sc || session->state != ISCSI_STATE_LOGGED_IN) {
+	if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) {
 		iscsi_conn_printk(KERN_INFO, conn,
 				  "dropping R2T itt %d in recovery.\n",
-				  task->itt);
+				  ctask->itt);
 		return 0;
 	}
 
-	rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
+	rc = __kfifo_get(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*));
 	BUG_ON(!rc);
 
 	r2t->exp_statsn = rhdr->statsn;
@@ -649,7 +659,7 @@
 	if (r2t->data_length == 0) {
 		iscsi_conn_printk(KERN_ERR, conn,
 				  "invalid R2T with zero data len\n");
-		__kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
+		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
 			    sizeof(void*));
 		return ISCSI_ERR_DATALEN;
 	}
@@ -660,12 +670,12 @@
 			    r2t->data_length, session->max_burst);
 
 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
-	if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
+	if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
 		iscsi_conn_printk(KERN_ERR, conn,
 				  "invalid R2T with data len %u at offset %u "
 				  "and total length %d\n", r2t->data_length,
-				  r2t->data_offset, scsi_out(task->sc)->length);
-		__kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
+				  r2t->data_offset, scsi_bufflen(ctask->sc));
+		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
 			    sizeof(void*));
 		return ISCSI_ERR_DATALEN;
 	}
@@ -673,13 +683,13 @@
 	r2t->ttt = rhdr->ttt; /* no flip */
 	r2t->solicit_datasn = 0;
 
-	iscsi_solicit_data_init(conn, task, r2t);
+	iscsi_solicit_data_init(conn, ctask, r2t);
 
-	tcp_task->exp_datasn = r2tsn + 1;
-	__kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
+	tcp_ctask->exp_datasn = r2tsn + 1;
+	__kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
 	conn->r2t_pdus_cnt++;
 
-	iscsi_requeue_task(task);
+	iscsi_requeue_ctask(ctask);
 	return 0;
 }
 
@@ -722,8 +732,10 @@
 iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 {
 	int rc = 0, opcode, ahslen;
+	struct iscsi_session *session = conn->session;
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-	struct iscsi_task *task;
+	struct iscsi_cmd_task *ctask;
+	uint32_t itt;
 
 	/* verify PDU length */
 	tcp_conn->in.datalen = ntoh24(hdr->dlength);
@@ -741,7 +753,7 @@
 
 	opcode = hdr->opcode & ISCSI_OPCODE_MASK;
 	/* verify itt (itt encoding: age+cid+itt) */
-	rc = iscsi_verify_itt(conn, hdr->itt);
+	rc = iscsi_verify_itt(conn, hdr, &itt);
 	if (rc)
 		return rc;
 
@@ -750,21 +762,15 @@
 
 	switch(opcode) {
 	case ISCSI_OP_SCSI_DATA_IN:
+		ctask = session->cmds[itt];
 		spin_lock(&conn->session->lock);
-		task = iscsi_itt_to_ctask(conn, hdr->itt);
-		if (!task)
-			rc = ISCSI_ERR_BAD_ITT;
-		else
-			rc = iscsi_data_in(conn, task);
-		if (rc) {
-			spin_unlock(&conn->session->lock);
-			break;
-		}
-
+		rc = iscsi_data_rsp(conn, ctask);
+		spin_unlock(&conn->session->lock);
+		if (rc)
+			return rc;
 		if (tcp_conn->in.datalen) {
-			struct iscsi_tcp_task *tcp_task = task->dd_data;
+			struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 			struct hash_desc *rx_hash = NULL;
-			struct scsi_data_buffer *sdb = scsi_in(task->sc);
 
 			/*
 			 * Setup copy of Data-In into the Scsi_Cmnd
@@ -779,21 +785,17 @@
 
 			debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, "
 				  "datalen=%d)\n", tcp_conn,
-				  tcp_task->data_offset,
+				  tcp_ctask->data_offset,
 				  tcp_conn->in.datalen);
-			rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
-						   sdb->table.sgl,
-						   sdb->table.nents,
-						   tcp_task->data_offset,
-						   tcp_conn->in.datalen,
-						   iscsi_tcp_process_data_in,
-						   rx_hash);
-			spin_unlock(&conn->session->lock);
-			return rc;
+			return iscsi_segment_seek_sg(&tcp_conn->in.segment,
+						     scsi_sglist(ctask->sc),
+						     scsi_sg_count(ctask->sc),
+						     tcp_ctask->data_offset,
+						     tcp_conn->in.datalen,
+						     iscsi_tcp_process_data_in,
+						     rx_hash);
 		}
-		rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
-		spin_unlock(&conn->session->lock);
-		break;
+		/* fall through */
 	case ISCSI_OP_SCSI_CMD_RSP:
 		if (tcp_conn->in.datalen) {
 			iscsi_tcp_data_recv_prep(tcp_conn);
@@ -802,17 +804,15 @@
 		rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
 		break;
 	case ISCSI_OP_R2T:
-		spin_lock(&conn->session->lock);
-		task = iscsi_itt_to_ctask(conn, hdr->itt);
-		if (!task)
-			rc = ISCSI_ERR_BAD_ITT;
-		else if (ahslen)
+		ctask = session->cmds[itt];
+		if (ahslen)
 			rc = ISCSI_ERR_AHSLEN;
-		else if (task->sc->sc_data_direction == DMA_TO_DEVICE)
-			rc = iscsi_r2t_rsp(conn, task);
-		else
+		else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) {
+			spin_lock(&session->lock);
+			rc = iscsi_r2t_rsp(conn, ctask);
+			spin_unlock(&session->lock);
+		} else
 			rc = ISCSI_ERR_PROTO;
-		spin_unlock(&conn->session->lock);
 		break;
 	case ISCSI_OP_LOGIN_RSP:
 	case ISCSI_OP_TEXT_RSP:
@@ -979,7 +979,7 @@
 
 error:
 	debug_tcp("Error receiving PDU, errno=%d\n", rc);
-	iscsi_conn_failure(conn, rc);
+	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
 	return 0;
 }
 
@@ -1098,10 +1098,8 @@
 
 	while (1) {
 		rc = iscsi_tcp_xmit_segment(tcp_conn, segment);
-		if (rc < 0) {
-			rc = ISCSI_ERR_XMIT_FAILED;
+		if (rc < 0)
 			goto error;
-		}
 		if (rc == 0)
 			break;
 
@@ -1110,7 +1108,7 @@
 		if (segment->total_copied >= segment->total_size) {
 			if (segment->done != NULL) {
 				rc = segment->done(tcp_conn, segment);
-				if (rc != 0)
+				if (rc < 0)
 					goto error;
 			}
 		}
@@ -1125,8 +1123,8 @@
 	/* Transmit error. We could initiate error recovery
 	 * here. */
 	debug_tcp("Error sending PDU, errno=%d\n", rc);
-	iscsi_conn_failure(conn, rc);
-	return -EIO;
+	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+	return rc;
 }
 
 /**
@@ -1176,7 +1174,7 @@
 {
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 
-	debug_tcp("%s(%p%s)\n", __func__, tcp_conn,
+	debug_tcp("%s(%p%s)\n", __FUNCTION__, tcp_conn,
 			conn->hdrdgst_en? ", digest enabled" : "");
 
 	/* Clear the data segment - needs to be filled in by the
@@ -1185,7 +1183,7 @@
 
 	/* If header digest is enabled, compute the CRC and
 	 * place the digest into the same buffer. We make
-	 * sure that both iscsi_tcp_task and mtask have
+	 * sure that both iscsi_tcp_ctask and mtask have
 	 * sufficient room.
 	 */
 	if (conn->hdrdgst_en) {
@@ -1217,7 +1215,7 @@
 	struct hash_desc *tx_hash = NULL;
 	unsigned int hdr_spec_len;
 
-	debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __func__,
+	debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __FUNCTION__,
 			tcp_conn, offset, len,
 			conn->datadgst_en? ", digest enabled" : "");
 
@@ -1242,7 +1240,7 @@
 	struct hash_desc *tx_hash = NULL;
 	unsigned int hdr_spec_len;
 
-	debug_tcp("%s(%p, datalen=%d%s)\n", __func__, tcp_conn, len,
+	debug_tcp("%s(%p, datalen=%d%s)\n", __FUNCTION__, tcp_conn, len,
 		  conn->datadgst_en? ", digest enabled" : "");
 
 	/* Make sure the datalen matches what the caller
@@ -1260,7 +1258,7 @@
 /**
  * iscsi_solicit_data_cont - initialize next Data-Out
  * @conn: iscsi connection
- * @task: scsi command task
+ * @ctask: scsi command task
  * @r2t: R2T info
  * @left: bytes left to transfer
  *
@@ -1271,7 +1269,7 @@
  *	Called under connection lock.
  **/
 static int
-iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_task *task,
+iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
 			struct iscsi_r2t_info *r2t)
 {
 	struct iscsi_data *hdr;
@@ -1288,8 +1286,8 @@
 	hdr->datasn = cpu_to_be32(r2t->solicit_datasn);
 	r2t->solicit_datasn++;
 	hdr->opcode = ISCSI_OP_SCSI_DATA_OUT;
-	memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun));
-	hdr->itt = task->hdr->itt;
+	memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
+	hdr->itt = ctask->hdr->itt;
 	hdr->exp_statsn = r2t->exp_statsn;
 	new_offset = r2t->data_offset + r2t->sent;
 	hdr->offset = cpu_to_be32(new_offset);
@@ -1307,76 +1305,87 @@
 }
 
 /**
- * iscsi_tcp_task - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
+ * iscsi_tcp_ctask - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
  * @conn: iscsi connection
- * @task: scsi command task
+ * @ctask: scsi command task
  * @sc: scsi command
  **/
 static int
-iscsi_tcp_task_init(struct iscsi_task *task)
+iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask)
 {
-	struct iscsi_tcp_task *tcp_task = task->dd_data;
-	struct iscsi_conn *conn = task->conn;
-	struct scsi_cmnd *sc = task->sc;
+	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+	struct iscsi_conn *conn = ctask->conn;
+	struct scsi_cmnd *sc = ctask->sc;
 	int err;
 
-	if (!sc) {
-		/*
-		 * mgmt tasks do not have a scatterlist since they come
-		 * in from the iscsi interface.
-		 */
-		debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id,
-			   task->itt);
-
-		/* Prepare PDU, optionally w/ immediate data */
-		iscsi_tcp_send_hdr_prep(conn, task->hdr, sizeof(*task->hdr));
-
-		/* If we have immediate data, attach a payload */
-		if (task->data_count)
-			iscsi_tcp_send_linear_data_prepare(conn, task->data,
-							   task->data_count);
-		return 0;
-	}
-
-	BUG_ON(__kfifo_len(tcp_task->r2tqueue));
-	tcp_task->sent = 0;
-	tcp_task->exp_datasn = 0;
+	BUG_ON(__kfifo_len(tcp_ctask->r2tqueue));
+	tcp_ctask->sent = 0;
+	tcp_ctask->exp_datasn = 0;
 
 	/* Prepare PDU, optionally w/ immediate data */
-	debug_scsi("task deq [cid %d itt 0x%x imm %d unsol %d]\n",
-		    conn->id, task->itt, task->imm_count,
-		    task->unsol_count);
-	iscsi_tcp_send_hdr_prep(conn, task->hdr, task->hdr_len);
+	debug_scsi("ctask deq [cid %d itt 0x%x imm %d unsol %d]\n",
+		    conn->id, ctask->itt, ctask->imm_count,
+		    ctask->unsol_count);
+	iscsi_tcp_send_hdr_prep(conn, ctask->hdr, ctask->hdr_len);
 
-	if (!task->imm_count)
+	if (!ctask->imm_count)
 		return 0;
 
 	/* If we have immediate data, attach a payload */
-	err = iscsi_tcp_send_data_prep(conn, scsi_out(sc)->table.sgl,
-				       scsi_out(sc)->table.nents,
-				       0, task->imm_count);
+	err = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc), scsi_sg_count(sc),
+				       0, ctask->imm_count);
 	if (err)
 		return err;
-	tcp_task->sent += task->imm_count;
-	task->imm_count = 0;
+	tcp_ctask->sent += ctask->imm_count;
+	ctask->imm_count = 0;
+	return 0;
+}
+
+/**
+ * iscsi_tcp_mtask_xmit - xmit management(immediate) task
+ * @conn: iscsi connection
+ * @mtask: task management task
+ *
+ * Notes:
+ *	The function can return -EAGAIN in which case caller must
+ *	call it again later, or recover. '0' return code means successful
+ *	xmit.
+ **/
+static int
+iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
+{
+	int rc;
+
+	/* Flush any pending data first. */
+	rc = iscsi_tcp_flush(conn);
+	if (rc < 0)
+		return rc;
+
+	if (mtask->hdr->itt == RESERVED_ITT) {
+		struct iscsi_session *session = conn->session;
+
+		spin_lock_bh(&session->lock);
+		iscsi_free_mgmt_task(conn, mtask);
+		spin_unlock_bh(&session->lock);
+	}
+
 	return 0;
 }
 
 /*
- * iscsi_tcp_task_xmit - xmit normal PDU task
- * @task: iscsi command task
+ * iscsi_tcp_ctask_xmit - xmit normal PDU task
+ * @conn: iscsi connection
+ * @ctask: iscsi command task
  *
  * We're expected to return 0 when everything was transmitted succesfully,
  * -EAGAIN if there's still data in the queue, or != 0 for any other kind
  * of error.
  */
 static int
-iscsi_tcp_task_xmit(struct iscsi_task *task)
+iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
-	struct iscsi_conn *conn = task->conn;
-	struct iscsi_tcp_task *tcp_task = task->dd_data;
-	struct scsi_cmnd *sc = task->sc;
-	struct scsi_data_buffer *sdb;
+	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+	struct scsi_cmnd *sc = ctask->sc;
 	int rc = 0;
 
 flush:
@@ -1385,39 +1394,32 @@
 	if (rc < 0)
 		return rc;
 
-	/* mgmt command */
-	if (!sc) {
-		if (task->hdr->itt == RESERVED_ITT)
-			iscsi_put_task(task);
-		return 0;
-	}
-
 	/* Are we done already? */
 	if (sc->sc_data_direction != DMA_TO_DEVICE)
 		return 0;
 
-	sdb = scsi_out(sc);
-	if (task->unsol_count != 0) {
-		struct iscsi_data *hdr = &tcp_task->unsol_dtask.hdr;
+	if (ctask->unsol_count != 0) {
+		struct iscsi_data *hdr = &tcp_ctask->unsol_dtask.hdr;
 
 		/* Prepare a header for the unsolicited PDU.
 		 * The amount of data we want to send will be
-		 * in task->data_count.
+		 * in ctask->data_count.
 		 * FIXME: return the data count instead.
 		 */
-		iscsi_prep_unsolicit_data_pdu(task, hdr);
+		iscsi_prep_unsolicit_data_pdu(ctask, hdr);
 
 		debug_tcp("unsol dout [itt 0x%x doff %d dlen %d]\n",
-				task->itt, tcp_task->sent, task->data_count);
+				ctask->itt, tcp_ctask->sent, ctask->data_count);
 
 		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
-		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
-					      sdb->table.nents, tcp_task->sent,
-					      task->data_count);
+		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
+					      scsi_sg_count(sc),
+					      tcp_ctask->sent,
+					      ctask->data_count);
 		if (rc)
 			goto fail;
-		tcp_task->sent += task->data_count;
-		task->unsol_count -= task->data_count;
+		tcp_ctask->sent += ctask->data_count;
+		ctask->unsol_count -= ctask->data_count;
 		goto flush;
 	} else {
 		struct iscsi_session *session = conn->session;
@@ -1426,22 +1428,22 @@
 		/* All unsolicited PDUs sent. Check for solicited PDUs.
 		 */
 		spin_lock_bh(&session->lock);
-		r2t = tcp_task->r2t;
+		r2t = tcp_ctask->r2t;
 		if (r2t != NULL) {
 			/* Continue with this R2T? */
-			if (!iscsi_solicit_data_cont(conn, task, r2t)) {
+			if (!iscsi_solicit_data_cont(conn, ctask, r2t)) {
 				debug_scsi("  done with r2t %p\n", r2t);
 
-				__kfifo_put(tcp_task->r2tpool.queue,
+				__kfifo_put(tcp_ctask->r2tpool.queue,
 					    (void*)&r2t, sizeof(void*));
-				tcp_task->r2t = r2t = NULL;
+				tcp_ctask->r2t = r2t = NULL;
 			}
 		}
 
 		if (r2t == NULL) {
-			__kfifo_get(tcp_task->r2tqueue, (void*)&tcp_task->r2t,
+			__kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
 				    sizeof(void*));
-			r2t = tcp_task->r2t;
+			r2t = tcp_ctask->r2t;
 		}
 		spin_unlock_bh(&session->lock);
 
@@ -1452,19 +1454,19 @@
 		}
 
 		debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n",
-			r2t, r2t->solicit_datasn - 1, task->itt,
+			r2t, r2t->solicit_datasn - 1, ctask->itt,
 			r2t->data_offset + r2t->sent, r2t->data_count);
 
 		iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr,
 					sizeof(struct iscsi_hdr));
 
-		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
-					      sdb->table.nents,
+		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
+					      scsi_sg_count(sc),
 					      r2t->data_offset + r2t->sent,
 					      r2t->data_count);
 		if (rc)
 			goto fail;
-		tcp_task->sent += r2t->data_count;
+		tcp_ctask->sent += r2t->data_count;
 		r2t->sent += r2t->data_count;
 		goto flush;
 	}
@@ -1481,7 +1483,7 @@
 	struct iscsi_cls_conn *cls_conn;
 	struct iscsi_tcp_conn *tcp_conn;
 
-	cls_conn = iscsi_conn_setup(cls_session, sizeof(*tcp_conn), conn_idx);
+	cls_conn = iscsi_conn_setup(cls_session, conn_idx);
 	if (!cls_conn)
 		return NULL;
 	conn = cls_conn->dd_data;
@@ -1491,14 +1493,18 @@
 	 */
 	conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
 
-	tcp_conn = conn->dd_data;
+	tcp_conn = kzalloc(sizeof(*tcp_conn), GFP_KERNEL);
+	if (!tcp_conn)
+		goto tcp_conn_alloc_fail;
+
+	conn->dd_data = tcp_conn;
 	tcp_conn->iscsi_conn = conn;
 
 	tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
 						  CRYPTO_ALG_ASYNC);
 	tcp_conn->tx_hash.flags = 0;
 	if (IS_ERR(tcp_conn->tx_hash.tfm))
-		goto free_conn;
+		goto free_tcp_conn;
 
 	tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
 						  CRYPTO_ALG_ASYNC);
@@ -1510,12 +1516,14 @@
 
 free_tx_tfm:
 	crypto_free_hash(tcp_conn->tx_hash.tfm);
-free_conn:
+free_tcp_conn:
 	iscsi_conn_printk(KERN_ERR, conn,
 			  "Could not create connection due to crc32c "
 			  "loading error. Make sure the crc32c "
 			  "module is built as a module or into the "
 			  "kernel\n");
+	kfree(tcp_conn);
+tcp_conn_alloc_fail:
 	iscsi_conn_teardown(cls_conn);
 	return NULL;
 }
@@ -1536,6 +1544,7 @@
 
 	spin_lock_bh(&session->lock);
 	tcp_conn->sock = NULL;
+	conn->recv_lock = NULL;
 	spin_unlock_bh(&session->lock);
 	sockfd_put(sock);
 }
@@ -1547,32 +1556,20 @@
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 
 	iscsi_tcp_release_conn(conn);
+	iscsi_conn_teardown(cls_conn);
 
 	if (tcp_conn->tx_hash.tfm)
 		crypto_free_hash(tcp_conn->tx_hash.tfm);
 	if (tcp_conn->rx_hash.tfm)
 		crypto_free_hash(tcp_conn->rx_hash.tfm);
 
-	iscsi_conn_teardown(cls_conn);
+	kfree(tcp_conn);
 }
 
 static void
 iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
 {
 	struct iscsi_conn *conn = cls_conn->dd_data;
-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-
-	/* userspace may have goofed up and not bound us */
-	if (!tcp_conn->sock)
-		return;
-	/*
-	 * Make sure our recv side is stopped.
-	 * Older tools called conn stop before ep_disconnect
-	 * so IO could still be coming in.
-	 */
-	write_lock_bh(&tcp_conn->sock->sk->sk_callback_lock);
-	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
-	write_unlock_bh(&tcp_conn->sock->sk->sk_callback_lock);
 
 	iscsi_conn_stop(cls_conn, flag);
 	iscsi_tcp_release_conn(conn);
@@ -1623,8 +1620,6 @@
 		    struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
 		    int is_leading)
 {
-	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
-	struct iscsi_host *ihost = shost_priv(shost);
 	struct iscsi_conn *conn = cls_conn->dd_data;
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 	struct sock *sk;
@@ -1648,8 +1643,8 @@
 	if (err)
 		goto free_socket;
 
-	err = iscsi_tcp_get_addr(conn, sock, ihost->local_address,
-				&ihost->local_port, kernel_getsockname);
+	err = iscsi_tcp_get_addr(conn, sock, conn->local_address,
+				&conn->local_port, kernel_getsockname);
 	if (err)
 		goto free_socket;
 
@@ -1666,6 +1661,13 @@
 	sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */
 	sk->sk_allocation = GFP_ATOMIC;
 
+	/* FIXME: disable Nagle's algorithm */
+
+	/*
+	 * Intercept TCP callbacks for sendfile like receive
+	 * processing.
+	 */
+	conn->recv_lock = &sk->sk_callback_lock;
 	iscsi_conn_set_callbacks(conn);
 	tcp_conn->sendpage = tcp_conn->sock->ops->sendpage;
 	/*
@@ -1679,6 +1681,21 @@
 	return err;
 }
 
+/* called with host lock */
+static void
+iscsi_tcp_mtask_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
+{
+	debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt);
+
+	/* Prepare PDU, optionally w/ immediate data */
+	iscsi_tcp_send_hdr_prep(conn, mtask->hdr, sizeof(*mtask->hdr));
+
+	/* If we have immediate data, attach a payload */
+	if (mtask->data_count)
+		iscsi_tcp_send_linear_data_prepare(conn, mtask->data,
+						   mtask->data_count);
+}
+
 static int
 iscsi_r2tpool_alloc(struct iscsi_session *session)
 {
@@ -1689,8 +1706,8 @@
 	 * initialize per-task: R2T pool and xmit queue
 	 */
 	for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
-	        struct iscsi_task *task = session->cmds[cmd_i];
-		struct iscsi_tcp_task *tcp_task = task->dd_data;
+	        struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
+		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 
 		/*
 		 * pre-allocated x4 as much r2ts to handle race when
@@ -1699,16 +1716,16 @@
 		 */
 
 		/* R2T pool */
-		if (iscsi_pool_init(&tcp_task->r2tpool, session->max_r2t * 4, NULL,
+		if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, NULL,
 				    sizeof(struct iscsi_r2t_info))) {
 			goto r2t_alloc_fail;
 		}
 
 		/* R2T xmit queue */
-		tcp_task->r2tqueue = kfifo_alloc(
+		tcp_ctask->r2tqueue = kfifo_alloc(
 		      session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
-		if (tcp_task->r2tqueue == ERR_PTR(-ENOMEM)) {
-			iscsi_pool_free(&tcp_task->r2tpool);
+		if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) {
+			iscsi_pool_free(&tcp_ctask->r2tpool);
 			goto r2t_alloc_fail;
 		}
 	}
@@ -1717,11 +1734,11 @@
 
 r2t_alloc_fail:
 	for (i = 0; i < cmd_i; i++) {
-		struct iscsi_task *task = session->cmds[i];
-		struct iscsi_tcp_task *tcp_task = task->dd_data;
+		struct iscsi_cmd_task *ctask = session->cmds[i];
+		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 
-		kfifo_free(tcp_task->r2tqueue);
-		iscsi_pool_free(&tcp_task->r2tpool);
+		kfifo_free(tcp_ctask->r2tqueue);
+		iscsi_pool_free(&tcp_ctask->r2tpool);
 	}
 	return -ENOMEM;
 }
@@ -1732,11 +1749,11 @@
 	int i;
 
 	for (i = 0; i < session->cmds_max; i++) {
-		struct iscsi_task *task = session->cmds[i];
-		struct iscsi_tcp_task *tcp_task = task->dd_data;
+		struct iscsi_cmd_task *ctask = session->cmds[i];
+		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 
-		kfifo_free(tcp_task->r2tqueue);
-		iscsi_pool_free(&tcp_task->r2tpool);
+		kfifo_free(tcp_ctask->r2tqueue);
+		iscsi_pool_free(&tcp_ctask->r2tpool);
 	}
 }
 
@@ -1801,6 +1818,29 @@
 	return len;
 }
 
+static int
+iscsi_tcp_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
+			 char *buf)
+{
+        struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+	int len;
+
+	switch (param) {
+	case ISCSI_HOST_PARAM_IPADDRESS:
+		spin_lock_bh(&session->lock);
+		if (!session->leadconn)
+			len = -ENODEV;
+		else
+			len = sprintf(buf, "%s\n",
+				     session->leadconn->local_address);
+		spin_unlock_bh(&session->lock);
+		break;
+	default:
+		return iscsi_host_get_param(shost, param, buf);
+	}
+	return len;
+}
+
 static void
 iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats)
 {
@@ -1826,70 +1866,54 @@
 }
 
 static struct iscsi_cls_session *
-iscsi_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
-			 uint16_t qdepth, uint32_t initial_cmdsn,
-			 uint32_t *hostno)
+iscsi_tcp_session_create(struct iscsi_transport *iscsit,
+			 struct scsi_transport_template *scsit,
+			 uint16_t cmds_max, uint16_t qdepth,
+			 uint32_t initial_cmdsn, uint32_t *hostno)
 {
 	struct iscsi_cls_session *cls_session;
 	struct iscsi_session *session;
-	struct Scsi_Host *shost;
+	uint32_t hn;
 	int cmd_i;
 
-	if (ep) {
-		printk(KERN_ERR "iscsi_tcp: invalid ep %p.\n", ep);
-		return NULL;
-	}
-
-	shost = iscsi_host_alloc(&iscsi_sht, 0, qdepth);
-	if (!shost)
-		return NULL;
-	shost->transportt = iscsi_tcp_scsi_transport;
-	shost->max_lun = iscsi_max_lun;
-	shost->max_id = 0;
-	shost->max_channel = 0;
-	shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE;
-
-	if (iscsi_host_add(shost, NULL))
-		goto free_host;
-	*hostno = shost->host_no;
-
-	cls_session = iscsi_session_setup(&iscsi_tcp_transport, shost, cmds_max,
-					  sizeof(struct iscsi_tcp_task),
-					  initial_cmdsn, 0);
+	cls_session = iscsi_session_setup(iscsit, scsit, cmds_max, qdepth,
+					 sizeof(struct iscsi_tcp_cmd_task),
+					 sizeof(struct iscsi_tcp_mgmt_task),
+					 initial_cmdsn, &hn);
 	if (!cls_session)
-		goto remove_host;
-	session = cls_session->dd_data;
+		return NULL;
+	*hostno = hn;
 
-	shost->can_queue = session->scsi_cmds_max;
+	session = class_to_transport_session(cls_session);
 	for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
-		struct iscsi_task *task = session->cmds[cmd_i];
-		struct iscsi_tcp_task *tcp_task = task->dd_data;
+		struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
+		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 
-		task->hdr = &tcp_task->hdr.cmd_hdr;
-		task->hdr_max = sizeof(tcp_task->hdr) - ISCSI_DIGEST_SIZE;
+		ctask->hdr = &tcp_ctask->hdr.cmd_hdr;
+		ctask->hdr_max = sizeof(tcp_ctask->hdr) - ISCSI_DIGEST_SIZE;
 	}
 
-	if (iscsi_r2tpool_alloc(session))
-		goto remove_session;
+	for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) {
+		struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i];
+		struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
+
+		mtask->hdr = (struct iscsi_hdr *) &tcp_mtask->hdr;
+	}
+
+	if (iscsi_r2tpool_alloc(class_to_transport_session(cls_session)))
+		goto r2tpool_alloc_fail;
+
 	return cls_session;
 
-remove_session:
+r2tpool_alloc_fail:
 	iscsi_session_teardown(cls_session);
-remove_host:
-	iscsi_host_remove(shost);
-free_host:
-	iscsi_host_free(shost);
 	return NULL;
 }
 
 static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session)
 {
-	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
-
-	iscsi_r2tpool_free(cls_session->dd_data);
-
-	iscsi_host_remove(shost);
-	iscsi_host_free(shost);
+	iscsi_r2tpool_free(class_to_transport_session(cls_session));
+	iscsi_session_teardown(cls_session);
 }
 
 static int iscsi_tcp_slave_configure(struct scsi_device *sdev)
@@ -1944,11 +1968,14 @@
 				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
 				  ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
 				  ISCSI_LU_RESET_TMO |
-				  ISCSI_PING_TMO | ISCSI_RECV_TMO |
-				  ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
+				  ISCSI_PING_TMO | ISCSI_RECV_TMO,
 	.host_param_mask	= ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
 				  ISCSI_HOST_INITIATOR_NAME |
 				  ISCSI_HOST_NETDEV_NAME,
+	.host_template		= &iscsi_sht,
+	.conndata_size		= sizeof(struct iscsi_conn),
+	.max_conn		= 1,
+	.max_cmd_len		= 16,
 	/* session management */
 	.create_session		= iscsi_tcp_session_create,
 	.destroy_session	= iscsi_tcp_session_destroy,
@@ -1962,14 +1989,16 @@
 	.start_conn		= iscsi_conn_start,
 	.stop_conn		= iscsi_tcp_conn_stop,
 	/* iscsi host params */
-	.get_host_param		= iscsi_host_get_param,
+	.get_host_param		= iscsi_tcp_host_get_param,
 	.set_host_param		= iscsi_host_set_param,
 	/* IO */
 	.send_pdu		= iscsi_conn_send_pdu,
 	.get_stats		= iscsi_conn_get_stats,
-	.init_task		= iscsi_tcp_task_init,
-	.xmit_task		= iscsi_tcp_task_xmit,
-	.cleanup_task		= iscsi_tcp_cleanup_task,
+	.init_cmd_task		= iscsi_tcp_ctask_init,
+	.init_mgmt_task		= iscsi_tcp_mtask_init,
+	.xmit_cmd_task		= iscsi_tcp_ctask_xmit,
+	.xmit_mgmt_task		= iscsi_tcp_mtask_xmit,
+	.cleanup_cmd_task	= iscsi_tcp_cleanup_ctask,
 	/* recovery */
 	.session_recovery_timedout = iscsi_session_recovery_timedout,
 };
@@ -1982,10 +2011,9 @@
 		       iscsi_max_lun);
 		return -EINVAL;
 	}
+	iscsi_tcp_transport.max_lun = iscsi_max_lun;
 
-	iscsi_tcp_scsi_transport = iscsi_register_transport(
-							&iscsi_tcp_transport);
-	if (!iscsi_tcp_scsi_transport)
+	if (!iscsi_register_transport(&iscsi_tcp_transport))
 		return -ENODEV;
 
 	return 0;
--- open-iscsi-2.0.870~rc3.orig/kernel/iscsi_tcp.h
+++ open-iscsi-2.0.870~rc3/kernel/iscsi_tcp.h
@@ -103,6 +103,11 @@
 	char			hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */
 };
 
+struct iscsi_tcp_mgmt_task {
+	struct iscsi_hdr	hdr;
+	char			hdrext[ISCSI_DIGEST_SIZE]; /* Header-Digest */
+};
+
 struct iscsi_r2t_info {
 	__be32			ttt;		/* copied from R2T */
 	__be32			exp_statsn;	/* copied from R2T */
@@ -114,7 +119,7 @@
 	struct iscsi_data_task	dtask;		/* Data-Out header buf */
 };
 
-struct iscsi_tcp_task {
+struct iscsi_tcp_cmd_task {
 	struct iscsi_hdr_buff {
 		struct iscsi_cmd	cmd_hdr;
 		char			hdrextbuf[ISCSI_MAX_AHS_SIZE +
--- open-iscsi-2.0.870~rc3.orig/kernel/libiscsi.c
+++ open-iscsi-2.0.870~rc3/kernel/libiscsi.c
@@ -38,6 +38,13 @@
 #include "scsi_transport_iscsi.h"
 #include "libiscsi.h"
 
+struct iscsi_session *
+class_to_transport_session(struct iscsi_cls_session *cls_session)
+{
+	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+	return iscsi_hostdata(shost->hostdata);
+}
+EXPORT_SYMBOL_GPL(class_to_transport_session);
 
 /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
 #define SNA32_CHECK 2147483648UL
@@ -80,170 +87,91 @@
 		 * xmit thread
 		 */
 		if (!list_empty(&session->leadconn->xmitqueue) ||
-		    !list_empty(&session->leadconn->mgmtqueue)) {
-			if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD))
-				scsi_queue_work(session->host,
-						&session->leadconn->xmitwork);
-		}
+		    !list_empty(&session->leadconn->mgmtqueue))
+			scsi_queue_work(session->host,
+					&session->leadconn->xmitwork);
 	}
 }
 EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
 
-void iscsi_prep_unsolicit_data_pdu(struct iscsi_task *task,
+void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
 				   struct iscsi_data *hdr)
 {
-	struct iscsi_conn *conn = task->conn;
+	struct iscsi_conn *conn = ctask->conn;
 
 	memset(hdr, 0, sizeof(struct iscsi_data));
 	hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
-	hdr->datasn = cpu_to_be32(task->unsol_datasn);
-	task->unsol_datasn++;
+	hdr->datasn = cpu_to_be32(ctask->unsol_datasn);
+	ctask->unsol_datasn++;
 	hdr->opcode = ISCSI_OP_SCSI_DATA_OUT;
-	memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun));
+	memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
 
-	hdr->itt = task->hdr->itt;
+	hdr->itt = ctask->hdr->itt;
 	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
-	hdr->offset = cpu_to_be32(task->unsol_offset);
+	hdr->offset = cpu_to_be32(ctask->unsol_offset);
 
-	if (task->unsol_count > conn->max_xmit_dlength) {
+	if (ctask->unsol_count > conn->max_xmit_dlength) {
 		hton24(hdr->dlength, conn->max_xmit_dlength);
-		task->data_count = conn->max_xmit_dlength;
-		task->unsol_offset += task->data_count;
+		ctask->data_count = conn->max_xmit_dlength;
+		ctask->unsol_offset += ctask->data_count;
 		hdr->flags = 0;
 	} else {
-		hton24(hdr->dlength, task->unsol_count);
-		task->data_count = task->unsol_count;
+		hton24(hdr->dlength, ctask->unsol_count);
+		ctask->data_count = ctask->unsol_count;
 		hdr->flags = ISCSI_FLAG_CMD_FINAL;
 	}
 }
 EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
 
-static int iscsi_add_hdr(struct iscsi_task *task, unsigned len)
+static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
 {
-	unsigned exp_len = task->hdr_len + len;
+	unsigned exp_len = ctask->hdr_len + len;
 
-	if (exp_len > task->hdr_max) {
+	if (exp_len > ctask->hdr_max) {
 		WARN_ON(1);
 		return -EINVAL;
 	}
 
 	WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */
-	task->hdr_len = exp_len;
-	return 0;
-}
-
-/*
- * make an extended cdb AHS
- */
-static int iscsi_prep_ecdb_ahs(struct iscsi_task *task)
-{
-	struct scsi_cmnd *cmd = task->sc;
-	unsigned rlen, pad_len;
-	unsigned short ahslength;
-	struct iscsi_ecdb_ahdr *ecdb_ahdr;
-	int rc;
-
-	ecdb_ahdr = iscsi_next_hdr(task);
-	rlen = cmd->cmd_len - ISCSI_CDB_SIZE;
-
-	BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb));
-	ahslength = rlen + sizeof(ecdb_ahdr->reserved);
-
-	pad_len = iscsi_padding(rlen);
-
-	rc = iscsi_add_hdr(task, sizeof(ecdb_ahdr->ahslength) +
-	                   sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len);
-	if (rc)
-		return rc;
-
-	if (pad_len)
-		memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
-
-	ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
-	ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
-	ecdb_ahdr->reserved = 0;
-	memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
-
-	debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
-		   "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n",
-		   cmd->cmd_len, rlen, pad_len, ahslength, task->hdr_len);
-
-	return 0;
-}
-
-static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
-{
-	struct scsi_cmnd *sc = task->sc;
-	struct iscsi_rlength_ahdr *rlen_ahdr;
-	int rc;
-
-	rlen_ahdr = iscsi_next_hdr(task);
-	rc = iscsi_add_hdr(task, sizeof(*rlen_ahdr));
-	if (rc)
-		return rc;
-
-	rlen_ahdr->ahslength =
-		cpu_to_be16(sizeof(rlen_ahdr->read_length) +
-						  sizeof(rlen_ahdr->reserved));
-	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
-	rlen_ahdr->reserved = 0;
-	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
-
-	debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
-		   "rlen_ahdr->ahslength(%d)\n",
-		   be32_to_cpu(rlen_ahdr->read_length),
-		   be16_to_cpu(rlen_ahdr->ahslength));
+	ctask->hdr_len = exp_len;
 	return 0;
 }
 
 /**
  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
- * @task: iscsi task
+ * @ctask: iscsi cmd task
  *
  * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set
  * fields like dlength or final based on how much data it sends
  */
-static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
+static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
 {
-	struct iscsi_conn *conn = task->conn;
+	struct iscsi_conn *conn = ctask->conn;
 	struct iscsi_session *session = conn->session;
-	struct iscsi_cmd *hdr = task->hdr;
-	struct scsi_cmnd *sc = task->sc;
-	unsigned hdrlength, cmd_len;
+	struct iscsi_cmd *hdr = ctask->hdr;
+	struct scsi_cmnd *sc = ctask->sc;
+	unsigned hdrlength;
 	int rc;
 
-	task->hdr_len = 0;
-	rc = iscsi_add_hdr(task, sizeof(*hdr));
+	ctask->hdr_len = 0;
+	rc = iscsi_add_hdr(ctask, sizeof(*hdr));
 	if (rc)
 		return rc;
 	hdr->opcode = ISCSI_OP_SCSI_CMD;
 	hdr->flags = ISCSI_ATTR_SIMPLE;
 	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
-	hdr->itt = build_itt(task->itt, session->age);
+	hdr->itt = build_itt(ctask->itt, session->age);
+	hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
 	hdr->cmdsn = cpu_to_be32(session->cmdsn);
 	session->cmdsn++;
 	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
-	cmd_len = sc->cmd_len;
-	if (cmd_len < ISCSI_CDB_SIZE)
-		memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len);
-	else if (cmd_len > ISCSI_CDB_SIZE) {
-		rc = iscsi_prep_ecdb_ahs(task);
-		if (rc)
-			return rc;
-		cmd_len = ISCSI_CDB_SIZE;
-	}
-	memcpy(hdr->cdb, sc->cmnd, cmd_len);
+	memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
+	if (sc->cmd_len < MAX_COMMAND_SIZE)
+		memset(&hdr->cdb[sc->cmd_len], 0,
+			MAX_COMMAND_SIZE - sc->cmd_len);
 
-	task->imm_count = 0;
-	if (scsi_bidi_cmnd(sc)) {
-		hdr->flags |= ISCSI_FLAG_CMD_READ;
-		rc = iscsi_prep_bidi_ahs(task);
-		if (rc)
-			return rc;
-	}
+	ctask->imm_count = 0;
 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
-		unsigned out_len = scsi_out(sc)->length;
-		hdr->data_length = cpu_to_be32(out_len);
 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
 		/*
 		 * Write counters:
@@ -259,41 +187,40 @@
 		 *
 		 *      pad_count       bytes to be sent as zero-padding
 		 */
-		task->unsol_count = 0;
-		task->unsol_offset = 0;
-		task->unsol_datasn = 0;
+		ctask->unsol_count = 0;
+		ctask->unsol_offset = 0;
+		ctask->unsol_datasn = 0;
 
 		if (session->imm_data_en) {
-			if (out_len >= session->first_burst)
-				task->imm_count = min(session->first_burst,
+			if (scsi_bufflen(sc) >= session->first_burst)
+				ctask->imm_count = min(session->first_burst,
 							conn->max_xmit_dlength);
 			else
-				task->imm_count = min(out_len,
+				ctask->imm_count = min(scsi_bufflen(sc),
 							conn->max_xmit_dlength);
-			hton24(hdr->dlength, task->imm_count);
+			hton24(hdr->dlength, ctask->imm_count);
 		} else
 			zero_data(hdr->dlength);
 
 		if (!session->initial_r2t_en) {
-			task->unsol_count = min(session->first_burst, out_len)
-							     - task->imm_count;
-			task->unsol_offset = task->imm_count;
+			ctask->unsol_count = min((session->first_burst),
+				(scsi_bufflen(sc))) - ctask->imm_count;
+			ctask->unsol_offset = ctask->imm_count;
 		}
 
-		if (!task->unsol_count)
+		if (!ctask->unsol_count)
 			/* No unsolicit Data-Out's */
 			hdr->flags |= ISCSI_FLAG_CMD_FINAL;
 	} else {
 		hdr->flags |= ISCSI_FLAG_CMD_FINAL;
 		zero_data(hdr->dlength);
-		hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
 
 		if (sc->sc_data_direction == DMA_FROM_DEVICE)
 			hdr->flags |= ISCSI_FLAG_CMD_READ;
 	}
 
 	/* calculate size of additional header segments (AHSs) */
-	hdrlength = task->hdr_len - sizeof(*hdr);
+	hdrlength = ctask->hdr_len - sizeof(*hdr);
 
 	WARN_ON(hdrlength & (ISCSI_PAD_LEN-1));
 	hdrlength /= ISCSI_PAD_LEN;
@@ -301,175 +228,110 @@
 	WARN_ON(hdrlength >= 256);
 	hdr->hlength = hdrlength & 0xFF;
 
-	if (conn->session->tt->init_task &&
-	    conn->session->tt->init_task(task))
-		return -EIO;
-
-	task->state = ISCSI_TASK_RUNNING;
-	list_move_tail(&task->running, &conn->run_list);
+	if (conn->session->tt->init_cmd_task(conn->ctask))
+		return EIO;
 
 	conn->scsicmd_pdus_cnt++;
 	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
-		   "bidi_len %d cmdsn %d win %d]\n", scsi_bidi_cmnd(sc) ?
-		   "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ?
-		   "write" : "read", conn->id, sc, sc->cmnd[0], task->itt,
-		   scsi_bufflen(sc),
-		   scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
-		   session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+		"cmdsn %d win %d]\n",
+		sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+		conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
+		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
 	return 0;
 }
 
 /**
- * iscsi_complete_command - finish a task
- * @task: iscsi cmd task
+ * iscsi_complete_command - return command back to scsi-ml
+ * @ctask: iscsi cmd task
  *
  * Must be called with session lock.
- * This function returns the scsi command to scsi-ml or cleans
- * up mgmt tasks then returns the task to the pool.
+ * This function returns the scsi command to scsi-ml and returns
+ * the cmd task to the pool of available cmd tasks.
  */
-static void iscsi_complete_command(struct iscsi_task *task)
+static void iscsi_complete_command(struct iscsi_cmd_task *ctask)
 {
-	struct iscsi_conn *conn = task->conn;
+	struct iscsi_conn *conn = ctask->conn;
 	struct iscsi_session *session = conn->session;
-	struct scsi_cmnd *sc = task->sc;
-
-	list_del_init(&task->running);
-	task->state = ISCSI_TASK_COMPLETED;
-	task->sc = NULL;
-
-	if (conn->task == task)
-		conn->task = NULL;
-	/*
-	 * login task is preallocated so do not free
-	 */
-	if (conn->login_task == task)
-		return;
-
-	__kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
-
-	if (conn->ping_task == task)
-		conn->ping_task = NULL;
-
-	if (sc) {
-		task->sc = NULL;
-		/* SCSI eh reuses commands to verify us */
-		sc->SCp.ptr = NULL;
-		/*
-		 * queue command may call this to free the task, but
-		 * not have setup the sc callback
-		 */
-		if (sc->scsi_done)
-			sc->scsi_done(sc);
-	}
-}
+	struct scsi_cmnd *sc = ctask->sc;
 
-void __iscsi_get_task(struct iscsi_task *task)
-{
-	atomic_inc(&task->refcount);
+	ctask->state = ISCSI_TASK_COMPLETED;
+	ctask->sc = NULL;
+	/* SCSI eh reuses commands to verify us */
+	sc->SCp.ptr = NULL;
+	if (conn->ctask == ctask)
+		conn->ctask = NULL;
+	list_del_init(&ctask->running);
+	__kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
+	sc->scsi_done(sc);
 }
-EXPORT_SYMBOL_GPL(__iscsi_get_task);
 
-static void __iscsi_put_task(struct iscsi_task *task)
+static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask)
 {
-	if (atomic_dec_and_test(&task->refcount))
-		iscsi_complete_command(task);
+	atomic_inc(&ctask->refcount);
 }
 
-void iscsi_put_task(struct iscsi_task *task)
+static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
 {
-	struct iscsi_session *session = task->conn->session;
-
-	spin_lock_bh(&session->lock);
-	__iscsi_put_task(task);
-	spin_unlock_bh(&session->lock);
+	if (atomic_dec_and_test(&ctask->refcount))
+		iscsi_complete_command(ctask);
 }
-EXPORT_SYMBOL_GPL(iscsi_put_task);
 
 /*
  * session lock must be held
  */
-static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
+static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
 			 int err)
 {
 	struct scsi_cmnd *sc;
 
-	sc = task->sc;
+	sc = ctask->sc;
 	if (!sc)
 		return;
 
-	if (task->state == ISCSI_TASK_PENDING)
+	if (ctask->state == ISCSI_TASK_PENDING)
 		/*
 		 * cmd never made it to the xmit thread, so we should not count
 		 * the cmd in the sequencing
 		 */
 		conn->session->queued_cmdsn--;
 	else
-		conn->session->tt->cleanup_task(conn, task);
+		conn->session->tt->cleanup_cmd_task(conn, ctask);
 
 	sc->result = err;
-	if (!scsi_bidi_cmnd(sc))
-		scsi_set_resid(sc, scsi_bufflen(sc));
-	else {
-		scsi_out(sc)->resid = scsi_out(sc)->length;
-		scsi_in(sc)->resid = scsi_in(sc)->length;
-	}
-
-	if (conn->task == task)
-		conn->task = NULL;
+	scsi_set_resid(sc, scsi_bufflen(sc));
+	if (conn->ctask == ctask)
+		conn->ctask = NULL;
 	/* release ref from queuecommand */
-	__iscsi_put_task(task);
+	__iscsi_put_ctask(ctask);
 }
 
-static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
-				struct iscsi_task *task)
+/**
+ * iscsi_free_mgmt_task - return mgmt task back to pool
+ * @conn: iscsi connection
+ * @mtask: mtask
+ *
+ * Must be called with session lock.
+ */
+void iscsi_free_mgmt_task(struct iscsi_conn *conn,
+			  struct iscsi_mgmt_task *mtask)
 {
-	struct iscsi_session *session = conn->session;
-	struct iscsi_hdr *hdr = (struct iscsi_hdr *)task->hdr;
-	struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
-
-	if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
-		return -ENOTCONN;
-
-	if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) &&
-	    hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
-		nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
-	/*
-	 * pre-format CmdSN for outgoing PDU.
-	 */
-	nop->cmdsn = cpu_to_be32(session->cmdsn);
-	if (hdr->itt != RESERVED_ITT) {
-		hdr->itt = build_itt(task->itt, session->age);
-		/*
-		 * TODO: We always use immediate, so we never hit this.
-		 * If we start to send tmfs or nops as non-immediate then
-		 * we should start checking the cmdsn numbers for mgmt tasks.
-		 */
-		if (conn->c_stage == ISCSI_CONN_STARTED &&
-		    !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
-			session->queued_cmdsn++;
-			session->cmdsn++;
-		}
-	}
-
-	if (session->tt->init_task)
-		session->tt->init_task(task);
-
-	if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
-		session->state = ISCSI_STATE_LOGGING_OUT;
+	list_del_init(&mtask->running);
+	if (conn->login_mtask == mtask)
+		return;
 
-	list_move_tail(&task->running, &conn->mgmt_run_list);
-	debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
-		   hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
-		   task->data_count);
-	return 0;
+	if (conn->ping_mtask == mtask)
+		conn->ping_mtask = NULL;
+	__kfifo_put(conn->session->mgmtpool.queue,
+		    (void*)&mtask, sizeof(void*));
 }
+EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task);
 
-static struct iscsi_task *
+static struct iscsi_mgmt_task *
 __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 		      char *data, uint32_t data_size)
 {
 	struct iscsi_session *session = conn->session;
-	struct iscsi_task *task;
+	struct iscsi_mgmt_task *mtask;
 
 	if (session->state == ISCSI_STATE_TERMINATE)
 		return NULL;
@@ -479,56 +341,29 @@
 		/*
 		 * Login and Text are sent serially, in
 		 * request-followed-by-response sequence.
-		 * Same task can be used. Same ITT must be used.
-		 * Note that login_task is preallocated at conn_create().
+		 * Same mtask can be used. Same ITT must be used.
+		 * Note that login_mtask is preallocated at conn_create().
 		 */
-		task = conn->login_task;
+		mtask = conn->login_mtask;
 	else {
 		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
 		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
 
-		if (!__kfifo_get(session->cmdpool.queue,
-				 (void*)&task, sizeof(void*)))
+		if (!__kfifo_get(session->mgmtpool.queue,
+				 (void*)&mtask, sizeof(void*)))
 			return NULL;
-
-		if ((hdr->opcode == (ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE)) &&
-		     hdr->ttt == RESERVED_ITT) {
-			conn->ping_task = task;
-			conn->last_ping = jiffies;
-		}
 	}
-	/*
-	 * released in complete pdu for task we expect a response for, and
-	 * released by the lld when it has transmitted the task for
-	 * pdus we do not expect a response for.
-	 */
-	atomic_set(&task->refcount, 1);
-	task->conn = conn;
-	task->sc = NULL;
 
 	if (data_size) {
-		memcpy(task->data, data, data_size);
-		task->data_count = data_size;
-	} else
-		task->data_count = 0;
-
-	memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr));
-	INIT_LIST_HEAD(&task->running);
-	list_add_tail(&task->running, &conn->mgmtqueue);
-
-	if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
-		if (iscsi_prep_mgmt_task(conn, task)) {
-			__iscsi_put_task(task);
-			return NULL;
-		}
-
-		if (session->tt->xmit_task(task))
-			task = NULL;
-
+		memcpy(mtask->data, data, data_size);
+		mtask->data_count = data_size;
 	} else
-		scsi_queue_work(conn->session->host, &conn->xmitwork);
+		mtask->data_count = 0;
 
-	return task;
+	memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
+	INIT_LIST_HEAD(&mtask->running);
+	list_add_tail(&mtask->running, &conn->mgmtqueue);
+	return mtask;
 }
 
 int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
@@ -542,6 +377,7 @@
 	if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
 		err = -EPERM;
 	spin_unlock_bh(&session->lock);
+	scsi_queue_work(session->host, &conn->xmitwork);
 	return err;
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
@@ -550,7 +386,7 @@
  * iscsi_cmd_rsp - SCSI Command Response processing
  * @conn: iscsi connection
  * @hdr: iscsi header
- * @task: scsi command task
+ * @ctask: scsi command task
  * @data: cmd data buffer
  * @datalen: len of buffer
  *
@@ -558,12 +394,12 @@
  * then completes the command and task.
  **/
 static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
-			       struct iscsi_task *task, char *data,
+			       struct iscsi_cmd_task *ctask, char *data,
 			       int datalen)
 {
 	struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr;
 	struct iscsi_session *session = conn->session;
-	struct scsi_cmnd *sc = task->sc;
+	struct scsi_cmnd *sc = ctask->sc;
 
 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
 	conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
@@ -587,7 +423,7 @@
 			goto out;
 		}
 
-		senselen = get_unaligned_be16(data);
+		senselen = be16_to_cpu(get_unaligned((__be16 *) data));
 		if (datalen < senselen)
 			goto invalid_datalen;
 
@@ -597,18 +433,6 @@
 			   min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
 	}
 
-	if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
-			   ISCSI_FLAG_CMD_BIDI_OVERFLOW)) {
-		int res_count = be32_to_cpu(rhdr->bi_residual_count);
-
-		if (scsi_bidi_cmnd(sc) && res_count > 0 &&
-				(rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
-				 res_count <= scsi_in(sc)->length))
-			scsi_in(sc)->resid = res_count;
-		else
-			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
-	}
-
 	if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW |
 	                   ISCSI_FLAG_CMD_OVERFLOW)) {
 		int res_count = be32_to_cpu(rhdr->residual_count);
@@ -616,51 +440,19 @@
 		if (res_count > 0 &&
 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
 		     res_count <= scsi_bufflen(sc)))
-			/* write side for bidi or uni-io set_resid */
 			scsi_set_resid(sc, res_count);
 		else
 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
-	}
+	} else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
+	                          ISCSI_FLAG_CMD_BIDI_OVERFLOW))
+		sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
+
 out:
 	debug_scsi("done [sc %lx res %d itt 0x%x]\n",
-		   (long)sc, sc->result, task->itt);
+		   (long)sc, sc->result, ctask->itt);
 	conn->scsirsp_pdus_cnt++;
 
-	__iscsi_put_task(task);
-}
-
-/**
- * iscsi_data_in_rsp - SCSI Data-In Response processing
- * @conn: iscsi connection
- * @hdr:  iscsi pdu
- * @task: scsi command task
- **/
-static void
-iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
-		  struct iscsi_task *task)
-{
-	struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)hdr;
-	struct scsi_cmnd *sc = task->sc;
-
-	if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
-		return;
-
-	sc->result = (DID_OK << 16) | rhdr->cmd_status;
-	conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
-	if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
-	                   ISCSI_FLAG_DATA_OVERFLOW)) {
-		int res_count = be32_to_cpu(rhdr->residual_count);
-
-		if (res_count > 0 &&
-		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
-		     res_count <= scsi_in(sc)->length))
-			scsi_in(sc)->resid = res_count;
-		else
-			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
-	}
-
-	conn->scsirsp_pdus_cnt++;
-	__iscsi_put_task(task);
+	__iscsi_put_ctask(ctask);
 }
 
 static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
@@ -685,9 +477,9 @@
 static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
 {
         struct iscsi_nopout hdr;
-	struct iscsi_task *task;
+	struct iscsi_mgmt_task *mtask;
 
-	if (!rhdr && conn->ping_task)
+	if (!rhdr && conn->ping_mtask)
 		return;
 
 	memset(&hdr, 0, sizeof(struct iscsi_nopout));
@@ -701,9 +493,18 @@
 	} else
 		hdr.ttt = RESERVED_ITT;
 
-	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
-	if (!task)
+	mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
+	if (!mtask) {
 		iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
+		return;
+	}
+
+	/* only track our nops */
+	if (!rhdr) {
+		conn->ping_mtask = mtask;
+		conn->last_ping = jiffies;
+	}
+	scsi_queue_work(conn->session->host, &conn->xmitwork);
 }
 
 static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
@@ -732,31 +533,6 @@
 }
 
 /**
- * iscsi_itt_to_task - look up task by itt
- * @conn: iscsi connection
- * @itt: itt
- *
- * This should be used for mgmt tasks like login and nops, or if
- * the LDD's itt space does not include the session age.
- *
- * The session lock must be held.
- */
-static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
-{
-	struct iscsi_session *session = conn->session;
-	uint32_t i;
-
-	if (itt == RESERVED_ITT)
-		return NULL;
-
-	i = get_itt(itt);
-	if (i >= session->cmds_max)
-		return NULL;
-
-	return session->cmds[i];
-}
-
-/**
  * __iscsi_complete_pdu - complete pdu
  * @conn: iscsi conn
  * @hdr: iscsi header
@@ -767,28 +543,108 @@
  * queuecommand or send generic. session lock must be held and verify
  * itt must have been called.
  */
-int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
-			 char *data, int datalen)
+static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+				char *data, int datalen)
 {
 	struct iscsi_session *session = conn->session;
 	int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0;
-	struct iscsi_task *task;
+	struct iscsi_cmd_task *ctask;
+	struct iscsi_mgmt_task *mtask;
 	uint32_t itt;
 
 	conn->last_recv = jiffies;
-	rc = iscsi_verify_itt(conn, hdr->itt);
-	if (rc)
-		return rc;
-
 	if (hdr->itt != RESERVED_ITT)
 		itt = get_itt(hdr->itt);
 	else
 		itt = ~0U;
 
-	debug_scsi("[op 0x%x cid %d itt 0x%x len %d]\n",
-		   opcode, conn->id, itt, datalen);
+	if (itt < session->cmds_max) {
+		ctask = session->cmds[itt];
+
+		debug_scsi("cmdrsp [op 0x%x cid %d itt 0x%x len %d]\n",
+			   opcode, conn->id, ctask->itt, datalen);
+
+		switch(opcode) {
+		case ISCSI_OP_SCSI_CMD_RSP:
+			BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
+			iscsi_scsi_cmd_rsp(conn, hdr, ctask, data,
+					   datalen);
+			break;
+		case ISCSI_OP_SCSI_DATA_IN:
+			BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
+			if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
+				conn->scsirsp_pdus_cnt++;
+				__iscsi_put_ctask(ctask);
+			}
+			break;
+		case ISCSI_OP_R2T:
+			/* LLD handles this for now */
+			break;
+		default:
+			rc = ISCSI_ERR_BAD_OPCODE;
+			break;
+		}
+	} else if (itt >= ISCSI_MGMT_ITT_OFFSET &&
+		   itt < ISCSI_MGMT_ITT_OFFSET + session->mgmtpool_max) {
+		mtask = session->mgmt_cmds[itt - ISCSI_MGMT_ITT_OFFSET];
+
+		debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n",
+			   opcode, conn->id, mtask->itt, datalen);
 
-	if (itt == ~0U) {
+		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
+		switch(opcode) {
+		case ISCSI_OP_LOGOUT_RSP:
+			if (datalen) {
+				rc = ISCSI_ERR_PROTO;
+				break;
+			}
+			conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
+			/* fall through */
+		case ISCSI_OP_LOGIN_RSP:
+		case ISCSI_OP_TEXT_RSP:
+			/*
+			 * login related PDU's exp_statsn is handled in
+			 * userspace
+			 */
+			if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
+				rc = ISCSI_ERR_CONN_FAILED;
+			iscsi_free_mgmt_task(conn, mtask);
+			break;
+		case ISCSI_OP_SCSI_TMFUNC_RSP:
+			if (datalen) {
+				rc = ISCSI_ERR_PROTO;
+				break;
+			}
+
+			iscsi_tmf_rsp(conn, hdr);
+			iscsi_free_mgmt_task(conn, mtask);
+			break;
+		case ISCSI_OP_NOOP_IN:
+			if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) ||
+			    datalen) {
+				rc = ISCSI_ERR_PROTO;
+				break;
+			}
+			conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
+
+			if (conn->ping_mtask != mtask) {
+				/*
+				 * If this is not in response to one of our
+				 * nops then it must be from userspace.
+				 */
+				if (iscsi_recv_pdu(conn->cls_conn, hdr, data,
+						   datalen))
+					rc = ISCSI_ERR_CONN_FAILED;
+			} else
+				mod_timer(&conn->transport_timer,
+					  jiffies + conn->recv_timeout);
+			iscsi_free_mgmt_task(conn, mtask);
+			break;
+		default:
+			rc = ISCSI_ERR_BAD_OPCODE;
+			break;
+		}
+	} else if (itt == ~0U) {
 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
 
 		switch(opcode) {
@@ -815,99 +671,11 @@
 			rc = ISCSI_ERR_BAD_OPCODE;
 			break;
 		}
-		goto out;
-	}
-
-	switch(opcode) {
-	case ISCSI_OP_SCSI_CMD_RSP:
-	case ISCSI_OP_SCSI_DATA_IN:
-		task = iscsi_itt_to_ctask(conn, hdr->itt);
-		if (!task)
-			return ISCSI_ERR_BAD_ITT;
-		break;
-	case ISCSI_OP_R2T:
-		/*
-		 * LLD handles R2Ts if they need to.
-		 */
-		return 0;
-	case ISCSI_OP_LOGOUT_RSP:
-	case ISCSI_OP_LOGIN_RSP:
-	case ISCSI_OP_TEXT_RSP:
-	case ISCSI_OP_SCSI_TMFUNC_RSP:
-	case ISCSI_OP_NOOP_IN:
-		task = iscsi_itt_to_task(conn, hdr->itt);
-		if (!task)
-			return ISCSI_ERR_BAD_ITT;
-		break;
-	default:
-		return ISCSI_ERR_BAD_OPCODE;
-	}
-
-	switch(opcode) {
-	case ISCSI_OP_SCSI_CMD_RSP:
-		iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen);
-		break;
-	case ISCSI_OP_SCSI_DATA_IN:
-		iscsi_data_in_rsp(conn, hdr, task);
-		break;
-	case ISCSI_OP_LOGOUT_RSP:
-		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
-		if (datalen) {
-			rc = ISCSI_ERR_PROTO;
-			break;
-		}
-		conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
-		goto recv_pdu;
-	case ISCSI_OP_LOGIN_RSP:
-	case ISCSI_OP_TEXT_RSP:
-		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
-		/*
-		 * login related PDU's exp_statsn is handled in
-		 * userspace
-		 */
-		goto recv_pdu;
-	case ISCSI_OP_SCSI_TMFUNC_RSP:
-		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
-		if (datalen) {
-			rc = ISCSI_ERR_PROTO;
-			break;
-		}
-
-		iscsi_tmf_rsp(conn, hdr);
-		__iscsi_put_task(task);
-		break;
-	case ISCSI_OP_NOOP_IN:
-		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
-		if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
-			rc = ISCSI_ERR_PROTO;
-			break;
-		}
-		conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
-
-		if (conn->ping_task != task)
-			/*
-			 * If this is not in response to one of our
-			 * nops then it must be from userspace.
-			 */
-			goto recv_pdu;
-
-		mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
-		__iscsi_put_task(task);
-		break;
-	default:
-		rc = ISCSI_ERR_BAD_OPCODE;
-		break;
-	}
+	} else
+		rc = ISCSI_ERR_BAD_ITT;
 
-out:
-	return rc;
-recv_pdu:
-	if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
-		rc = ISCSI_ERR_CONN_FAILED;
-	__iscsi_put_task(task);
 	return rc;
 }
-EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
 
 int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 		       char *data, int datalen)
@@ -921,63 +689,51 @@
 }
 EXPORT_SYMBOL_GPL(iscsi_complete_pdu);
 
-int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
+/* verify itt (itt encoding: age+cid+itt) */
+int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+		     uint32_t *ret_itt)
 {
 	struct iscsi_session *session = conn->session;
-	uint32_t i;
-
-	if (itt == RESERVED_ITT)
-		return 0;
-
-	if (((__force u32)itt & ISCSI_AGE_MASK) !=
-	    (session->age << ISCSI_AGE_SHIFT)) {
-		iscsi_conn_printk(KERN_ERR, conn,
-				  "received itt %x expected session age (%x)\n",
-				  (__force u32)itt, session->age);
-		return ISCSI_ERR_BAD_ITT;
-	}
+	struct iscsi_cmd_task *ctask;
+	uint32_t itt;
 
-	i = get_itt(itt);
-	if (i >= session->cmds_max) {
-		iscsi_conn_printk(KERN_ERR, conn,
-				  "received invalid itt index %u (max cmds "
-				   "%u.\n", i, session->cmds_max);
-		return ISCSI_ERR_BAD_ITT;
-	}
-	return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_verify_itt);
+	if (hdr->itt != RESERVED_ITT) {
+		if (((__force u32)hdr->itt & ISCSI_AGE_MASK) !=
+		    (session->age << ISCSI_AGE_SHIFT)) {
+			iscsi_conn_printk(KERN_ERR, conn,
+					  "received itt %x expected session "
+					  "age (%x)\n", (__force u32)hdr->itt,
+					  session->age & ISCSI_AGE_MASK);
+			return ISCSI_ERR_BAD_ITT;
+		}
 
-/**
- * iscsi_itt_to_ctask - look up ctask by itt
- * @conn: iscsi connection
- * @itt: itt
- *
- * This should be used for cmd tasks.
- *
- * The session lock must be held.
- */
-struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
-{
-	struct iscsi_task *task;
+		itt = get_itt(hdr->itt);
+	} else
+		itt = ~0U;
 
-	if (iscsi_verify_itt(conn, itt))
-		return NULL;
+	if (itt < session->cmds_max) {
+		ctask = session->cmds[itt];
 
-	task = iscsi_itt_to_task(conn, itt);
-	if (!task || !task->sc)
-		return NULL;
+		if (!ctask->sc) {
+			iscsi_conn_printk(KERN_INFO, conn, "dropping ctask "
+					  "with itt 0x%x\n", ctask->itt);
+			/* force drop */
+			return ISCSI_ERR_NO_SCSI_CMD;
+		}
 
-	if (task->sc->SCp.phase != conn->session->age) {
-		iscsi_session_printk(KERN_ERR, conn->session,
-				  "task's session age %d, expected %d\n",
-				  task->sc->SCp.phase, conn->session->age);
-		return NULL;
+		if (ctask->sc->SCp.phase != session->age) {
+			iscsi_conn_printk(KERN_ERR, conn,
+					  "iscsi: ctask's session age %d, "
+					  "expected %d\n", ctask->sc->SCp.phase,
+					  session->age);
+			return ISCSI_ERR_SESSION_FAILED;
+		}
 	}
 
-	return task;
+	*ret_itt = itt;
+	return 0;
 }
-EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask);
+EXPORT_SYMBOL_GPL(iscsi_verify_itt);
 
 void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
 {
@@ -999,6 +755,61 @@
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_failure);
 
+static void iscsi_prep_mtask(struct iscsi_conn *conn,
+			     struct iscsi_mgmt_task *mtask)
+{
+	struct iscsi_session *session = conn->session;
+	struct iscsi_hdr *hdr = mtask->hdr;
+	struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
+
+	if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) &&
+	    hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
+		nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
+	/*
+	 * pre-format CmdSN for outgoing PDU.
+	 */
+	nop->cmdsn = cpu_to_be32(session->cmdsn);
+	if (hdr->itt != RESERVED_ITT) {
+		hdr->itt = build_itt(mtask->itt, session->age);
+		/*
+		 * TODO: We always use immediate, so we never hit this.
+		 * If we start to send tmfs or nops as non-immediate then
+		 * we should start checking the cmdsn numbers for mgmt tasks.
+		 */
+		if (conn->c_stage == ISCSI_CONN_STARTED &&
+		    !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+			session->queued_cmdsn++;
+			session->cmdsn++;
+		}
+	}
+
+	if (session->tt->init_mgmt_task)
+		session->tt->init_mgmt_task(conn, mtask);
+
+	debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
+		   hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
+		   mtask->data_count);
+}
+
+static int iscsi_xmit_mtask(struct iscsi_conn *conn)
+{
+	struct iscsi_hdr *hdr = conn->mtask->hdr;
+	int rc;
+
+	if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
+		conn->session->state = ISCSI_STATE_LOGGING_OUT;
+	spin_unlock_bh(&conn->session->lock);
+
+	rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
+	spin_lock_bh(&conn->session->lock);
+	if (rc)
+		return rc;
+
+	/* done with this in-progress mtask */
+	conn->mtask = NULL;
+	return 0;
+}
+
 static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
 {
 	struct iscsi_session *session = conn->session;
@@ -1016,38 +827,37 @@
 	return 0;
 }
 
-static int iscsi_xmit_task(struct iscsi_conn *conn)
+static int iscsi_xmit_ctask(struct iscsi_conn *conn)
 {
-	struct iscsi_task *task = conn->task;
+	struct iscsi_cmd_task *ctask = conn->ctask;
 	int rc;
 
-	__iscsi_get_task(task);
+	__iscsi_get_ctask(ctask);
 	spin_unlock_bh(&conn->session->lock);
-	rc = conn->session->tt->xmit_task(task);
+	rc = conn->session->tt->xmit_cmd_task(conn, ctask);
 	spin_lock_bh(&conn->session->lock);
-	__iscsi_put_task(task);
+	__iscsi_put_ctask(ctask);
 	if (!rc)
-		/* done with this task */
-		conn->task = NULL;
+		/* done with this ctask */
+		conn->ctask = NULL;
 	return rc;
 }
 
 /**
- * iscsi_requeue_task - requeue task to run from session workqueue
- * @task: task to requeue
+ * iscsi_requeue_ctask - requeue ctask to run from session workqueue
+ * @ctask: ctask to requeue
  *
- * LLDs that need to run a task from the session workqueue should call
- * this. The session lock must be held. This should only be called
- * by software drivers.
+ * LLDs that need to run a ctask from the session workqueue should call
+ * this. The session lock must be held.
  */
-void iscsi_requeue_task(struct iscsi_task *task)
+void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask)
 {
-	struct iscsi_conn *conn = task->conn;
+	struct iscsi_conn *conn = ctask->conn;
 
-	list_move_tail(&task->running, &conn->requeue);
+	list_move_tail(&ctask->running, &conn->requeue);
 	scsi_queue_work(conn->session->host, &conn->xmitwork);
 }
-EXPORT_SYMBOL_GPL(iscsi_requeue_task);
+EXPORT_SYMBOL_GPL(iscsi_requeue_ctask);
 
 /**
  * iscsi_data_xmit - xmit any command into the scheduled connection
@@ -1069,8 +879,14 @@
 		return -ENODATA;
 	}
 
-	if (conn->task) {
-		rc = iscsi_xmit_task(conn);
+	if (conn->ctask) {
+		rc = iscsi_xmit_ctask(conn);
+		if (rc)
+			goto again;
+	}
+
+	if (conn->mtask) {
+		rc = iscsi_xmit_mtask(conn);
 	        if (rc)
 		        goto again;
 	}
@@ -1082,14 +898,17 @@
 	 */
 check_mgmt:
 	while (!list_empty(&conn->mgmtqueue)) {
-		conn->task = list_entry(conn->mgmtqueue.next,
-					 struct iscsi_task, running);
-		if (iscsi_prep_mgmt_task(conn, conn->task)) {
-			__iscsi_put_task(conn->task);
-			conn->task = NULL;
+		conn->mtask = list_entry(conn->mgmtqueue.next,
+					 struct iscsi_mgmt_task, running);
+		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
+			iscsi_free_mgmt_task(conn, conn->mtask);
+			conn->mtask = NULL;
 			continue;
 		}
-		rc = iscsi_xmit_task(conn);
+
+		iscsi_prep_mtask(conn, conn->mtask);
+		list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list);
+		rc = iscsi_xmit_mtask(conn);
 		if (rc)
 			goto again;
 	}
@@ -1099,21 +918,24 @@
 		if (conn->tmf_state == TMF_QUEUED)
 			break;
 
-		conn->task = list_entry(conn->xmitqueue.next,
-					 struct iscsi_task, running);
+		conn->ctask = list_entry(conn->xmitqueue.next,
+					 struct iscsi_cmd_task, running);
 		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
-			fail_command(conn, conn->task, DID_IMM_RETRY << 16);
+			fail_command(conn, conn->ctask, DID_IMM_RETRY << 16);
 			continue;
 		}
-		if (iscsi_prep_scsi_cmd_pdu(conn->task)) {
-			fail_command(conn, conn->task, DID_ABORT << 16);
+		if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) {
+			fail_command(conn, conn->ctask, DID_ABORT << 16);
 			continue;
 		}
-		rc = iscsi_xmit_task(conn);
+
+		conn->ctask->state = ISCSI_TASK_RUNNING;
+		list_move_tail(conn->xmitqueue.next, &conn->run_list);
+		rc = iscsi_xmit_ctask(conn);
 		if (rc)
 			goto again;
 		/*
-		 * we could continuously get new task requests so
+		 * we could continuously get new ctask requests so
 		 * we need to check the mgmt queue for nops that need to
 		 * be sent to aviod starvation
 		 */
@@ -1131,11 +953,11 @@
 		if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
 			break;
 
-		conn->task = list_entry(conn->requeue.next,
-					 struct iscsi_task, running);
-		conn->task->state = ISCSI_TASK_RUNNING;
+		conn->ctask = list_entry(conn->requeue.next,
+					 struct iscsi_cmd_task, running);
+		conn->ctask->state = ISCSI_TASK_RUNNING;
 		list_move_tail(conn->requeue.next, &conn->run_list);
-		rc = iscsi_xmit_task(conn);
+		rc = iscsi_xmit_ctask(conn);
 		if (rc)
 			goto again;
 		if (!list_empty(&conn->mgmtqueue))
@@ -1179,12 +1001,11 @@
 
 int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 {
-	struct iscsi_cls_session *cls_session;
 	struct Scsi_Host *host;
 	int reason = 0;
 	struct iscsi_session *session;
 	struct iscsi_conn *conn;
-	struct iscsi_task *task = NULL;
+	struct iscsi_cmd_task *ctask = NULL;
 
 	sc->scsi_done = done;
 	sc->result = 0;
@@ -1193,11 +1014,10 @@
 	host = sc->device->host;
 	spin_unlock(host->host_lock);
 
-	cls_session = starget_to_session(scsi_target(sc->device));
-	session = cls_session->dd_data;
+	session = iscsi_hostdata(host->hostdata);
 	spin_lock(&session->lock);
 
-	reason = iscsi_session_chkready(cls_session);
+	reason = iscsi_session_chkready(session_to_cls(session));
 	if (reason) {
 		sc->result = reason;
 		goto fault;
@@ -1252,39 +1072,26 @@
 		goto reject;
 	}
 
-	if (!__kfifo_get(session->cmdpool.queue, (void*)&task,
+	if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask,
 			 sizeof(void*))) {
 		reason = FAILURE_OOM;
 		goto reject;
 	}
+	session->queued_cmdsn++;
+
 	sc->SCp.phase = session->age;
-	sc->SCp.ptr = (char *)task;
+	sc->SCp.ptr = (char *)ctask;
 
-	atomic_set(&task->refcount, 1);
-	task->state = ISCSI_TASK_PENDING;
-	task->conn = conn;
-	task->sc = sc;
-	INIT_LIST_HEAD(&task->running);
-	list_add_tail(&task->running, &conn->xmitqueue);
-
-	if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
-		if (iscsi_prep_scsi_cmd_pdu(task)) {
-			sc->result = DID_ABORT << 16;
-			sc->scsi_done = NULL;
-			iscsi_complete_command(task);
-			goto fault;
-		}
-		if (session->tt->xmit_task(task)) {
-			sc->scsi_done = NULL;
-			iscsi_complete_command(task);
-			reason = FAILURE_SESSION_NOT_READY;
-			goto reject;
-		}
-	} else
-		scsi_queue_work(session->host, &conn->xmitwork);
+	atomic_set(&ctask->refcount, 1);
+	ctask->state = ISCSI_TASK_PENDING;
+	ctask->conn = conn;
+	ctask->sc = sc;
+	INIT_LIST_HEAD(&ctask->running);
 
-	session->queued_cmdsn++;
+	list_add_tail(&ctask->running, &conn->xmitqueue);
 	spin_unlock(&session->lock);
+
+	scsi_queue_work(host, &conn->xmitwork);
 	spin_lock(host->host_lock);
 	return 0;
 
@@ -1297,13 +1104,8 @@
 fault:
 	spin_unlock(&session->lock);
 	debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
-	if (!scsi_bidi_cmnd(sc))
-		scsi_set_resid(sc, scsi_bufflen(sc));
-	else {
-		scsi_out(sc)->resid = scsi_out(sc)->length;
-		scsi_in(sc)->resid = scsi_in(sc)->length;
-	}
-	done(sc);
+	scsi_set_resid(sc, scsi_bufflen(sc));
+	sc->scsi_done(sc);
 	spin_lock(host->host_lock);
 	return 0;
 }
@@ -1320,7 +1122,7 @@
 
 void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
 {
-	struct iscsi_session *session = cls_session->dd_data;
+	struct iscsi_session *session = class_to_transport_session(cls_session);
 
 	spin_lock_bh(&session->lock);
 	if (session->state != ISCSI_STATE_LOGGED_IN) {
@@ -1334,13 +1136,9 @@
 
 int iscsi_eh_host_reset(struct scsi_cmnd *sc)
 {
-	struct iscsi_cls_session *cls_session;
-	struct iscsi_session *session;
-	struct iscsi_conn *conn;
-
-	cls_session = starget_to_session(scsi_target(sc->device));
-	session = cls_session->dd_data;
-	conn = session->leadconn;
+	struct Scsi_Host *host = sc->device->host;
+	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
+	struct iscsi_conn *conn = session->leadconn;
 
 	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->lock);
@@ -1402,11 +1200,11 @@
 				   int timeout)
 {
 	struct iscsi_session *session = conn->session;
-	struct iscsi_task *task;
+	struct iscsi_mgmt_task *mtask;
 
-	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
+	mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
 				      NULL, 0);
-	if (!task) {
+	if (!mtask) {
 		spin_unlock_bh(&session->lock);
 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
 		spin_lock_bh(&session->lock);
@@ -1422,6 +1220,7 @@
 
 	spin_unlock_bh(&session->lock);
 	mutex_unlock(&session->eh_mutex);
+	scsi_queue_work(session->host, &conn->xmitwork);
 
 	/*
 	 * block eh thread until:
@@ -1440,7 +1239,7 @@
 
 	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->lock);
-	/* if the session drops it will clean up the task */
+	/* if the session drops it will clean up the mtask */
 	if (age != session->age ||
 	    session->state != ISCSI_STATE_LOGGED_IN)
 		return -ENOTCONN;
@@ -1454,51 +1253,48 @@
 static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
 			      int error)
 {
-	struct iscsi_task *task, *tmp;
+	struct iscsi_cmd_task *ctask, *tmp;
 
-	if (conn->task && (conn->task->sc->device->lun == lun || lun == -1))
-		conn->task = NULL;
+	if (conn->ctask && (conn->ctask->sc->device->lun == lun || lun == -1))
+		conn->ctask = NULL;
 
 	/* flush pending */
-	list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) {
-		if (lun == task->sc->device->lun || lun == -1) {
+	list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
+		if (lun == ctask->sc->device->lun || lun == -1) {
 			debug_scsi("failing pending sc %p itt 0x%x\n",
-				   task->sc, task->itt);
-			fail_command(conn, task, error << 16);
+				   ctask->sc, ctask->itt);
+			fail_command(conn, ctask, error << 16);
 		}
 	}
 
-	list_for_each_entry_safe(task, tmp, &conn->requeue, running) {
-		if (lun == task->sc->device->lun || lun == -1) {
+	list_for_each_entry_safe(ctask, tmp, &conn->requeue, running) {
+		if (lun == ctask->sc->device->lun || lun == -1) {
 			debug_scsi("failing requeued sc %p itt 0x%x\n",
-				   task->sc, task->itt);
-			fail_command(conn, task, error << 16);
+				   ctask->sc, ctask->itt);
+			fail_command(conn, ctask, error << 16);
 		}
 	}
 
 	/* fail all other running */
-	list_for_each_entry_safe(task, tmp, &conn->run_list, running) {
-		if (lun == task->sc->device->lun || lun == -1) {
+	list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
+		if (lun == ctask->sc->device->lun || lun == -1) {
 			debug_scsi("failing in progress sc %p itt 0x%x\n",
-				   task->sc, task->itt);
-			fail_command(conn, task, DID_BUS_BUSY << 16);
+				   ctask->sc, ctask->itt);
+			fail_command(conn, ctask, DID_BUS_BUSY << 16);
 		}
 	}
 }
 
-void iscsi_suspend_tx(struct iscsi_conn *conn)
+static void iscsi_suspend_tx(struct iscsi_conn *conn)
 {
 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-	if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
-		scsi_flush_work(conn->session->host);
+	scsi_flush_work(conn->session->host);
 }
-EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
 
 static void iscsi_start_tx(struct iscsi_conn *conn)
 {
 	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-	if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
-		scsi_queue_work(conn->session->host, &conn->xmitwork);
+	scsi_queue_work(conn->session->host, &conn->xmitwork);
 }
 
 static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
@@ -1509,7 +1305,7 @@
 	enum scsi_eh_timer_return rc = EH_NOT_HANDLED;
 
 	cls_session = starget_to_session(scsi_target(scmd->device));
-	session = cls_session->dd_data;
+	session = class_to_transport_session(cls_session);
 
 	debug_scsi("scsi cmd %p timedout\n", scmd);
 
@@ -1547,7 +1343,7 @@
 			   jiffies))
 		rc = EH_RESET_TIMER;
 	/* if in the middle of checking the transport then give us more time */
-	if (conn->ping_task)
+	if (conn->ping_mtask)
 		rc = EH_RESET_TIMER;
 done:
 	spin_unlock(&session->lock);
@@ -1571,7 +1367,7 @@
 
 	recv_timeout *= HZ;
 	last_recv = conn->last_recv;
-	if (conn->ping_task &&
+	if (conn->ping_mtask &&
 	    time_before_eq(conn->last_ping + (conn->ping_timeout * HZ),
 			   jiffies)) {
 		iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs "
@@ -1597,30 +1393,27 @@
 	spin_unlock(&session->lock);
 }
 
-static void iscsi_prep_abort_task_pdu(struct iscsi_task *task,
+static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask,
 				      struct iscsi_tm *hdr)
 {
 	memset(hdr, 0, sizeof(*hdr));
 	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
 	hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK;
 	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
-	memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun));
-	hdr->rtt = task->hdr->itt;
-	hdr->refcmdsn = task->hdr->cmdsn;
+	memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
+	hdr->rtt = ctask->hdr->itt;
+	hdr->refcmdsn = ctask->hdr->cmdsn;
 }
 
 int iscsi_eh_abort(struct scsi_cmnd *sc)
 {
-	struct iscsi_cls_session *cls_session;
-	struct iscsi_session *session;
+	struct Scsi_Host *host = sc->device->host;
+	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
 	struct iscsi_conn *conn;
-	struct iscsi_task *task;
+	struct iscsi_cmd_task *ctask;
 	struct iscsi_tm *hdr;
 	int rc, age;
 
-	cls_session = starget_to_session(scsi_target(sc->device));
-	session = cls_session->dd_data;
-
 	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->lock);
 	/*
@@ -1649,17 +1442,17 @@
 	conn->eh_abort_cnt++;
 	age = session->age;
 
-	task = (struct iscsi_task *)sc->SCp.ptr;
-	debug_scsi("aborting [sc %p itt 0x%x]\n", sc, task->itt);
+	ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
+	debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
 
-	/* task completed before time out */
-	if (!task->sc) {
+	/* ctask completed before time out */
+	if (!ctask->sc) {
 		debug_scsi("sc completed while abort in progress\n");
 		goto success;
 	}
 
-	if (task->state == ISCSI_TASK_PENDING) {
-		fail_command(conn, task, DID_ABORT << 16);
+	if (ctask->state == ISCSI_TASK_PENDING) {
+		fail_command(conn, ctask, DID_ABORT << 16);
 		goto success;
 	}
 
@@ -1669,7 +1462,7 @@
 	conn->tmf_state = TMF_QUEUED;
 
 	hdr = &conn->tmhdr;
-	iscsi_prep_abort_task_pdu(task, hdr);
+	iscsi_prep_abort_task_pdu(ctask, hdr);
 
 	if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) {
 		rc = FAILED;
@@ -1679,20 +1472,16 @@
 	switch (conn->tmf_state) {
 	case TMF_SUCCESS:
 		spin_unlock_bh(&session->lock);
-		/*
-		 * stop tx side incase the target had sent a abort rsp but
-		 * the initiator was still writing out data.
-		 */
 		iscsi_suspend_tx(conn);
 		/*
-		 * we do not stop the recv side because targets have been
-		 * good and have never sent us a successful tmf response
-		 * then sent more data for the cmd.
+		 * clean up task if aborted. grab the recv lock as a writer
 		 */
+		write_lock_bh(conn->recv_lock);
 		spin_lock(&session->lock);
-		fail_command(conn, task, DID_ABORT << 16);
+		fail_command(conn, ctask, DID_ABORT << 16);
 		conn->tmf_state = TMF_INITIAL;
 		spin_unlock(&session->lock);
+		write_unlock_bh(conn->recv_lock);
 		iscsi_start_tx(conn);
 		goto success_unlocked;
 	case TMF_TIMEDOUT:
@@ -1702,7 +1491,7 @@
 	case TMF_NOT_FOUND:
 		if (!sc->SCp.ptr) {
 			conn->tmf_state = TMF_INITIAL;
-			/* task completed before tmf abort response */
+			/* ctask completed before tmf abort response */
 			debug_scsi("sc completed while abort in progress\n");
 			goto success;
 		}
@@ -1715,7 +1504,7 @@
 success:
 	spin_unlock_bh(&session->lock);
 success_unlocked:
-	debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, task->itt);
+	debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
 	mutex_unlock(&session->eh_mutex);
 	return SUCCESS;
 
@@ -1723,7 +1512,7 @@
 	spin_unlock_bh(&session->lock);
 failed_unlocked:
 	debug_scsi("abort failed [sc %p itt 0x%x]\n", sc,
-		    task ? task->itt : 0);
+		    ctask ? ctask->itt : 0);
 	mutex_unlock(&session->eh_mutex);
 	return FAILED;
 }
@@ -1741,15 +1530,12 @@
 
 int iscsi_eh_device_reset(struct scsi_cmnd *sc)
 {
-	struct iscsi_cls_session *cls_session;
-	struct iscsi_session *session;
+	struct Scsi_Host *host = sc->device->host;
+	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
 	struct iscsi_conn *conn;
 	struct iscsi_tm *hdr;
 	int rc = FAILED;
 
-	cls_session = starget_to_session(scsi_target(sc->device));
-	session = cls_session->dd_data;
-
 	debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
 
 	mutex_lock(&session->eh_mutex);
@@ -1792,11 +1578,13 @@
 	spin_unlock_bh(&session->lock);
 
 	iscsi_suspend_tx(conn);
-
-	spin_lock_bh(&session->lock);
+	/* need to grab the recv lock then session lock */
+	write_lock_bh(conn->recv_lock);
+	spin_lock(&session->lock);
 	fail_all_commands(conn, sc->device->lun, DID_ERROR);
 	conn->tmf_state = TMF_INITIAL;
-	spin_unlock_bh(&session->lock);
+	spin_unlock(&session->lock);
+	write_unlock_bh(conn->recv_lock);
 
 	iscsi_start_tx(conn);
 	goto done;
@@ -1872,203 +1660,177 @@
 }
 EXPORT_SYMBOL_GPL(iscsi_pool_free);
 
-/**
- * iscsi_host_add - add host to system
- * @shost: scsi host
- * @pdev: parent device
- *
- * This should be called by partial offload and software iscsi drivers
- * to add a host to the system.
- */
-int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev)
-{
-	if (!shost->can_queue)
-		shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX;
-
-	return scsi_add_host(shost, pdev);
-}
-EXPORT_SYMBOL_GPL(iscsi_host_add);
-
-/**
- * iscsi_host_alloc - allocate a host and driver data
- * @sht: scsi host template
- * @dd_data_size: driver host data size
- * @qdepth: default device queue depth
- *
- * This should be called by partial offload and software iscsi drivers.
- * To access the driver specific memory use the iscsi_host_priv() macro.
- */
-struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
-				   int dd_data_size, uint16_t qdepth)
-{
-	struct Scsi_Host *shost;
-
-	shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size);
-	if (!shost)
-		return NULL;
-	shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
-
-	if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) {
-		if (qdepth != 0)
-			printk(KERN_ERR "iscsi: invalid queue depth of %d. "
-			       "Queue depth must be between 1 and %d.\n",
-			       qdepth, ISCSI_MAX_CMD_PER_LUN);
-		qdepth = ISCSI_DEF_CMD_PER_LUN;
-	}
-	shost->cmd_per_lun = qdepth;
-	return shost;
-}
-EXPORT_SYMBOL_GPL(iscsi_host_alloc);
-
-/**
- * iscsi_host_remove - remove host and sessions
- * @shost: scsi host
+/*
+ * iSCSI Session's hostdata organization:
  *
- * This will also remove any sessions attached to the host, but if userspace
- * is managing the session at the same time this will break. TODO: add
- * refcounting to the netlink iscsi interface so a rmmod or host hot unplug
- * does not remove the memory from under us.
+ *    *------------------* <== hostdata_session(host->hostdata)
+ *    | ptr to class sess|
+ *    |------------------| <== iscsi_hostdata(host->hostdata)
+ *    | iscsi_session    |
+ *    *------------------*
  */
-void iscsi_host_remove(struct Scsi_Host *shost)
-{
-	iscsi_host_for_each_session(shost, iscsi_session_teardown);
-	scsi_remove_host(shost);
-}
-EXPORT_SYMBOL_GPL(iscsi_host_remove);
 
-void iscsi_host_free(struct Scsi_Host *shost)
-{
-	struct iscsi_host *ihost = shost_priv(shost);
+#define hostdata_privsize(_sz)	(sizeof(unsigned long) + _sz + \
+				 _sz % sizeof(unsigned long))
 
-	kfree(ihost->netdev);
-	kfree(ihost->hwaddress);
-	kfree(ihost->initiatorname);
-	scsi_host_put(shost);
-}
-EXPORT_SYMBOL_GPL(iscsi_host_free);
+#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
 
 /**
  * iscsi_session_setup - create iscsi cls session and host and session
+ * @scsit: scsi transport template
  * @iscsit: iscsi transport template
- * @shost: scsi host
- * @cmds_max: session can queue
- * @cmd_task_size: LLD task private data size
+ * @cmds_max: scsi host can queue
+ * @qdepth: scsi host cmds per lun
+ * @cmd_task_size: LLD ctask private data size
+ * @mgmt_task_size: LLD mtask private data size
  * @initial_cmdsn: initial CmdSN
+ * @hostno: host no allocated
  *
  * This can be used by software iscsi_transports that allocate
  * a session per scsi host.
- *
- * Callers should set cmds_max to the largest total numer (mgmt + scsi) of
- * tasks they support. The iscsi layer reserves ISCSI_MGMT_CMDS_MAX tasks
- * for nop handling and login/logout requests.
- */
+ **/
 struct iscsi_cls_session *
-iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
-		    uint16_t cmds_max, int cmd_task_size,
-		    uint32_t initial_cmdsn, unsigned int id)
+iscsi_session_setup(struct iscsi_transport *iscsit,
+		    struct scsi_transport_template *scsit,
+		    uint16_t cmds_max, uint16_t qdepth,
+		    int cmd_task_size, int mgmt_task_size,
+		    uint32_t initial_cmdsn, uint32_t *hostno)
 {
+	struct Scsi_Host *shost;
 	struct iscsi_session *session;
 	struct iscsi_cls_session *cls_session;
-	int cmd_i, scsi_cmds, total_cmds = cmds_max;
-
-	if (!total_cmds)
-		total_cmds = ISCSI_DEF_XMIT_CMDS_MAX;
-	/*
-	 * The iscsi layer needs some tasks for nop handling and tmfs,
-	 * so the cmds_max must at least be greater than ISCSI_MGMT_CMDS_MAX
-	 * + 1 command for scsi IO.
-	 */
-	if (total_cmds < ISCSI_TOTAL_CMDS_MIN) {
-		printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
-		       "must be a power of two that is at least %d.\n",
-		       total_cmds, ISCSI_TOTAL_CMDS_MIN);
-		return NULL;
-	}
+	int cmd_i;
 
-	if (total_cmds > ISCSI_TOTAL_CMDS_MAX) {
-		printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
-		       "must be a power of 2 less than or equal to %d.\n",
-		       cmds_max, ISCSI_TOTAL_CMDS_MAX);
-		total_cmds = ISCSI_TOTAL_CMDS_MAX;
+	if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) {
+		if (qdepth != 0)
+			printk(KERN_ERR "iscsi: invalid queue depth of %d. "
+			      "Queue depth must be between 1 and %d.\n",
+			      qdepth, ISCSI_MAX_CMD_PER_LUN);
+		qdepth = ISCSI_DEF_CMD_PER_LUN;
 	}
 
-	if (!is_power_of_2(total_cmds)) {
-		printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
-		       "must be a power of 2.\n", total_cmds);
-		total_cmds = rounddown_pow_of_two(total_cmds);
-		if (total_cmds < ISCSI_TOTAL_CMDS_MIN)
-			return NULL;
-		printk(KERN_INFO "iscsi: Rounding can_queue to %d.\n",
-		       total_cmds);
+	if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET ||
+	    cmds_max < 2) {
+		if (cmds_max != 0)
+			printk(KERN_ERR "iscsi: invalid can_queue of %d. "
+			       "can_queue must be a power of 2 and between "
+			       "2 and %d - setting to %d.\n", cmds_max,
+			       ISCSI_MGMT_ITT_OFFSET, ISCSI_DEF_XMIT_CMDS_MAX);
+		cmds_max = ISCSI_DEF_XMIT_CMDS_MAX;
 	}
-	scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX;
 
-	cls_session = iscsi_alloc_session(shost, iscsit,
-					  sizeof(struct iscsi_session));
-	if (!cls_session)
+	shost = scsi_host_alloc(iscsit->host_template,
+				hostdata_privsize(sizeof(*session)));
+	if (!shost)
 		return NULL;
-	session = cls_session->dd_data;
-	session->cls_session = cls_session;
+
+	/* the iscsi layer takes one task for reserve */
+	shost->can_queue = cmds_max - 1;
+	shost->cmd_per_lun = qdepth;
+	shost->max_id = 1;
+	shost->max_channel = 0;
+	shost->max_lun = iscsit->max_lun;
+	shost->max_cmd_len = iscsit->max_cmd_len;
+	shost->transportt = scsit;
+	shost->transportt->create_work_queue = 1;
+	shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
+	*hostno = shost->host_no;
+
+	session = iscsi_hostdata(shost->hostdata);
+	memset(session, 0, sizeof(struct iscsi_session));
 	session->host = shost;
 	session->state = ISCSI_STATE_FREE;
 	session->fast_abort = 1;
 	session->lu_reset_timeout = 15;
 	session->abort_timeout = 10;
-	session->scsi_cmds_max = scsi_cmds;
-	session->cmds_max = total_cmds;
+	session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
+	session->cmds_max = cmds_max;
 	session->queued_cmdsn = session->cmdsn = initial_cmdsn;
 	session->exp_cmdsn = initial_cmdsn + 1;
 	session->max_cmdsn = initial_cmdsn + 1;
 	session->max_r2t = 1;
 	session->tt = iscsit;
 	mutex_init(&session->eh_mutex);
-	spin_lock_init(&session->lock);
 
 	/* initialize SCSI PDU commands pool */
 	if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
 			    (void***)&session->cmds,
-			    cmd_task_size + sizeof(struct iscsi_task)))
+			    cmd_task_size + sizeof(struct iscsi_cmd_task)))
 		goto cmdpool_alloc_fail;
 
 	/* pre-format cmds pool with ITT */
 	for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
-		struct iscsi_task *task = session->cmds[cmd_i];
+		struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
 
 		if (cmd_task_size)
-			task->dd_data = &task[1];
-		task->itt = cmd_i;
-		INIT_LIST_HEAD(&task->running);
+			ctask->dd_data = &ctask[1];
+		ctask->itt = cmd_i;
+		INIT_LIST_HEAD(&ctask->running);
 	}
 
-	if (!try_module_get(iscsit->owner))
-		goto module_get_fail;
+	spin_lock_init(&session->lock);
+
+	/* initialize immediate command pool */
+	if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max,
+			   (void***)&session->mgmt_cmds,
+			   mgmt_task_size + sizeof(struct iscsi_mgmt_task)))
+		goto mgmtpool_alloc_fail;
+
+
+	/* pre-format immediate cmds pool with ITT */
+	for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) {
+		struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i];
+
+		if (mgmt_task_size)
+			mtask->dd_data = &mtask[1];
+		mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i;
+		INIT_LIST_HEAD(&mtask->running);
+	}
 
-	if (iscsi_add_session(cls_session, id))
+	if (scsi_add_host(shost, NULL))
+		goto add_host_fail;
+
+	if (!try_module_get(iscsit->owner))
 		goto cls_session_fail;
+
+	cls_session = iscsi_create_session(shost, iscsit, 0);
+	if (!cls_session)
+		goto module_put;
+	*(unsigned long*)shost->hostdata = (unsigned long)cls_session;
+
 	return cls_session;
 
-cls_session_fail:
+module_put:
 	module_put(iscsit->owner);
-module_get_fail:
+cls_session_fail:
+	scsi_remove_host(shost);
+add_host_fail:
+	iscsi_pool_free(&session->mgmtpool);
+mgmtpool_alloc_fail:
 	iscsi_pool_free(&session->cmdpool);
 cmdpool_alloc_fail:
-	iscsi_free_session(cls_session);
+	scsi_host_put(shost);
 	return NULL;
 }
 EXPORT_SYMBOL_GPL(iscsi_session_setup);
 
 /**
  * iscsi_session_teardown - destroy session, host, and cls_session
- * @cls_session: iscsi session
+ * shost: scsi host
  *
- * The driver must have called iscsi_remove_session before
- * calling this.
- */
+ * This can be used by software iscsi_transports that allocate
+ * a session per scsi host.
+ **/
 void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
 {
-	struct iscsi_session *session = cls_session->dd_data;
+	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
 	struct module *owner = cls_session->transport->owner;
 
+	iscsi_remove_session(cls_session);
+	scsi_remove_host(shost);
+
+	iscsi_pool_free(&session->mgmtpool);
 	iscsi_pool_free(&session->cmdpool);
 
 	kfree(session->password);
@@ -2076,10 +1838,12 @@
 	kfree(session->username);
 	kfree(session->username_in);
 	kfree(session->targetname);
+	kfree(session->netdev);
+	kfree(session->hwaddress);
 	kfree(session->initiatorname);
-	kfree(session->ifacename);
 
-	iscsi_destroy_session(cls_session);
+	iscsi_free_session(cls_session);
+	scsi_host_put(shost);
 	module_put(owner);
 }
 EXPORT_SYMBOL_GPL(iscsi_session_teardown);
@@ -2087,26 +1851,22 @@
 /**
  * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn
  * @cls_session: iscsi_cls_session
- * @dd_size: private driver data size
  * @conn_idx: cid
- */
+ **/
 struct iscsi_cls_conn *
-iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
-		 uint32_t conn_idx)
+iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
 {
-	struct iscsi_session *session = cls_session->dd_data;
+	struct iscsi_session *session = class_to_transport_session(cls_session);
 	struct iscsi_conn *conn;
 	struct iscsi_cls_conn *cls_conn;
 	char *data;
 
-	cls_conn = iscsi_create_conn(cls_session, sizeof(*conn) + dd_size,
-				     conn_idx);
+	cls_conn = iscsi_create_conn(cls_session, conn_idx);
 	if (!cls_conn)
 		return NULL;
 	conn = cls_conn->dd_data;
-	memset(conn, 0, sizeof(*conn) + dd_size);
+	memset(conn, 0, sizeof(*conn));
 
-	conn->dd_data = cls_conn->dd_data + sizeof(*conn);
 	conn->session = session;
 	conn->cls_conn = cls_conn;
 	conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
@@ -2125,30 +1885,30 @@
 	INIT_LIST_HEAD(&conn->requeue);
 	INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
 
-	/* allocate login_task used for the login/text sequences */
+	/* allocate login_mtask used for the login/text sequences */
 	spin_lock_bh(&session->lock);
-	if (!__kfifo_get(session->cmdpool.queue,
-                         (void*)&conn->login_task,
+	if (!__kfifo_get(session->mgmtpool.queue,
+                         (void*)&conn->login_mtask,
 			 sizeof(void*))) {
 		spin_unlock_bh(&session->lock);
-		goto login_task_alloc_fail;
+		goto login_mtask_alloc_fail;
 	}
 	spin_unlock_bh(&session->lock);
 
 	data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL);
 	if (!data)
-		goto login_task_data_alloc_fail;
-	conn->login_task->data = conn->data = data;
+		goto login_mtask_data_alloc_fail;
+	conn->login_mtask->data = conn->data = data;
 
 	init_timer(&conn->tmf_timer);
 	init_waitqueue_head(&conn->ehwait);
 
 	return cls_conn;
 
-login_task_data_alloc_fail:
-	__kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
+login_mtask_data_alloc_fail:
+	__kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
 		    sizeof(void*));
-login_task_alloc_fail:
+login_mtask_alloc_fail:
 	iscsi_destroy_conn(cls_conn);
 	return NULL;
 }
@@ -2208,7 +1968,7 @@
 	spin_lock_bh(&session->lock);
 	kfree(conn->data);
 	kfree(conn->persistent_address);
-	__kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
+	__kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
 		    sizeof(void*));
 	if (session->leadconn == conn)
 		session->leadconn = NULL;
@@ -2280,7 +2040,7 @@
 	}
 	spin_unlock_bh(&session->lock);
 
-	iscsi_unblock_session(session->cls_session);
+	iscsi_unblock_session(session_to_cls(session));
 	wake_up(&conn->ehwait);
 	return 0;
 }
@@ -2289,23 +2049,21 @@
 static void
 flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
 {
-	struct iscsi_task *task, *tmp;
+	struct iscsi_mgmt_task *mtask, *tmp;
 
 	/* handle pending */
-	list_for_each_entry_safe(task, tmp, &conn->mgmtqueue, running) {
-		debug_scsi("flushing pending mgmt task itt 0x%x\n", task->itt);
-		/* release ref from prep task */
-		__iscsi_put_task(task);
+	list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) {
+		debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt);
+		iscsi_free_mgmt_task(conn, mtask);
 	}
 
 	/* handle running */
-	list_for_each_entry_safe(task, tmp, &conn->mgmt_run_list, running) {
-		debug_scsi("flushing running mgmt task itt 0x%x\n", task->itt);
-		/* release ref from prep task */
-		__iscsi_put_task(task);
+	list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) {
+		debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt);
+		iscsi_free_mgmt_task(conn, mtask);
 	}
 
-	conn->task = NULL;
+	conn->mtask = NULL;
 }
 
 static void iscsi_start_session_recovery(struct iscsi_session *session,
@@ -2324,6 +2082,17 @@
 	}
 
 	/*
+	 * The LLD either freed/unset the lock on us, or userspace called
+	 * stop but did not create a proper connection (connection was never
+	 * bound or it was unbound then stop was called).
+	 */
+	if (!conn->recv_lock) {
+		spin_unlock_bh(&session->lock);
+		mutex_unlock(&session->eh_mutex);
+		return;
+	}
+
+	/*
 	 * When this is called for the in_login state, we only want to clean
 	 * up the login task and connection. We do not need to block and set
 	 * the recovery state again
@@ -2339,6 +2108,11 @@
 	spin_unlock_bh(&session->lock);
 
 	iscsi_suspend_tx(conn);
+
+	write_lock_bh(conn->recv_lock);
+	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
+	write_unlock_bh(conn->recv_lock);
+
 	/*
 	 * for connection level recovery we should not calculate
 	 * header digest. conn->hdr_size used for optimization
@@ -2351,7 +2125,7 @@
 		if (session->state == ISCSI_STATE_IN_RECOVERY &&
 		    old_stop_stage != STOP_CONN_RECOVER) {
 			debug_scsi("blocking session\n");
-			iscsi_block_session(session->cls_session);
+			iscsi_block_session(session_to_cls(session));
 		}
 	}
 
@@ -2386,7 +2160,7 @@
 int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
 		    struct iscsi_cls_conn *cls_conn, int is_leading)
 {
-	struct iscsi_session *session = cls_session->dd_data;
+	struct iscsi_session *session = class_to_transport_session(cls_session);
 	struct iscsi_conn *conn = cls_conn->dd_data;
 
 	spin_lock_bh(&session->lock);
@@ -2525,14 +2299,6 @@
 		if (!conn->persistent_address)
 			return -ENOMEM;
 		break;
-	case ISCSI_PARAM_IFACE_NAME:
-		if (!session->ifacename)
-			session->ifacename = kstrdup(buf, GFP_KERNEL);
-		break;
-	case ISCSI_PARAM_INITIATOR_NAME:
-		if (!session->initiatorname)
-			session->initiatorname = kstrdup(buf, GFP_KERNEL);
-		break;
 	default:
 		return -ENOSYS;
 	}
@@ -2544,7 +2310,8 @@
 int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
 			    enum iscsi_param param, char *buf)
 {
-	struct iscsi_session *session = cls_session->dd_data;
+	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
 	int len;
 
 	switch(param) {
@@ -2599,15 +2366,6 @@
 	case ISCSI_PARAM_PASSWORD_IN:
 		len = sprintf(buf, "%s\n", session->password_in);
 		break;
-	case ISCSI_PARAM_IFACE_NAME:
-		len = sprintf(buf, "%s\n", session->ifacename);
-		break;
-	case ISCSI_PARAM_INITIATOR_NAME:
-		if (!session->initiatorname)
-			len = sprintf(buf, "%s\n", "unknown");
-		else
-			len = sprintf(buf, "%s\n", session->initiatorname);
-		break;
 	default:
 		return -ENOSYS;
 	}
@@ -2667,35 +2425,29 @@
 int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
 			 char *buf)
 {
-	struct iscsi_host *ihost = shost_priv(shost);
+	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
 	int len;
 
 	switch (param) {
 	case ISCSI_HOST_PARAM_NETDEV_NAME:
-		if (!ihost->netdev)
+		if (!session->netdev)
 			len = sprintf(buf, "%s\n", "default");
 		else
-			len = sprintf(buf, "%s\n", ihost->netdev);
+			len = sprintf(buf, "%s\n", session->netdev);
 		break;
 	case ISCSI_HOST_PARAM_HWADDRESS:
-		if (!ihost->hwaddress)
+		if (!session->hwaddress)
 			len = sprintf(buf, "%s\n", "default");
 		else
-			len = sprintf(buf, "%s\n", ihost->hwaddress);
+			len = sprintf(buf, "%s\n", session->hwaddress);
 		break;
 	case ISCSI_HOST_PARAM_INITIATOR_NAME:
-		if (!ihost->initiatorname)
-			len = sprintf(buf, "%s\n", "unknown");
-		else
-			len = sprintf(buf, "%s\n", ihost->initiatorname);
-		break;
-	case ISCSI_HOST_PARAM_IPADDRESS:
-		if (!strlen(ihost->local_address))
+		if (!session->initiatorname)
 			len = sprintf(buf, "%s\n", "unknown");
 		else
-			len = sprintf(buf, "%s\n",
-				      ihost->local_address);
+			len = sprintf(buf, "%s\n", session->initiatorname);
 		break;
+
 	default:
 		return -ENOSYS;
 	}
@@ -2707,20 +2459,20 @@
 int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param,
 			 char *buf, int buflen)
 {
-	struct iscsi_host *ihost = shost_priv(shost);
+	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
 
 	switch (param) {
 	case ISCSI_HOST_PARAM_NETDEV_NAME:
-		if (!ihost->netdev)
-			ihost->netdev = kstrdup(buf, GFP_KERNEL);
+		if (!session->netdev)
+			session->netdev = kstrdup(buf, GFP_KERNEL);
 		break;
 	case ISCSI_HOST_PARAM_HWADDRESS:
-		if (!ihost->hwaddress)
-			ihost->hwaddress = kstrdup(buf, GFP_KERNEL);
+		if (!session->hwaddress)
+			session->hwaddress = kstrdup(buf, GFP_KERNEL);
 		break;
 	case ISCSI_HOST_PARAM_INITIATOR_NAME:
-		if (!ihost->initiatorname)
-			ihost->initiatorname = kstrdup(buf, GFP_KERNEL);
+		if (!session->initiatorname)
+			session->initiatorname = kstrdup(buf, GFP_KERNEL);
 		break;
 	default:
 		return -ENOSYS;
--- open-iscsi-2.0.870~rc3.orig/kernel/libiscsi.h
+++ open-iscsi-2.0.870~rc3/kernel/libiscsi.h
@@ -24,16 +24,13 @@
 #define LIBISCSI_H
 
 #include <linux/types.h>
-#include <linux/wait.h>
 #include <linux/mutex.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
-
 #include "iscsi_proto.h"
 #include "iscsi_if.h"
 
 struct scsi_transport_template;
-struct scsi_host_template;
 struct scsi_device;
 struct Scsi_Host;
 struct scsi_cmnd;
@@ -43,7 +40,6 @@
 struct iscsi_cls_conn;
 struct iscsi_session;
 struct iscsi_nopin;
-struct device;
 
 /* #define DEBUG_SCSI */
 #ifdef DEBUG_SCSI
@@ -53,7 +49,9 @@
 #endif
 
 #define ISCSI_DEF_XMIT_CMDS_MAX	128	/* must be power of 2 */
-#define ISCSI_MGMT_CMDS_MAX	15
+#define ISCSI_MGMT_CMDS_MAX	16	/* must be power of 2 */
+
+#define ISCSI_MGMT_ITT_OFFSET	0xa00
 
 #define ISCSI_DEF_CMD_PER_LUN		32
 #define ISCSI_MAX_CMD_PER_LUN		128
@@ -71,10 +69,7 @@
 /* Connection suspend "bit" */
 #define ISCSI_SUSPEND_BIT		1
 
-#define ISCSI_ITT_MASK			(0x1fff)
-#define ISCSI_TOTAL_CMDS_MAX		4096
-/* this must be a power of two greater than ISCSI_MGMT_CMDS_MAX */
-#define ISCSI_TOTAL_CMDS_MIN		16
+#define ISCSI_ITT_MASK			(0xfff)
 #define ISCSI_AGE_SHIFT			28
 #define ISCSI_AGE_MASK			(0xf << ISCSI_AGE_SHIFT)
 
@@ -87,6 +82,18 @@
 	ISCSI_DIGEST_SIZE = sizeof(__u32),
 };
 
+struct iscsi_mgmt_task {
+	/*
+	 * Becuae LLDs allocate their hdr differently, this is a pointer to
+	 * that storage. It must be setup at session creation time.
+	 */
+	struct iscsi_hdr	*hdr;
+	char			*data;		/* mgmt payload */
+	unsigned		data_count;	/* counts data to be sent */
+	uint32_t		itt;		/* this ITT */
+	void			*dd_data;	/* driver/transport data */
+	struct list_head	running;
+};
 
 enum {
 	ISCSI_TASK_COMPLETED,
@@ -94,7 +101,7 @@
 	ISCSI_TASK_RUNNING,
 };
 
-struct iscsi_task {
+struct iscsi_cmd_task {
 	/*
 	 * Because LLDs allocate their hdr differently, this is a pointer
 	 * and length to that storage. It must be setup at session
@@ -111,7 +118,6 @@
 	/* offset in unsolicited stream (bytes); */
 	unsigned		unsol_offset;
 	unsigned		data_count;	/* remaining Data-Out */
-	char			*data;		/* mgmt payload */
 	struct scsi_cmnd	*sc;		/* associated SCSI cmd*/
 	struct iscsi_conn	*conn;		/* used connection    */
 
@@ -122,9 +128,9 @@
 	void			*dd_data;	/* driver/transport data */
 };
 
-static inline void* iscsi_next_hdr(struct iscsi_task *task)
+static inline void* iscsi_next_hdr(struct iscsi_cmd_task *ctask)
 {
-	return (void*)task->hdr + task->hdr_len;
+	return (void*)ctask->hdr + ctask->hdr_len;
 }
 
 /* Connection's states */
@@ -140,6 +146,11 @@
 	void			*dd_data;	/* iscsi_transport data */
 	struct iscsi_session	*session;	/* parent session */
 	/*
+	 * LLDs should set this lock. It protects the transport recv
+	 * code
+	 */
+	rwlock_t		*recv_lock;
+	/*
 	 * conn_stop() flag: stop to recover, stop to terminate
 	 */
         int			stop_stage;
@@ -148,7 +159,7 @@
 	unsigned long		last_ping;
 	int			ping_timeout;
 	int			recv_timeout;
-	struct iscsi_task 	*ping_task;
+	struct iscsi_mgmt_task	*ping_mtask;
 
 	/* iSCSI connection-wide sequencing */
 	uint32_t		exp_statsn;
@@ -164,8 +175,9 @@
 	 * should always fit in this buffer
 	 */
 	char			*data;
-	struct iscsi_task 	*login_task;	/* mtask used for login/text */
-	struct iscsi_task	*task;		/* xmit task in progress */
+	struct iscsi_mgmt_task	*login_mtask;	/* mtask used for login/text */
+	struct iscsi_mgmt_task	*mtask;		/* xmit mtask in progress */
+	struct iscsi_cmd_task	*ctask;		/* xmit ctask in progress */
 
 	/* xmit */
 	struct list_head	mgmtqueue;	/* mgmt (control) xmit queue */
@@ -196,6 +208,9 @@
 	/* remote portal currently connected to */
 	int			portal_port;
 	char			portal_address[ISCSI_ADDRESS_BUF_LEN];
+	/* local address */
+	int			local_port;
+	char			local_address[ISCSI_ADDRESS_BUF_LEN];
 
 	/* MIB-statistics */
 	uint64_t		txdata_octets;
@@ -210,7 +225,6 @@
 
 	/* custom statistics */
 	uint32_t		eh_abort_cnt;
-	uint32_t		fmr_unalign_cnt;
 };
 
 struct iscsi_pool {
@@ -231,7 +245,6 @@
 };
 
 struct iscsi_session {
-	struct iscsi_cls_session *cls_session;
 	/*
 	 * Syncs up the scsi eh thread with the iscsi eh thread when sending
 	 * task management functions. This must be taken before the session
@@ -267,8 +280,10 @@
 	char			*password;
 	char			*password_in;
 	char			*targetname;
-	char			*ifacename;
 	char			*initiatorname;
+	/* hw address or netdev iscsi connection is bound to */
+	char			*hwaddress;
+	char			*netdev;
 	/* control data */
 	struct iscsi_transport	*tt;
 	struct Scsi_Host	*host;
@@ -282,20 +297,12 @@
 	int			state;		/* session state           */
 	int			age;		/* counts session re-opens */
 
-	int			scsi_cmds_max; 	/* max scsi commands */
 	int			cmds_max;	/* size of cmds array */
-	struct iscsi_task	**cmds;		/* Original Cmds arr */
+	struct iscsi_cmd_task	**cmds;		/* Original Cmds arr */
 	struct iscsi_pool	cmdpool;	/* PDU's pool */
-};
-
-struct iscsi_host {
-	char			*initiatorname;
-	/* hw address or netdev iscsi connection is bound to */
-	char			*hwaddress;
-	char			*netdev;
-	/* local address */
-	int			local_port;
-	char			local_address[ISCSI_ADDRESS_BUF_LEN];
+	int			mgmtpool_max;	/* size of mgmt array */
+	struct iscsi_mgmt_task	**mgmt_cmds;	/* Original mgmt arr */
+	struct iscsi_pool	mgmtpool;	/* Mgmt PDU's pool */
 };
 
 /*
@@ -308,44 +315,42 @@
 extern int iscsi_queuecommand(struct scsi_cmnd *sc,
 			      void (*done)(struct scsi_cmnd *));
 
+
 /*
  * iSCSI host helpers.
  */
-#define iscsi_host_priv(_shost) \
-	(shost_priv(_shost) + sizeof(struct iscsi_host))
-
 extern int iscsi_host_set_param(struct Scsi_Host *shost,
 				enum iscsi_host_param param, char *buf,
 				int buflen);
 extern int iscsi_host_get_param(struct Scsi_Host *shost,
 				enum iscsi_host_param param, char *buf);
-extern int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev);
-extern struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
-					  int dd_data_size, uint16_t qdepth);
-extern void iscsi_host_remove(struct Scsi_Host *shost);
-extern void iscsi_host_free(struct Scsi_Host *shost);
 
 /*
  * session management
  */
 extern struct iscsi_cls_session *
-iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost,
-		    uint16_t, int, uint32_t, unsigned int);
+iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *,
+		    uint16_t, uint16_t, int, int, uint32_t, uint32_t *);
 extern void iscsi_session_teardown(struct iscsi_cls_session *);
+extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *);
 extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
 extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
 			   enum iscsi_param param, char *buf, int buflen);
 extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
 				   enum iscsi_param param, char *buf);
 
+#define session_to_cls(_sess) \
+	hostdata_session(_sess->host->hostdata)
+
 #define iscsi_session_printk(prefix, _sess, fmt, a...)	\
-	iscsi_cls_session_printk(prefix, _sess->cls_session, fmt, ##a)
+	iscsi_cls_session_printk(prefix,		\
+		(struct iscsi_cls_session *)session_to_cls(_sess), fmt, ##a)
 
 /*
  * connection management
  */
 extern struct iscsi_cls_conn *iscsi_conn_setup(struct iscsi_cls_session *,
-					       int, uint32_t);
+					       uint32_t);
 extern void iscsi_conn_teardown(struct iscsi_cls_conn *);
 extern int iscsi_conn_start(struct iscsi_cls_conn *);
 extern void iscsi_conn_stop(struct iscsi_cls_conn *, int);
@@ -354,29 +359,25 @@
 extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err);
 extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
 				enum iscsi_param param, char *buf);
-extern void iscsi_suspend_tx(struct iscsi_conn *conn);
 
 #define iscsi_conn_printk(prefix, _c, fmt, a...) \
-	iscsi_cls_conn_printk(prefix, ((struct iscsi_conn *)_c)->cls_conn, \
-			      fmt, ##a)
+	iscsi_cls_conn_printk(prefix, _c->cls_conn, fmt, ##a)
 
 /*
  * pdu and task processing
  */
 extern void iscsi_update_cmdsn(struct iscsi_session *, struct iscsi_nopin *);
-extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_task *,
+extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *,
 					struct iscsi_data *hdr);
 extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *,
 				char *, uint32_t);
 extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
 			      char *, int);
-extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
-				char *, int);
-extern int iscsi_verify_itt(struct iscsi_conn *, itt_t);
-extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t);
-extern void iscsi_requeue_task(struct iscsi_task *task);
-extern void iscsi_put_task(struct iscsi_task *task);
-extern void __iscsi_get_task(struct iscsi_task *task);
+extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *,
+			    uint32_t *);
+extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask);
+extern void iscsi_free_mgmt_task(struct iscsi_conn *conn,
+				 struct iscsi_mgmt_task *mtask);
 
 /*
  * generic helpers
--- open-iscsi-2.0.870~rc3.orig/kernel/scsi_transport_iscsi.c
+++ open-iscsi-2.0.870~rc3/kernel/scsi_transport_iscsi.c
@@ -30,24 +30,23 @@
 #include "scsi_transport_iscsi.h"
 #include "iscsi_if.h"
 
-#define ISCSI_SESSION_ATTRS 21
+#define ISCSI_SESSION_ATTRS 19
 #define ISCSI_CONN_ATTRS 13
 #define ISCSI_HOST_ATTRS 4
-
-#define ISCSI_TRANSPORT_VERSION "2.0-870"
+#define ISCSI_TRANSPORT_VERSION "2.0-869"
 
 struct iscsi_internal {
 	int daemon_pid;
 	struct scsi_transport_template t;
 	struct iscsi_transport *iscsi_transport;
 	struct list_head list;
-	struct device dev;
+	struct class_device cdev;
 
-	struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
+	struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
 	struct transport_container conn_cont;
-	struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
+	struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
 	struct transport_container session_cont;
-	struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
+	struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
 };
 
 static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
@@ -64,12 +63,12 @@
 #define to_iscsi_internal(tmpl) \
 	container_of(tmpl, struct iscsi_internal, t)
 
-#define dev_to_iscsi_internal(_dev) \
-	container_of(_dev, struct iscsi_internal, dev)
+#define cdev_to_iscsi_internal(_cdev) \
+	container_of(_cdev, struct iscsi_internal, cdev)
 
-static void iscsi_transport_release(struct device *dev)
+static void iscsi_transport_release(struct class_device *cdev)
 {
-	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
+	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
 	kfree(priv);
 }
 
@@ -79,33 +78,37 @@
  */
 static struct class iscsi_transport_class = {
 	.name = "iscsi_transport",
-	.dev_release = iscsi_transport_release,
+	.release = iscsi_transport_release,
 };
 
 static ssize_t
-show_transport_handle(struct device *dev, struct device_attribute *attr,
-		      char *buf)
+show_transport_handle(struct class_device *cdev, char *buf)
 {
-	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
+	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
 	return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
 }
-static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
+static CLASS_DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
 
 #define show_transport_attr(name, format)				\
 static ssize_t								\
-show_transport_##name(struct device *dev, 				\
-		      struct device_attribute *attr,char *buf)		\
+show_transport_##name(struct class_device *cdev, char *buf)		\
 {									\
-	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);	\
+	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);	\
 	return sprintf(buf, format"\n", priv->iscsi_transport->name);	\
 }									\
-static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
 
 show_transport_attr(caps, "0x%x");
+show_transport_attr(max_lun, "%d");
+show_transport_attr(max_conn, "%d");
+show_transport_attr(max_cmd_len, "%d");
 
 static struct attribute *iscsi_transport_attrs[] = {
-	&dev_attr_handle.attr,
-	&dev_attr_caps.attr,
+	&class_device_attr_handle.attr,
+	&class_device_attr_caps.attr,
+	&class_device_attr_max_lun.attr,
+	&class_device_attr_max_conn.attr,
+	&class_device_attr_max_cmd_len.attr,
 	NULL,
 };
 
@@ -113,143 +116,21 @@
 	.attrs = iscsi_transport_attrs,
 };
 
-/*
- * iSCSI endpoint attrs
- */
-#define iscsi_dev_to_endpoint(_dev) \
-	container_of(_dev, struct iscsi_endpoint, dev)
-
-#define ISCSI_ATTR(_prefix,_name,_mode,_show,_store)	\
-struct device_attribute dev_attr_##_prefix##_##_name =	\
-        __ATTR(_name,_mode,_show,_store)
-
-static void iscsi_endpoint_release(struct device *dev)
-{
-	struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
-	kfree(ep);
-}
-
-static struct class iscsi_endpoint_class = {
-	.name = "iscsi_endpoint",
-	.dev_release = iscsi_endpoint_release,
-};
-
-static ssize_t
-show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
-	return sprintf(buf, "%llu\n", (unsigned long long) ep->id);
-}
-static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL);
-
-static struct attribute *iscsi_endpoint_attrs[] = {
-	&dev_attr_ep_handle.attr,
-	NULL,
-};
-
-static struct attribute_group iscsi_endpoint_group = {
-	.attrs = iscsi_endpoint_attrs,
-};
-
-#define ISCSI_MAX_EPID -1
-
-static int iscsi_match_epid(struct device *dev, void *data)
-{
-	struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
-	uint64_t *epid = (uint64_t *) data;
-
-	return *epid == ep->id;
-}
-
-struct iscsi_endpoint *
-iscsi_create_endpoint(int dd_size)
-{
-	struct device *dev;
-	struct iscsi_endpoint *ep;
-	uint64_t id;
-	int err;
-
-	for (id = 1; id < ISCSI_MAX_EPID; id++) {
-		dev = class_find_device(&iscsi_endpoint_class, NULL, &id,
-					iscsi_match_epid);
-		if (!dev)
-			break;
-	}
-	if (id == ISCSI_MAX_EPID) {
-		printk(KERN_ERR "Too many connections. Max supported %u\n",
-		       ISCSI_MAX_EPID - 1);
-		return NULL;
-	}
-
-	ep = kzalloc(sizeof(*ep) + dd_size, GFP_KERNEL);
-	if (!ep)
-		return NULL;
-
-	ep->id = id;
-	ep->dev.class = &iscsi_endpoint_class;
-	snprintf(ep->dev.bus_id, BUS_ID_SIZE, "ep-%llu",
-		 (unsigned long long) id);
-	err = device_register(&ep->dev);
-        if (err)
-                goto free_ep;
-
-	err = sysfs_create_group(&ep->dev.kobj, &iscsi_endpoint_group);
-	if (err)
-		goto unregister_dev;
-
-	if (dd_size)
-		ep->dd_data = &ep[1];
-	return ep;
-
-unregister_dev:
-	device_unregister(&ep->dev);
-	return NULL;
-
-free_ep:
-	kfree(ep);
-	return NULL;
-}
-EXPORT_SYMBOL_GPL(iscsi_create_endpoint);
-
-void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
-{
-	sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group);
-	device_unregister(&ep->dev);
-}
-EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint);
-
-struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
-{
-	struct iscsi_endpoint *ep;
-	struct device *dev;
 
-	dev = class_find_device(&iscsi_endpoint_class, NULL, &handle,
-				iscsi_match_epid);
-	if (!dev)
-		return NULL;
-
-	ep = iscsi_dev_to_endpoint(dev);
-	/*
-	 * we can drop this now because the interface will prevent
-	 * removals and lookups from racing.
-	 */
-	put_device(dev);
-	return ep;
-}
-EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
 
 static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
-			    struct device *cdev)
+			    struct class_device *cdev)
 {
 	struct Scsi_Host *shost = dev_to_shost(dev);
-	struct iscsi_cls_host *ihost = shost->shost_data;
+	struct iscsi_host *ihost = shost->shost_data;
 
 	memset(ihost, 0, sizeof(*ihost));
-	atomic_set(&ihost->nr_scans, 0);
+	INIT_LIST_HEAD(&ihost->sessions);
 	mutex_init(&ihost->mutex);
+	atomic_set(&ihost->nr_scans, 0);
 
-	snprintf(ihost->scan_workq_name, sizeof(ihost->scan_workq_name),
-		 "iscsi_scan_%d", shost->host_no);
+	snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d",
+		shost->host_no);
 	ihost->scan_workq = create_singlethread_workqueue(
 						ihost->scan_workq_name);
 	if (!ihost->scan_workq)
@@ -258,10 +139,10 @@
 }
 
 static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
-			     struct device *cdev)
+			     struct class_device *cdev)
 {
 	struct Scsi_Host *shost = dev_to_shost(dev);
-	struct iscsi_cls_host *ihost = shost->shost_data;
+	struct iscsi_host *ihost = shost->shost_data;
 
 	destroy_workqueue(ihost->scan_workq);
 	return 0;
@@ -404,24 +285,6 @@
 	return dev->release == iscsi_session_release;
 }
 
-static int iscsi_iter_session_fn(struct device *dev, void *data)
-{
-	void (* fn) (struct iscsi_cls_session *) = data;
-
-	if (!iscsi_is_session_dev(dev))
-		return 0;
-	fn(iscsi_dev_to_session(dev));
-	return 0;
-}
-
-void iscsi_host_for_each_session(struct Scsi_Host *shost,
-				 void (*fn)(struct iscsi_cls_session *))
-{
-	device_for_each_child(&shost->shost_gendev, fn,
-			      iscsi_iter_session_fn);
-}
-EXPORT_SYMBOL_GPL(iscsi_host_for_each_session);
-
 /**
  * iscsi_scan_finished - helper to report when running scans are done
  * @shost: scsi host
@@ -432,7 +295,7 @@
  */
 int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
-	struct iscsi_cls_host *ihost = shost->shost_data;
+	struct iscsi_host *ihost = shost->shost_data;
 	/*
 	 * qla4xxx will have kicked off some session unblocks before calling
 	 * scsi_scan_host, so just wait for them to complete.
@@ -441,61 +304,22 @@
 }
 EXPORT_SYMBOL_GPL(iscsi_scan_finished);
 
-struct iscsi_scan_data {
-	unsigned int channel;
-	unsigned int id;
-	unsigned int lun;
-};
-
-static int iscsi_user_scan_session(struct device *dev, void *data)
+static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
+			   uint id, uint lun)
 {
-	struct iscsi_scan_data *scan_data = data;
+	struct iscsi_host *ihost = shost->shost_data;
 	struct iscsi_cls_session *session;
-	struct Scsi_Host *shost;
-	struct iscsi_cls_host *ihost;
-	unsigned long flags;
-	unsigned int id;
-
-	if (!iscsi_is_session_dev(dev))
-		return 0;
-
-	session = iscsi_dev_to_session(dev);
-	shost = iscsi_session_to_shost(session);
-	ihost = shost->shost_data;
 
 	mutex_lock(&ihost->mutex);
-	spin_lock_irqsave(&session->lock, flags);
-	if (session->state != ISCSI_SESSION_LOGGED_IN) {
-		spin_unlock_irqrestore(&session->lock, flags);
-		mutex_unlock(&ihost->mutex);
-		return 0;
-	}
-	id = session->target_id;
-	spin_unlock_irqrestore(&session->lock, flags);
-
-	if (id != ISCSI_MAX_TARGET) {
-		if ((scan_data->channel == SCAN_WILD_CARD ||
-		     scan_data->channel == 0) &&
-		    (scan_data->id == SCAN_WILD_CARD ||
-		     scan_data->id == id))
-			scsi_scan_target(&session->dev, 0, id,
-					 scan_data->lun, 1);
+	list_for_each_entry(session, &ihost->sessions, host_list) {
+		if ((channel == SCAN_WILD_CARD || channel == 0) &&
+		    (id == SCAN_WILD_CARD || id == session->target_id))
+			scsi_scan_target(&session->dev, 0,
+					 session->target_id, lun, 1);
 	}
 	mutex_unlock(&ihost->mutex);
-	return 0;
-}
-
-static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
-			   uint id, uint lun)
-{
-	struct iscsi_scan_data scan_data;
-
-	scan_data.channel = channel;
-	scan_data.id = id;
-	scan_data.lun = lun;
 
-	return device_for_each_child(&shost->shost_gendev, &scan_data,
-				     iscsi_user_scan_session);
+	return 0;
 }
 
 static void iscsi_scan_session(struct work_struct *work)
@@ -503,14 +327,19 @@
 	struct iscsi_cls_session *session =
 			container_of(work, struct iscsi_cls_session, scan_work);
 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
-	struct iscsi_cls_host *ihost = shost->shost_data;
-	struct iscsi_scan_data scan_data;
+	struct iscsi_host *ihost = shost->shost_data;
+	unsigned long flags;
 
-	scan_data.channel = 0;
-	scan_data.id = SCAN_WILD_CARD;
-	scan_data.lun = SCAN_WILD_CARD;
+	spin_lock_irqsave(&session->lock, flags);
+	if (session->state != ISCSI_SESSION_LOGGED_IN) {
+		spin_unlock_irqrestore(&session->lock, flags);
+		goto done;
+	}
+	spin_unlock_irqrestore(&session->lock, flags);
 
-	iscsi_user_scan_session(&session->dev, &scan_data);
+	scsi_scan_target(&session->dev, 0, session->target_id,
+			 SCAN_WILD_CARD, 1);
+done:
 	atomic_dec(&ihost->nr_scans);
 }
 
@@ -550,7 +379,7 @@
 			container_of(work, struct iscsi_cls_session,
 				     unblock_work);
 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
-	struct iscsi_cls_host *ihost = shost->shost_data;
+	struct iscsi_host *ihost = shost->shost_data;
 	unsigned long flags;
 
 	/*
@@ -618,19 +447,15 @@
 			container_of(work, struct iscsi_cls_session,
 				     unbind_work);
 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
-	struct iscsi_cls_host *ihost = shost->shost_data;
-	unsigned long flags;
+	struct iscsi_host *ihost = shost->shost_data;
 
 	/* Prevent new scans and make sure scanning is not in progress */
 	mutex_lock(&ihost->mutex);
-	spin_lock_irqsave(&session->lock, flags);
-	if (session->target_id == ISCSI_MAX_TARGET) {
-		spin_unlock_irqrestore(&session->lock, flags);
+	if (list_empty(&session->host_list)) {
 		mutex_unlock(&ihost->mutex);
 		return;
 	}
-	session->target_id = ISCSI_MAX_TARGET;
-	spin_unlock_irqrestore(&session->lock, flags);
+	list_del_init(&session->host_list);
 	mutex_unlock(&ihost->mutex);
 
 	scsi_remove_target(&session->dev);
@@ -640,18 +465,18 @@
 static int iscsi_unbind_session(struct iscsi_cls_session *session)
 {
 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
-	struct iscsi_cls_host *ihost = shost->shost_data;
+	struct iscsi_host *ihost = shost->shost_data;
 
 	return queue_work(ihost->scan_workq, &session->unbind_work);
 }
 
 struct iscsi_cls_session *
-iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
-		    int dd_size)
+iscsi_alloc_session(struct Scsi_Host *shost,
+		    struct iscsi_transport *transport)
 {
 	struct iscsi_cls_session *session;
 
-	session = kzalloc(sizeof(*session) + dd_size,
+	session = kzalloc(sizeof(*session) + transport->sessiondata_size,
 			  GFP_KERNEL);
 	if (!session)
 		return NULL;
@@ -660,6 +485,7 @@
 	session->recovery_tmo = 120;
 	session->state = ISCSI_SESSION_FREE;
 	INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
+	INIT_LIST_HEAD(&session->host_list);
 	INIT_LIST_HEAD(&session->sess_list);
 	INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
 	INIT_WORK(&session->block_work, __iscsi_block_session);
@@ -672,57 +498,22 @@
 	session->dev.parent = &shost->shost_gendev;
 	session->dev.release = iscsi_session_release;
 	device_initialize(&session->dev);
-	if (dd_size)
+	if (transport->sessiondata_size)
 		session->dd_data = &session[1];
 	return session;
 }
 EXPORT_SYMBOL_GPL(iscsi_alloc_session);
 
-static int iscsi_get_next_target_id(struct device *dev, void *data)
-{
-	struct iscsi_cls_session *session;
-	unsigned long flags;
-	int err = 0;
-
-	if (!iscsi_is_session_dev(dev))
-		return 0;
-
-	session = iscsi_dev_to_session(dev);
-	spin_lock_irqsave(&session->lock, flags);
-	if (*((unsigned int *) data) == session->target_id)
-		err = -EEXIST;
-	spin_unlock_irqrestore(&session->lock, flags);
-	return err;
-}
-
 int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
 {
 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
-	struct iscsi_cls_host *ihost;
+	struct iscsi_host *ihost;
 	unsigned long flags;
-	unsigned int id = target_id;
 	int err;
 
 	ihost = shost->shost_data;
 	session->sid = atomic_add_return(1, &iscsi_session_nr);
-
-	if (id == ISCSI_MAX_TARGET) {
-		for (id = 0; id < ISCSI_MAX_TARGET; id++) {
-			err = device_for_each_child(&shost->shost_gendev, &id,
-						    iscsi_get_next_target_id);
-			if (!err)
-				break;
-		}
-
-		if (id == ISCSI_MAX_TARGET) {
-			iscsi_cls_session_printk(KERN_ERR, session,
-						 "Too many iscsi targets. Max "
-						 "number of targets is %d.\n",
-						 ISCSI_MAX_TARGET - 1);
-			goto release_host;
-		}
-	}
-	session->target_id = id;
+	session->target_id = target_id;
 
 	snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
 		 session->sid);
@@ -738,6 +529,10 @@
 	list_add(&session->sess_list, &sesslist);
 	spin_unlock_irqrestore(&sesslock, flags);
 
+	mutex_lock(&ihost->mutex);
+	list_add(&session->host_list, &ihost->sessions);
+	mutex_unlock(&ihost->mutex);
+
 	iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
 	return 0;
 
@@ -751,18 +546,18 @@
  * iscsi_create_session - create iscsi class session
  * @shost: scsi host
  * @transport: iscsi transport
- * @dd_size: private driver data size
  * @target_id: which target
  *
  * This can be called from a LLD or iscsi_transport.
  */
 struct iscsi_cls_session *
-iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
-		     int dd_size, unsigned int target_id)
+iscsi_create_session(struct Scsi_Host *shost,
+		     struct iscsi_transport *transport,
+		     unsigned int target_id)
 {
 	struct iscsi_cls_session *session;
 
-	session = iscsi_alloc_session(shost, transport, dd_size);
+	session = iscsi_alloc_session(shost, transport);
 	if (!session)
 		return NULL;
 
@@ -798,7 +593,7 @@
 void iscsi_remove_session(struct iscsi_cls_session *session)
 {
 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
-	struct iscsi_cls_host *ihost = shost->shost_data;
+	struct iscsi_host *ihost = shost->shost_data;
 	unsigned long flags;
 	int err;
 
@@ -864,7 +659,6 @@
 /**
  * iscsi_create_conn - create iscsi class connection
  * @session: iscsi cls session
- * @dd_size: private driver data size
  * @cid: connection id
  *
  * This can be called from a LLD or iscsi_transport. The connection
@@ -877,17 +671,18 @@
  * non-zero.
  */
 struct iscsi_cls_conn *
-iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
+iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
 {
 	struct iscsi_transport *transport = session->transport;
 	struct iscsi_cls_conn *conn;
 	unsigned long flags;
 	int err;
 
-	conn = kzalloc(sizeof(*conn) + dd_size, GFP_KERNEL);
+	conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL);
 	if (!conn)
 		return NULL;
-	if (dd_size)
+
+	if (transport->conndata_size)
 		conn->dd_data = &conn[1];
 
 	INIT_LIST_HEAD(&conn->conn_list);
@@ -1220,20 +1015,21 @@
 EXPORT_SYMBOL_GPL(iscsi_session_event);
 
 static int
-iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep,
-			struct iscsi_uevent *ev, uint32_t initial_cmdsn,
-			uint16_t cmds_max, uint16_t queue_depth)
+iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
 {
 	struct iscsi_transport *transport = priv->iscsi_transport;
 	struct iscsi_cls_session *session;
-	uint32_t host_no;
+	uint32_t hostno;
 
-	session = transport->create_session(ep, cmds_max, queue_depth,
-					    initial_cmdsn, &host_no);
+	session = transport->create_session(transport, &priv->t,
+					    ev->u.c_session.cmds_max,
+					    ev->u.c_session.queue_depth,
+					    ev->u.c_session.initial_cmdsn,
+					    &hostno);
 	if (!session)
 		return -ENOMEM;
 
-	ev->r.c_session_ret.host_no = host_no;
+	ev->r.c_session_ret.host_no = hostno;
 	ev->r.c_session_ret.sid = session->sid;
 	return 0;
 }
@@ -1308,7 +1104,6 @@
 iscsi_if_transport_ep(struct iscsi_transport *transport,
 		      struct iscsi_uevent *ev, int msg_type)
 {
-	struct iscsi_endpoint *ep;
 	struct sockaddr *dst_addr;
 	int rc = 0;
 
@@ -1318,33 +1113,22 @@
 			return -EINVAL;
 
 		dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
-		ep = transport->ep_connect(dst_addr,
-					   ev->u.ep_connect.non_blocking);
-		if (IS_ERR(ep))
-			return PTR_ERR(ep);
-
-		ev->r.ep_connect_ret.handle = ep->id;
+		rc = transport->ep_connect(dst_addr,
+					   ev->u.ep_connect.non_blocking,
+					   &ev->r.ep_connect_ret.handle);
 		break;
 	case ISCSI_UEVENT_TRANSPORT_EP_POLL:
 		if (!transport->ep_poll)
 			return -EINVAL;
 
-		ep = iscsi_lookup_endpoint(ev->u.ep_poll.ep_handle);
-		if (!ep)
-			return -EINVAL;
-
-		ev->r.retcode = transport->ep_poll(ep,
+		ev->r.retcode = transport->ep_poll(ev->u.ep_poll.ep_handle,
 						   ev->u.ep_poll.timeout_ms);
 		break;
 	case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
 		if (!transport->ep_disconnect)
 			return -EINVAL;
 
-		ep = iscsi_lookup_endpoint(ev->u.ep_disconnect.ep_handle);
-		if (!ep)
-			return -EINVAL;
-
-		transport->ep_disconnect(ep);
+		transport->ep_disconnect(ev->u.ep_disconnect.ep_handle);
 		break;
 	}
 	return rc;
@@ -1409,7 +1193,6 @@
 	struct iscsi_internal *priv;
 	struct iscsi_cls_session *session;
 	struct iscsi_cls_conn *conn;
-	struct iscsi_endpoint *ep = NULL;
 
 	priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
 	if (!priv)
@@ -1423,22 +1206,7 @@
 
 	switch (nlh->nlmsg_type) {
 	case ISCSI_UEVENT_CREATE_SESSION:
-		err = iscsi_if_create_session(priv, ep, ev,
-					      ev->u.c_session.initial_cmdsn,
-					      ev->u.c_session.cmds_max,
-					      ev->u.c_session.queue_depth);
-		break;
-	case ISCSI_UEVENT_CREATE_BOUND_SESSION:
-		ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
-		if (!ep) {
-			err = -EINVAL;
-			break;
-		}
-
-		err = iscsi_if_create_session(priv, ep, ev,
-					ev->u.c_bound_session.initial_cmdsn,
-					ev->u.c_bound_session.cmds_max,
-					ev->u.c_bound_session.queue_depth);
+		err = iscsi_if_create_session(priv, ev);
 		break;
 	case ISCSI_UEVENT_DESTROY_SESSION:
 		session = iscsi_session_lookup(ev->u.d_session.sid);
@@ -1569,8 +1337,11 @@
 	mutex_unlock(&rx_queue_mutex);
 }
 
+#define iscsi_cdev_to_conn(_cdev) \
+	iscsi_dev_to_conn(_cdev->dev)
+
 #define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store)		\
-struct device_attribute dev_attr_##_prefix##_##_name =	\
+struct class_device_attribute class_device_attr_##_prefix##_##_name =	\
 	__ATTR(_name,_mode,_show,_store)
 
 /*
@@ -1578,10 +1349,9 @@
  */
 #define iscsi_conn_attr_show(param)					\
 static ssize_t								\
-show_conn_param_##param(struct device *dev, 				\
-			struct device_attribute *attr, char *buf)	\
+show_conn_param_##param(struct class_device *cdev, char *buf)		\
 {									\
-	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent);	\
+	struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev);		\
 	struct iscsi_transport *t = conn->transport;			\
 	return t->get_conn_param(conn, param, buf);			\
 }
@@ -1605,16 +1375,17 @@
 iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
 iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
 
+#define iscsi_cdev_to_session(_cdev) \
+	iscsi_dev_to_session(_cdev->dev)
+
 /*
  * iSCSI session attrs
  */
 #define iscsi_session_attr_show(param, perm)				\
 static ssize_t								\
-show_session_param_##param(struct device *dev,				\
-			   struct device_attribute *attr, char *buf)	\
+show_session_param_##param(struct class_device *cdev, char *buf)	\
 {									\
-	struct iscsi_cls_session *session = 				\
-		iscsi_dev_to_session(dev->parent);			\
+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
 	struct iscsi_transport *t = session->transport;			\
 									\
 	if (perm && !capable(CAP_SYS_ADMIN))				\
@@ -1644,14 +1415,11 @@
 iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
 iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
 iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
-iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
-iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
 
 static ssize_t
-show_priv_session_state(struct device *dev, struct device_attribute *attr,
-			char *buf)
+show_priv_session_state(struct class_device *cdev, char *buf)
 {
-	struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);
 	return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
 }
 static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
@@ -1659,11 +1427,9 @@
 
 #define iscsi_priv_session_attr_show(field, format)			\
 static ssize_t								\
-show_priv_session_##field(struct device *dev, 				\
-			  struct device_attribute *attr, char *buf)	\
+show_priv_session_##field(struct class_device *cdev, char *buf)		\
 {									\
-	struct iscsi_cls_session *session = 				\
-			iscsi_dev_to_session(dev->parent);		\
+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\
 	return sprintf(buf, format"\n", session->field);		\
 }
 
@@ -1678,10 +1444,9 @@
  */
 #define iscsi_host_attr_show(param)					\
 static ssize_t								\
-show_host_param_##param(struct device *dev, 				\
-			struct device_attribute *attr, char *buf)	\
+show_host_param_##param(struct class_device *cdev, char *buf)		\
 {									\
-	struct Scsi_Host *shost = transport_class_to_shost(dev);	\
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);	\
 	struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
 	return priv->iscsi_transport->get_host_param(shost, param, buf); \
 }
@@ -1698,7 +1463,7 @@
 
 #define SETUP_PRIV_SESSION_RD_ATTR(field)				\
 do {									\
-	priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
+	priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
 	count++;							\
 } while (0)
 
@@ -1706,7 +1471,7 @@
 #define SETUP_SESSION_RD_ATTR(field, param_flag)			\
 do {									\
 	if (tt->param_mask & param_flag) {				\
-		priv->session_attrs[count] = &dev_attr_sess_##field; \
+		priv->session_attrs[count] = &class_device_attr_sess_##field; \
 		count++;						\
 	}								\
 } while (0)
@@ -1714,7 +1479,7 @@
 #define SETUP_CONN_RD_ATTR(field, param_flag)				\
 do {									\
 	if (tt->param_mask & param_flag) {				\
-		priv->conn_attrs[count] = &dev_attr_conn_##field; \
+		priv->conn_attrs[count] = &class_device_attr_conn_##field; \
 		count++;						\
 	}								\
 } while (0)
@@ -1722,7 +1487,7 @@
 #define SETUP_HOST_RD_ATTR(field, param_flag)				\
 do {									\
 	if (tt->host_param_mask & param_flag) {				\
-		priv->host_attrs[count] = &dev_attr_host_##field; \
+		priv->host_attrs[count] = &class_device_attr_host_##field; \
 		count++;						\
 	}								\
 } while (0)
@@ -1812,24 +1577,22 @@
 	priv->daemon_pid = -1;
 	priv->iscsi_transport = tt;
 	priv->t.user_scan = iscsi_user_scan;
-	if (!(tt->caps & CAP_DATA_PATH_OFFLOAD))
-		priv->t.create_work_queue = 1;
 
-	priv->dev.class = &iscsi_transport_class;
-	snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name);
-	err = device_register(&priv->dev);
+	priv->cdev.class = &iscsi_transport_class;
+	snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
+	err = class_device_register(&priv->cdev);
 	if (err)
 		goto free_priv;
 
-	err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
+	err = sysfs_create_group(&priv->cdev.kobj, &iscsi_transport_group);
 	if (err)
-		goto unregister_dev;
+		goto unregister_cdev;
 
 	/* host parameters */
 	priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
 	priv->t.host_attrs.ac.class = &iscsi_host_class.class;
 	priv->t.host_attrs.ac.match = iscsi_host_match;
-	priv->t.host_size = sizeof(struct iscsi_cls_host);
+	priv->t.host_size = sizeof(struct iscsi_host);
 	transport_container_register(&priv->t.host_attrs);
 
 	SETUP_HOST_RD_ATTR(netdev, ISCSI_HOST_NETDEV_NAME);
@@ -1887,8 +1650,6 @@
 	SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT);
 	SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO);
 	SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO);
-	SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME);
-	SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME);
 	SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
 	SETUP_PRIV_SESSION_RD_ATTR(state);
 
@@ -1902,9 +1663,8 @@
 	printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
 	return &priv->t;
 
-unregister_dev:
-	device_unregister(&priv->dev);
-	return NULL;
+unregister_cdev:
+	class_device_unregister(&priv->cdev);
 free_priv:
 	kfree(priv);
 	return NULL;
@@ -1931,8 +1691,8 @@
 	transport_container_unregister(&priv->session_cont);
 	transport_container_unregister(&priv->t.host_attrs);
 
-	sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
-	device_unregister(&priv->dev);
+	sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
+	class_device_unregister(&priv->cdev);
 	mutex_unlock(&rx_queue_mutex);
 
 	return 0;
@@ -1952,13 +1712,9 @@
 	if (err)
 		return err;
 
-	err = class_register(&iscsi_endpoint_class);
-	if (err)
-		goto unregister_transport_class;
-
 	err = transport_class_register(&iscsi_host_class);
 	if (err)
-		goto unregister_endpoint_class;
+		goto unregister_transport_class;
 
 	err = transport_class_register(&iscsi_connection_class);
 	if (err)
@@ -1968,8 +1724,8 @@
 	if (err)
 		goto unregister_conn_class;
 
-	nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx,
-				    NULL, THIS_MODULE);
+	nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, NULL,
+			THIS_MODULE);
 	if (!nls) {
 		err = -ENOBUFS;
 		goto unregister_session_class;
@@ -1989,8 +1745,6 @@
 	transport_class_unregister(&iscsi_connection_class);
 unregister_host_class:
 	transport_class_unregister(&iscsi_host_class);
-unregister_endpoint_class:
-	class_unregister(&iscsi_endpoint_class);
 unregister_transport_class:
 	class_unregister(&iscsi_transport_class);
 	return err;
@@ -2003,7 +1757,6 @@
 	transport_class_unregister(&iscsi_connection_class);
 	transport_class_unregister(&iscsi_session_class);
 	transport_class_unregister(&iscsi_host_class);
-	class_unregister(&iscsi_endpoint_class);
 	class_unregister(&iscsi_transport_class);
 }
 
--- open-iscsi-2.0.870~rc3.orig/kernel/scsi_transport_iscsi.h
+++ open-iscsi-2.0.870~rc3/kernel/scsi_transport_iscsi.h
@@ -30,11 +30,11 @@
 
 struct scsi_transport_template;
 struct iscsi_transport;
-struct iscsi_endpoint;
 struct Scsi_Host;
 struct iscsi_cls_conn;
 struct iscsi_conn;
-struct iscsi_task;
+struct iscsi_cmd_task;
+struct iscsi_mgmt_task;
 struct sockaddr;
 
 /**
@@ -58,22 +58,19 @@
  * @stop_conn:		suspend/recover/terminate connection
  * @send_pdu:		send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text.
  * @session_recovery_timedout: notify LLD a block during recovery timed out
- * @init_task:		Initialize a iscsi_task and any internal structs.
- *			When offloading the data path, this is called from
- *			queuecommand with the session lock, or from the
- *			iscsi_conn_send_pdu context with the session lock.
- *			When not offloading the data path, this is called
- *			from the scsi work queue without the session lock.
- * @xmit_task		Requests LLD to transfer cmd task. Returns 0 or the
+ * @init_cmd_task:	Initialize a iscsi_cmd_task and any internal structs.
+ *			Called from queuecommand with session lock held.
+ * @init_mgmt_task:	Initialize a iscsi_mgmt_task and any internal structs.
+ *			Called from iscsi_conn_send_generic with xmitmutex.
+ * @xmit_cmd_task:	Requests LLD to transfer cmd task. Returns 0 or the
  *			the number of bytes transferred on success, and -Exyz
- *			value on error. When offloading the data path, this
- *			is called from queuecommand with the session lock, or
- *			from the iscsi_conn_send_pdu context with the session
- *			lock. When not offloading the data path, this is called
- *			from the scsi work queue without the session lock.
- * @cleanup_task:	requests LLD to fail task. Called with session lock
- *			and after the connection has been suspended and
- *			terminated during recovery. If called
+ *			value on error.
+ * @xmit_mgmt_task:	Requests LLD to transfer mgmt task. Returns 0 or the
+ *			the number of bytes transferred on success, and -Exyz
+ *			value on error.
+ * @cleanup_cmd_task:	requests LLD to fail cmd task. Called with xmitmutex
+ *			and session->lock after the connection has been
+ *			suspended and terminated during recovery. If called
  *			from abort task then connection is not suspended
  *			or terminated but sk_callback_lock is held
  *
@@ -86,9 +83,17 @@
 	/* LLD sets this to indicate what values it can export to sysfs */
 	uint64_t param_mask;
 	uint64_t host_param_mask;
-	struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep,
-					uint16_t cmds_max, uint16_t qdepth,
-					uint32_t sn, uint32_t *hn);
+	struct scsi_host_template *host_template;
+	/* LLD connection data size */
+	int conndata_size;
+	/* LLD session data size */
+	int sessiondata_size;
+	int max_lun;
+	unsigned int max_conn;
+	unsigned int max_cmd_len;
+	struct iscsi_cls_session *(*create_session) (struct iscsi_transport *it,
+		struct scsi_transport_template *t, uint16_t, uint16_t,
+		uint32_t sn, uint32_t *hn);
 	void (*destroy_session) (struct iscsi_cls_session *session);
 	struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
 				uint32_t cid);
@@ -113,15 +118,20 @@
 			 char *data, uint32_t data_size);
 	void (*get_stats) (struct iscsi_cls_conn *conn,
 			   struct iscsi_stats *stats);
-	int (*init_task) (struct iscsi_task *task);
-	int (*xmit_task) (struct iscsi_task *task);
-	void (*cleanup_task) (struct iscsi_conn *conn,
-				  struct iscsi_task *task);
+	int (*init_cmd_task) (struct iscsi_cmd_task *ctask);
+	void (*init_mgmt_task) (struct iscsi_conn *conn,
+				struct iscsi_mgmt_task *mtask);
+	int (*xmit_cmd_task) (struct iscsi_conn *conn,
+			      struct iscsi_cmd_task *ctask);
+	void (*cleanup_cmd_task) (struct iscsi_conn *conn,
+				  struct iscsi_cmd_task *ctask);
+	int (*xmit_mgmt_task) (struct iscsi_conn *conn,
+			       struct iscsi_mgmt_task *mtask);
 	void (*session_recovery_timedout) (struct iscsi_cls_session *session);
-	struct iscsi_endpoint *(*ep_connect) (struct sockaddr *dst_addr,
-					      int non_blocking);
-	int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms);
-	void (*ep_disconnect) (struct iscsi_endpoint *ep);
+	int (*ep_connect) (struct sockaddr *dst_addr, int non_blocking,
+			   uint64_t *ep_handle);
+	int (*ep_poll) (uint64_t ep_handle, int timeout_ms);
+	void (*ep_disconnect) (uint64_t ep_handle);
 	int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
 			  uint32_t enable, struct sockaddr *dst_addr);
 };
@@ -162,10 +172,9 @@
 	ISCSI_SESSION_FREE,
 };
 
-#define ISCSI_MAX_TARGET -1
-
 struct iscsi_cls_session {
 	struct list_head sess_list;		/* item in session_list */
+	struct list_head host_list;
 	struct iscsi_transport *transport;
 	spinlock_t lock;
 	struct work_struct block_work;
@@ -177,7 +186,7 @@
 	int recovery_tmo;
 	struct delayed_work recovery_work;
 
-	unsigned int target_id;
+	int target_id;
 
 	int state;
 	int sid;				/* session id */
@@ -194,20 +203,12 @@
 #define starget_to_session(_stgt) \
 	iscsi_dev_to_session(_stgt->dev.parent)
 
-struct iscsi_cls_host {
+struct iscsi_host {
+	struct list_head sessions;
 	atomic_t nr_scans;
 	struct mutex mutex;
 	struct workqueue_struct *scan_workq;
-	char scan_workq_name[20];
-};
-
-extern void iscsi_host_for_each_session(struct Scsi_Host *shost,
-				void (*fn)(struct iscsi_cls_session *));
-
-struct iscsi_endpoint {
-	void *dd_data;			/* LLD private data */
-	struct device dev;
-	uint64_t id;
+	char scan_workq_name[KOBJ_NAME_LEN];
 };
 
 /*
@@ -221,26 +222,22 @@
 
 extern int iscsi_session_chkready(struct iscsi_cls_session *session);
 extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost,
-				struct iscsi_transport *transport, int dd_size);
+					struct iscsi_transport *transport);
 extern int iscsi_add_session(struct iscsi_cls_session *session,
 			     unsigned int target_id);
 extern int iscsi_session_event(struct iscsi_cls_session *session,
 			       enum iscsi_uevent_e event);
 extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
 						struct iscsi_transport *t,
-						int dd_size,
 						unsigned int target_id);
 extern void iscsi_remove_session(struct iscsi_cls_session *session);
 extern void iscsi_free_session(struct iscsi_cls_session *session);
 extern int iscsi_destroy_session(struct iscsi_cls_session *session);
 extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess,
-						int dd_size, uint32_t cid);
+					    uint32_t cid);
 extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn);
 extern void iscsi_unblock_session(struct iscsi_cls_session *session);
 extern void iscsi_block_session(struct iscsi_cls_session *session);
 extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time);
-extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size);
-extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
-extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
 
 #endif
--- open-iscsi-2.0.870~rc3.orig/usr/Makefile
+++ open-iscsi-2.0.870~rc3/usr/Makefile
@@ -34,7 +34,7 @@
 PROGRAMS = iscsid iscsiadm iscsistart
 
 # sources shared between iscsid, iscsiadm and iscsistart
-ISCSI_LIB_SRCS = util.o io.o auth.o login.o log.o md5.o sha1.o iface.o idbm.o sysdeps.o sysfs.o iscsi_sysfs.o
+ISCSI_LIB_SRCS = util.o io.o auth.o login.o log.o md5.o sha1.o iscsi_sysfs.o idbm.o
 # sources shared between iscsid and iscsiadm
 COMMON_SRCS =  $(ISCSI_LIB_SRCS)
 # core initiator files
--- open-iscsi-2.0.870~rc3.orig/usr/auth.c
+++ open-iscsi-2.0.870~rc3/usr/auth.c
@@ -31,7 +31,6 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-#include "sysdeps.h"
 #include "auth.h"
 #include "initiator.h"
 #include "md5.h"
@@ -226,6 +225,58 @@
 		close(fd);
 }
 
+/**
+ * strlcpy - Copy a %NUL terminated string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Compatible with *BSD: the result is always a valid
+ * NUL-terminated string that fits in the buffer (unless,
+ * of course, the buffer size is zero). It does not pad
+ * out the result like strncpy() does.
+ **/
+
+size_t strlcpy(char *dest, const char *src, size_t size)
+{
+        size_t ret = strlen(src);
+
+        if (size) {
+                size_t len = (ret >= size) ? size-1 : ret;
+                memcpy(dest, src, len);
+                dest[len] = '\0';
+        }
+        return ret;
+}
+
+/**
+ * strlcat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @count: The size of the destination buffer.
+ **/
+
+size_t strlcat(char *dest, const char *src, size_t count)
+{
+	size_t dsize = strlen(dest);
+        size_t len = strlen(src);
+        size_t res = dsize + len;
+
+	/* This would be a bug */
+	if (dsize >= count) {
+		dest[count - 1] = 0;
+		return count;
+	}
+
+	dest += dsize;
+	count -= dsize;
+	if (len >= count)
+		len = count-1;
+	memcpy(dest, src, len);
+	dest[len] = 0;
+	return res;
+}
+
 static const char acl_none_option_name[] = "None";
 
 static int
--- open-iscsi-2.0.870~rc3.orig/usr/discovery.c
+++ open-iscsi-2.0.870~rc3/usr/discovery.c
@@ -53,7 +53,7 @@
 static char initiator_name[TARGET_NAME_MAXLEN];
 static char initiator_alias[TARGET_NAME_MAXLEN];
 
-int discovery_offload_sendtargets(int host_no, int do_login,
+int discovery_offload_sendtargets(idbm_t *db, int host_no, int do_login,
 				  discovery_rec_t *drec)
 {
 	struct sockaddr_storage ss;
@@ -183,8 +183,9 @@
 	return 1;
 }
 
-static int add_portal(struct list_head *rec_list, discovery_rec_t *drec,
-		      char *targetname, char *address, char *port, char *tag)
+static int add_portal(idbm_t *db, struct list_head *rec_list,
+		      discovery_rec_t *drec, char *targetname, char *address,
+		      char *port, char *tag)
 {
 	struct sockaddr_storage ss;
 	char host[NI_MAXHOST];
@@ -204,7 +205,7 @@
 	if (!rec)
 		return 0;
 
-	idbm_node_setup_from_conf(rec);
+	idbm_node_setup_from_conf(db, rec);
 	rec->disc_type = drec->type;
 	rec->disc_port = drec->port;
 	strcpy(rec->disc_address, drec->address);
@@ -225,8 +226,9 @@
 }
 
 static int
-add_target_record(char *name, char *end, discovery_rec_t *drec,
-		  struct list_head *rec_list, char *default_port)
+add_target_record(idbm_t *db, char *name, char *end,
+		  discovery_rec_t *drec, struct list_head *rec_list,
+		  char *default_port)
 {
 	char *text = NULL;
 	char *nul = name;
@@ -269,7 +271,7 @@
 			log_error("no default address known for target %s",
 				  name);
 			return 0;
-		} else if (!add_portal(rec_list, drec, name, drec->address,
+		} else if (!add_portal(db, rec_list, drec, name, drec->address,
 				       default_port, NULL)) {
 			log_error("failed to add default portal, ignoring "
 				  "target %s", name);
@@ -307,7 +309,7 @@
 					*temp = '\0';
 			}
 
-			if (!add_portal(rec_list, drec, name, address, port,
+			if (!add_portal(db, rec_list, drec, name, address, port,
 					tag)) {
 				log_error("failed to add default portal, "
 					 "ignoring target %s", name);
@@ -323,7 +325,7 @@
 }
 
 static int
-process_sendtargets_response(struct string_buffer *sendtargets,
+process_sendtargets_response(idbm_t *db, struct string_buffer *sendtargets,
 			     int final, discovery_rec_t *drec,
 			     struct list_head *rec_list,
 			     char *default_port)
@@ -376,7 +378,7 @@
 				 * the end of. don't bother passing the
 				 * "TargetName=" prefix.
 				 */
-				if (!add_target_record(record + 11, text,
+				if (!add_target_record(db, record + 11, text,
 							drec, rec_list,
 							default_port)) {
 					log_error(
@@ -405,7 +407,7 @@
 				 "processing final sendtargets record %p, "
 				 "line %s",
 				 record, record);
-			if (add_target_record (record + 11, text,
+			if (add_target_record (db, record + 11, text,
 					       drec, rec_list, default_port)) {
 				num_targets++;
 				record = NULL;
@@ -684,7 +686,7 @@
 }
 
 static int
-process_recvd_pdu(struct iscsi_hdr *pdu,
+process_recvd_pdu(idbm_t *db, struct iscsi_hdr *pdu,
 		  discovery_rec_t *drec,
 		  struct list_head *rec_list,
 		  iscsi_session_t *session,
@@ -725,7 +727,7 @@
 
 			*valid_text = 1;
 			/* process as much as we can right now */
-			process_sendtargets_response(sendtargets,
+			process_sendtargets_response(db, sendtargets,
 						     final,
 						     drec,
 						     rec_list,
@@ -819,7 +821,7 @@
 	iscsi_io_disconnect(&session->conn[0]);
 }
 
-int discovery_sendtargets(discovery_rec_t *drec,
+int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec,
 			  struct list_head *rec_list)
 {
 	iscsi_session_t *session;
@@ -1117,7 +1119,7 @@
 			/*
 			 * process iSCSI PDU received
 			 */
-			rc = process_recvd_pdu(pdu, drec, rec_list,
+			rc = process_recvd_pdu(db, pdu, drec, rec_list,
 					       session, &sendtargets,
 					       default_port,
 					       &active, &valid_text, data);
--- open-iscsi-2.0.870~rc3.orig/usr/idbm.c
+++ open-iscsi-2.0.870~rc3/usr/idbm.c
@@ -36,14 +36,11 @@
 #include "iscsi_settings.h"
 #include "transport.h"
 #include "iscsi_sysfs.h"
-#include "iface.h"
 
 #define IDBM_HIDE	0    /* Hide parameter when print. */
 #define IDBM_SHOW	1    /* Show parameter when print. */
 #define IDBM_MASKED	2    /* Show "stars" instead of real value when print */
 
-static struct idbm *db;
-
 #define __recinfo_str(_key, _info, _rec, _name, _show, _n, _mod) do { \
 	_info[_n].type = TYPE_STR; \
 	strncpy(_info[_n].name, _key, NAME_MAXVAL); \
@@ -286,8 +283,6 @@
 	 */
 	__recinfo_str("iface.transport_name", ri, r, iface.transport_name,
 		      IDBM_SHOW, num, 1);
-	__recinfo_str("iface.initiatorname", ri, r, iface.iname,
-		      IDBM_SHOW, num, 1);
 	__recinfo_str("node.discovery_address", ri, r, disc_address, IDBM_SHOW,
 		      num, 0);
 	__recinfo_int("node.discovery_port", ri, r, disc_port, IDBM_SHOW,
@@ -407,7 +402,8 @@
 	}
 }
 
-void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
+static void
+idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
 {
 	int num = 0;
 
@@ -417,10 +413,10 @@
 	__recinfo_str("iface.hwaddress", ri, r, hwaddress, IDBM_SHOW, num, 1);
 	__recinfo_str("iface.transport_name", ri, r, transport_name,
 		      IDBM_SHOW, num, 1);
-	__recinfo_str("iface.initiatorname", ri, r, iname, IDBM_SHOW, num, 1);
 }
 
-recinfo_t *idbm_recinfo_alloc(int max_keys)
+static recinfo_t*
+idbm_recinfo_alloc(int max_keys)
 {
 	recinfo_t *info;
 
@@ -431,7 +427,14 @@
 	return info;
 }
 
-void idbm_print(int type, void *rec, int show, FILE *f)
+enum {
+	PRINT_TYPE_DISCOVERY,
+	PRINT_TYPE_NODE,
+	PRINT_TYPE_IFACE,
+};
+
+static void
+idbm_print(int type, void *rec, int show, FILE *f)
 {
 	int i;
 	recinfo_t *info;
@@ -441,13 +444,13 @@
 		return;
 
 	switch (type) {
-	case IDBM_PRINT_TYPE_DISCOVERY:
+	case PRINT_TYPE_DISCOVERY:
 		idbm_recinfo_discovery((discovery_rec_t*)rec, info);
 		break;
-	case IDBM_PRINT_TYPE_NODE:
+	case PRINT_TYPE_NODE:
 		idbm_recinfo_node((node_rec_t*)rec, info);
 		break;
-	case IDBM_PRINT_TYPE_IFACE:
+	case PRINT_TYPE_IFACE:
 		idbm_recinfo_iface((struct iface_rec *)rec, info);
 		break;
 	}
@@ -502,8 +505,9 @@
 	}
 }
 
-int idbm_rec_update_param(recinfo_t *info, char *name, char *value,
-			  int line_number)
+static int
+idbm_rec_update_param(recinfo_t *info, char *name, char *value,
+		      int line_number)
 {
 	int i;
 	int passwd_done = 0;
@@ -575,7 +579,7 @@
 /*
  * TODO: we can also check for valid values here.
  */
-int idbm_verify_param(recinfo_t *info, char *name)
+static int idbm_verify_param(recinfo_t *info, char *name)
 {
 	int i;
 
@@ -597,7 +601,8 @@
 	return EINVAL;
 }
 
-void idbm_recinfo_config(recinfo_t *info, FILE *f)
+static void
+idbm_recinfo_config(recinfo_t *info, FILE *f)
 {
 	char name[NAME_MAXVAL];
 	char value[VALUE_MAXVAL];
@@ -667,7 +672,8 @@
 /*
  * TODO: remove db's copy of nrec and infos
  */
-static void idbm_sync_config(void)
+static void
+idbm_sync_config(idbm_t *db)
 {
 	char *config_file;
 	FILE *f;
@@ -732,37 +738,37 @@
 			strlen((char*)db->nrec.session.auth.password_in);
 }
 
-void idbm_node_setup_from_conf(node_rec_t *rec)
+void idbm_node_setup_from_conf(idbm_t *db, node_rec_t *rec)
 {
 	memset(rec, 0, sizeof(*rec));
 	idbm_node_setup_defaults(rec);
-	idbm_sync_config();
+	idbm_sync_config(db);
 	memcpy(rec, &db->nrec, sizeof(*rec));
 }
 
-int idbm_print_discovery_info(discovery_rec_t *rec, int show)
+int idbm_print_discovery_info(idbm_t *db, discovery_rec_t *rec, int show)
 {
-	idbm_print(IDBM_PRINT_TYPE_DISCOVERY, rec, show, stdout);
+	idbm_print(PRINT_TYPE_DISCOVERY, rec, show, stdout);
 	return 1;
 }
 
-int idbm_print_node_info(void *data, node_rec_t *rec)
+int idbm_print_node_info(idbm_t *db, void *data, node_rec_t *rec)
 {
 	int show = *((int *)data);
 
-	idbm_print(IDBM_PRINT_TYPE_NODE, rec, show, stdout);
+	idbm_print(PRINT_TYPE_NODE, rec, show, stdout);
 	return 0;
 }
 
-int idbm_print_iface_info(void *data, struct iface_rec *iface)
+int idbm_print_iface_info(idbm_t *db, void *data, struct iface_rec *iface)
 {
 	int show = *((int *)data);
 
-	idbm_print(IDBM_PRINT_TYPE_IFACE, iface, show, stdout);
+	idbm_print(PRINT_TYPE_IFACE, iface, show, stdout);
 	return 0;
 }
 
-int idbm_print_node_flat(void *data, node_rec_t *rec)
+int idbm_print_node_flat(idbm_t *db, void *data, node_rec_t *rec)
 {
 	if (strchr(rec->conn[0].address, '.'))
 		printf("%s:%d,%d %s\n", rec->conn[0].address, rec->conn[0].port,
@@ -773,7 +779,7 @@
 	return 0;
 }
 
-int idbm_print_node_tree(void *data, node_rec_t *rec)
+int idbm_print_node_tree(idbm_t *db, void *data, node_rec_t *rec)
 {
 	node_rec_t *last_rec = data;
 
@@ -825,7 +831,7 @@
 	return 0;
 }
 
-int idbm_lock(void)
+static int idbm_lock(idbm_t *db)
 {
 	int fd, i, ret;
 
@@ -857,7 +863,7 @@
 	return 0;
 }
 
-void idbm_unlock(void)
+static void idbm_unlock(idbm_t *db)
 {
 	if (db->refs > 1) {
 		db->refs--;
@@ -869,6 +875,560 @@
 }
 
 /*
+ * default is to use tcp through whatever the network layer
+ * selects for us
+ */
+void iface_init(struct iface_rec *iface)
+{
+	sprintf(iface->netdev, DEFAULT_NETDEV);
+//	sprintf(iface->ipaddress, DEFAULT_IPADDRESS);
+	sprintf(iface->hwaddress, DEFAULT_HWADDRESS);
+	sprintf(iface->transport_name, DEFAULT_TRANSPORT);
+	if (!strlen(iface->name))
+		sprintf(iface->name, DEFAULT_IFACENAME);
+}
+
+struct iface_rec *iface_alloc(char *ifname, int *err)
+{
+	struct iface_rec *iface;
+
+	if (!strlen(ifname) || strlen(ifname) + 1 > ISCSI_MAX_IFACE_LEN) {
+		*err = EINVAL;
+		return NULL;
+	}
+
+	iface = calloc(1, sizeof(*iface));
+	if (!iface) {
+		*err = ENOMEM;
+		return NULL;
+	}
+
+	strncpy(iface->name, ifname, ISCSI_MAX_IFACE_LEN);
+	INIT_LIST_HEAD(&iface->list);
+	return iface;
+}
+
+static int __iface_conf_read(struct iface_rec *iface)
+{
+	char *iface_conf;
+	recinfo_t *info;
+	FILE *f;
+	int rc = 0;
+
+	iface_conf = calloc(1, PATH_MAX);
+	if (!iface_conf)
+		return ENOMEM;
+
+	info = idbm_recinfo_alloc(MAX_KEYS);
+	if (!info) {
+		rc = ENOMEM;
+		goto free_conf;
+	}
+
+	snprintf(iface_conf, PATH_MAX, "%s/%s", IFACE_CONFIG_DIR,
+		 iface->name);
+
+	log_debug(5, "looking for iface conf %s", iface_conf);
+	f = fopen(iface_conf, "r");
+	if (!f) {
+		/*
+		 * if someone passes in default but has not defined
+		 * a iface with default then we do it for them
+		 */
+		if (!strcmp(iface->name, DEFAULT_IFACENAME)) {
+			iface_init(iface);
+			rc = 0;
+		} else
+			rc = errno;
+		goto free_info;
+	}
+
+	iface_init(iface);
+	idbm_recinfo_iface(iface, info);
+	idbm_recinfo_config(info, f);
+	fclose(f);
+
+free_info:
+	free(info);
+free_conf:
+	free(iface_conf);
+	return rc;
+}
+
+int iface_conf_read(idbm_t *db, struct iface_rec *iface)
+{
+	int rc;
+
+	idbm_lock(db);
+	rc = __iface_conf_read(iface);
+	idbm_unlock(db);
+	return rc;
+}
+
+int iface_conf_delete(idbm_t *db, struct iface_rec *iface)
+{
+	char *iface_conf;
+	int rc = 0;
+
+	iface_conf = calloc(1, PATH_MAX);
+	if (!iface_conf)
+		return ENOMEM;
+
+	sprintf(iface_conf, "%s/%s", IFACE_CONFIG_DIR, iface->name);
+	idbm_lock(db);
+	if (unlink(iface_conf))
+		rc = errno;
+	idbm_unlock(db);
+
+	free(iface_conf);
+	return rc;
+}
+
+int iface_conf_write(idbm_t *db, struct iface_rec *iface)
+{
+	char *iface_conf;
+	FILE *f;
+	int rc = 0;
+
+	iface_conf = calloc(1, PATH_MAX);
+	if (!iface_conf)
+		return ENOMEM;
+
+	sprintf(iface_conf, "%s/%s", IFACE_CONFIG_DIR, iface->name);
+	f = fopen(iface_conf, "w");
+	if (!f) {
+		rc = errno;
+		goto free_conf;
+	}
+
+	idbm_lock(db);
+	idbm_print(PRINT_TYPE_IFACE, iface, 1, f);
+	idbm_unlock(db);
+
+	fclose(f);
+free_conf:
+	free(iface_conf);
+	return rc;
+}
+
+int iface_conf_update(idbm_t *db, struct db_set_param *param,
+		       struct iface_rec *iface)
+{
+	recinfo_t *info;
+	int rc = 0;
+
+	info = idbm_recinfo_alloc(MAX_KEYS);
+	if (!info)
+		return ENOMEM;
+
+	idbm_recinfo_iface(iface, info);
+	rc = idbm_verify_param(info, param->name);
+	if (rc)
+		goto free_info;
+
+	rc = idbm_rec_update_param(info, param->name, param->value, 0);
+	if (rc) {
+		rc = EIO;
+		goto free_info;
+	}
+
+	rc = iface_conf_write(db, iface);
+free_info:
+	free(info);
+	return rc;
+}
+
+static int iface_get_next_id(void)
+{
+	struct stat statb;
+	char *iface_conf;
+	int i, rc = ENOSPC;
+
+	iface_conf = calloc(1, PATH_MAX);
+	if (!iface_conf)
+		return ENOMEM;
+
+	for (i = 0; i < INT_MAX; i++) {
+		memset(iface_conf, 0, PATH_MAX);
+		/* check len */
+		snprintf(iface_conf, PATH_MAX, "iface%d", i);
+		if (strlen(iface_conf) > ISCSI_MAX_IFACE_LEN - 1) {
+			log_error("iface namespace is full. Remove unused "
+				  "iface definitions from %s or send mail "
+				  "to open-iscsi@googlegroups.com to report "
+				  "the problem", IFACE_CONFIG_DIR);
+			rc = ENOSPC;
+			break;
+		}
+		memset(iface_conf, 0, PATH_MAX);
+		snprintf(iface_conf, PATH_MAX, "%s/iface%d", IFACE_CONFIG_DIR,
+			i);
+
+		if (!stat(iface_conf, &statb))
+			continue;
+		if (errno == ENOENT) {
+			rc = i;
+			break;
+		}
+	}
+
+	free(iface_conf);
+        return rc;
+}
+
+struct iface_search {
+	struct iface_rec *pattern;
+	struct iface_rec *found;
+};
+
+static int __iface_get_by_bind_info(void *data, struct iface_rec *iface)
+{
+	struct iface_search *search = data;
+
+	if (!strcmp(search->pattern->name, iface->name)) {
+		iface_copy(search->found, iface);
+		return 1;
+	}
+
+	if (iface_is_bound_by_hwaddr(search->pattern)) {
+		if (!strcmp(iface->hwaddress, search->pattern->hwaddress)) {
+			iface_copy(search->found, iface);
+			return 1;
+		} else
+			return 0;
+	}
+
+	if (iface_is_bound_by_netdev(search->pattern)) {
+		if (!strcmp(iface->netdev, search->pattern->netdev)) {
+			iface_copy(search->found, iface);
+			return 1;
+		} else
+			return 0;
+	}
+
+/*
+	if (iface_is_bound_by_ipaddr(search->pattern)) {
+		if (!strcmp(iface->ipaddress, search->pattern->ipaddress)) {
+			iface_copy(search->found, iface);
+			return 1;
+		} else
+			return 0;
+	}
+*/
+	return 0;
+}
+
+int iface_get_by_bind_info(idbm_t *db, struct iface_rec *pattern,
+			   struct iface_rec *out_rec)
+{
+	int num_found = 0, rc;
+	struct iface_search search;
+
+	search.pattern = pattern;
+	search.found = out_rec;
+
+	rc = iface_for_each_iface(db, &search, &num_found,
+				  __iface_get_by_bind_info);
+	if (rc == 1)
+		return 0;
+
+	if (iface_is_bound(pattern))
+		return ENODEV;
+
+	/*
+	 * compat for default behavior
+	 */
+	if (!strlen(pattern->name) ||
+	    !strcmp(pattern->name, DEFAULT_IFACENAME)) {
+		iface_init(out_rec);
+		return 0;
+	}
+
+	return ENODEV;
+}
+
+static int __iface_setup_host_bindings(void *data, struct host_info *info)
+{
+	idbm_t *db = data;
+	struct iface_rec iface;
+	struct iscsi_transport *t;
+	int id;
+
+	if (!strlen(info->iface.hwaddress) ||
+	    !strlen(info->iface.transport_name))
+		return 0;
+
+	t = get_transport_by_hba(info->host_no);
+	if (!t)
+		return 0;
+	/*
+	 * if software iscsi do not touch the bindngs. They do not
+	 * need it and may not support it
+	 */
+	if (!(t->caps & CAP_DATA_PATH_OFFLOAD))
+		return 0;
+
+	if (iface_get_by_bind_info(db, &info->iface, &iface)) {
+		/* Must be a new port */
+		id = iface_get_next_id();
+		if (id < 0) {
+			log_error("Could not add iface for %s.",
+				  info->iface.hwaddress);
+			return 0;
+		}
+		memset(&iface, 0, sizeof(struct iface_rec));
+		strcpy(iface.hwaddress, info->iface.hwaddress);
+		strcpy(iface.transport_name, info->iface.transport_name);
+		sprintf(iface.name, "iface%d", id);
+		if (iface_conf_write(db, &iface))
+			log_error("Could not write iface conf for %s %s",
+				  iface.name, iface.hwaddress);
+			/* fall through - will not be persistent */
+	}
+	return 0;
+}
+
+/*
+ * sync hw/offload iscsi scsi_hosts with iface values
+ */
+void iface_setup_host_bindings(idbm_t *db)
+{
+	int nr_found = 0;
+
+	idbm_lock(db);
+	if (access(IFACE_CONFIG_DIR, F_OK) != 0) {
+		if (mkdir(IFACE_CONFIG_DIR, 0660) != 0) {
+			log_error("Could not make %s. HW/OFFLOAD iscsi "
+				  "may not be supported", IFACE_CONFIG_DIR);
+			idbm_unlock(db);
+			return;
+		}
+	}
+	idbm_unlock(db);
+
+	if (sysfs_for_each_host(db, &nr_found,
+				__iface_setup_host_bindings))
+		log_error("Could not scan scsi hosts. HW/OFFLOAD iscsi "
+			  "operations may not be supported.");
+}
+
+void iface_copy(struct iface_rec *dst, struct iface_rec *src)
+{
+	if (strlen(src->name))
+		strcpy(dst->name, src->name);
+	if (strlen(src->netdev))
+		strcpy(dst->netdev, src->netdev);
+//	if (strlen(src->ipaddress))
+//		strcpy(dst->ipaddress, src->ipaddress);
+	if (strlen(src->hwaddress))
+		strcpy(dst->hwaddress, src->hwaddress);
+	if (strlen(src->transport_name))
+		strcpy(dst->transport_name, src->transport_name);
+}
+
+int iface_is_bound(struct iface_rec *iface)
+{
+	if (!iface)
+		return 0;
+
+	if (iface_is_bound_by_hwaddr(iface))
+		return 1;
+
+	if (iface_is_bound_by_netdev(iface))
+		return 1;
+
+//	if (iface_is_bound_by_ipaddr(iface))
+//		return 1;
+
+	return 0;
+}
+
+int iface_match_bind_info(struct iface_rec *pattern, struct iface_rec *iface)
+{
+	if (!pattern || !iface)
+		return 1;
+
+	/* if no values set then we have a match */
+	if (!strlen(pattern->hwaddress) &&
+//	    !strlen(pattern->ipaddress) &&
+	    !strlen(pattern->netdev) &&
+	    !strlen(pattern->name))
+		return 1;
+
+	/*
+	 * If both interfaces are not bound we return match.
+	 * This assumes we will not have two ifaces with different
+	 * names and no binding info. There should only be one
+	 * iface with no binding info for each transport and that
+	 * is the "default" which is used for backward compat from
+	 * when we did not have ifaces.	
+	 */
+	if (!iface_is_bound(iface) &&
+	    !iface_is_bound(pattern))
+		return 1;
+
+	if (iface_is_bound_by_hwaddr(pattern) &&
+	    !strcmp(pattern->hwaddress, iface->hwaddress))
+		return 1;
+
+	if (iface_is_bound_by_netdev(pattern) &&
+	    !strcmp(pattern->netdev, iface->netdev))
+		return 1;
+
+//	if (iface_is_bound_by_ipaddr(iface) &&
+//	   !strcmp(pattern->ipaddress, iface->ipaddress))
+//		return 1;
+
+	if (strlen(pattern->name)) {
+		if (!strcmp(pattern->name, iface->name))
+			return 1;
+	}
+
+	return 0;
+}
+
+int iface_is_bound_by_hwaddr(struct iface_rec *iface)
+{
+	if (iface && strlen(iface->hwaddress) &&
+	   strcmp(iface->hwaddress, DEFAULT_HWADDRESS))
+		return 1;
+	return 0;
+}
+
+int iface_is_bound_by_netdev(struct iface_rec *iface)
+{
+	if (iface && strlen(iface->netdev) &&
+	   strcmp(iface->netdev, DEFAULT_NETDEV))
+		return 1;
+	return 0;
+}
+
+int iface_is_bound_by_ipaddr(struct iface_rec *iface)
+{
+	return 0;
+/*	if (iface && strlen(iface->ipaddress) &&
+	   strcmp(iface->ipaddress, DEFAULT_NETDEV))
+		return 1;
+	return 0;
+*/
+}
+
+/**
+ * iface_print_node_tree - print out binding info
+ * @iface: iface to print out
+ *
+ * Currently this looks like the iface conf print, because we only
+ * have the binding info. When we store the iface specific node settings
+ * in the iface record then it will look different.
+ */
+int iface_print_tree(void *data, struct iface_rec *iface)
+{
+	printf("Name: %s\n", iface->name);
+	printf("\tTransport Name: %s\n",
+	       strlen(iface->transport_name) ? iface->transport_name :
+	       UNKNOWN_VALUE);
+	printf("\tHW Address: %s\n",
+	       strlen(iface->hwaddress) ? iface->hwaddress : UNKNOWN_VALUE);
+	printf("\tNetdev: %s\n",
+	       strlen(iface->netdev) ? iface->netdev : UNKNOWN_VALUE);
+	return 0;
+}
+
+int iface_print_flat(void *data, struct iface_rec *iface)
+{
+	printf("%s %s,%s,%s\n",
+		strlen(iface->name) ? iface->name : UNKNOWN_VALUE,
+		strlen(iface->transport_name) ? iface->transport_name :
+							UNKNOWN_VALUE,
+		strlen(iface->hwaddress) ? iface->hwaddress : UNKNOWN_VALUE,
+		strlen(iface->netdev) ? iface->netdev : UNKNOWN_VALUE);
+	return 0;
+}
+
+int iface_for_each_iface(idbm_t *db, void *data, int *nr_found, iface_op_fn *fn)
+{
+	DIR *iface_dirfd;
+	struct dirent *iface_dent;
+	struct iface_rec *iface;
+	int err = 0;
+
+	iface_dirfd = opendir(IFACE_CONFIG_DIR);
+	if (!iface_dirfd)
+		return errno;
+
+	while ((iface_dent = readdir(iface_dirfd))) {
+		if (!strcmp(iface_dent->d_name, ".") ||
+		    !strcmp(iface_dent->d_name, ".."))
+			continue;
+
+		log_debug(5, "iface_for_each_iface found %s",
+			 iface_dent->d_name);
+		iface = iface_alloc(iface_dent->d_name, &err);
+		if (!iface || err) {
+			if (err == EINVAL)
+				log_error("Invalid iface name %s. Must be "
+					  "from 1 to %d characters.",
+					   iface_dent->d_name,
+					   ISCSI_MAX_IFACE_LEN - 1);
+			else
+				log_error("Could not add iface %s.",
+					  iface_dent->d_name);
+			free(iface);
+			continue;
+		}
+
+		idbm_lock(db);
+		err = __iface_conf_read(iface);
+		idbm_unlock(db);
+		if (err) {
+			log_error("Could not read def iface %s (err %d)",
+				  iface->name, err);
+			free(iface);
+			continue;
+		}
+
+		if (!iface_is_bound(iface)) {
+			log_debug(5, "iface is not bound "
+				  "Iface settings " iface_fmt,
+				  iface_str(iface));
+			free(iface);
+			continue;
+		}
+
+		err = fn(data, iface);
+		free(iface);
+		if (err)
+			break;
+		(*nr_found)++;
+	}
+
+	closedir(iface_dirfd);
+	return err;
+}
+
+static int iface_link(void *data, struct iface_rec *iface)
+{
+	struct list_head *ifaces = data;
+	struct iface_rec *iface_copy;
+
+	iface_copy = calloc(1, sizeof(*iface_copy));
+	if (!iface_copy)
+		return ENOMEM;
+
+	memcpy(iface_copy, iface, sizeof(*iface_copy));
+	INIT_LIST_HEAD(&iface_copy->list);
+	list_add_tail(&iface_copy->list, ifaces);
+	return 0;
+}
+
+static void iface_link_ifaces(idbm_t *db, struct list_head *ifaces)
+{
+	int nr_found = 0;
+
+	iface_for_each_iface(db, ifaces, &nr_found, iface_link);
+}
+
+/*
  * Backwards Compat:
  * If the portal is a file then we are doing the old style default
  * session behavior (svn pre 780).
@@ -891,7 +1451,7 @@
 	return fopen(portal, "r");
 }
 
-static int __idbm_rec_read(node_rec_t *out_rec, char *conf)
+static int __idbm_rec_read(idbm_t *db, node_rec_t *out_rec, char *conf)
 {
 	recinfo_t *info;
 	FILE *f;
@@ -901,7 +1461,7 @@
 	if (!info)
 		return ENOMEM;
 
-	idbm_lock();
+	idbm_lock(db);
 	f = fopen(conf, "r");
 	if (!f) {
 		log_debug(5, "Could not open %s err %d\n", conf, errno);
@@ -916,13 +1476,13 @@
 	fclose(f);
 
 unlock:
-	idbm_unlock();
+	idbm_unlock(db);
 	free(info);
 	return rc;
 }
 
 int
-idbm_rec_read(node_rec_t *out_rec, char *targetname, int tpgt,
+idbm_rec_read(idbm_t *db, node_rec_t *out_rec, char *targetname, int tpgt,
 	      char *ip, int port, struct iface_rec *iface)
 {
 	struct stat statb;
@@ -955,7 +1515,7 @@
 	}
 
 read:
-	rc = __idbm_rec_read(out_rec, portal);
+	rc = __idbm_rec_read(db, out_rec, portal);
 free_portal:
 	free(portal);
 	return rc;
@@ -967,7 +1527,7 @@
 	       strcmp(dir->d_name, ST_CONFIG_NAME);
 }
 
-static int print_discovered(char *disc_path, int info_level)
+static int print_discovered(idbm_t *db, char *disc_path, int info_level)
 {
 	char *tmp_port = NULL, *last_address = NULL, *last_target = NULL;
 	char *target = NULL, *address = NULL, *ifaceid = NULL, *tpgt = NULL;
@@ -999,7 +1559,7 @@
 		memset(portal, 0, PATH_MAX);
 		snprintf(portal, PATH_MAX, "%s/%s/%s,%s,%s/%s", NODE_CONFIG_DIR,
 			 target, address, tmp_port, tpgt, ifaceid);
-		if (__idbm_rec_read(rec, portal)) {
+		if (__idbm_rec_read(db, rec, portal)) {
 			log_error("Could not read node record for %s "
 				  "%s %d %s", target, address, atoi(tmp_port),
 				  ifaceid);
@@ -1049,7 +1609,7 @@
 	return n;
 }
 
-int idbm_print_discovered(discovery_rec_t *drec, int info_level)
+int idbm_print_discovered(idbm_t *db, discovery_rec_t *drec, int info_level)
 {
 	char *disc_path;
 	int rc;
@@ -1075,13 +1635,13 @@
 		goto done;
 	}
 
-	rc = print_discovered(disc_path, info_level);
+	rc = print_discovered(db, disc_path, info_level);
 done:
 	free(disc_path);
 	return rc;
 }
 
-static int idbm_print_all_st(int info_level)
+static int idbm_print_all_st(idbm_t *db, int info_level)
 {
 	DIR *entity_dirfd;
 	struct dirent *entity_dent;
@@ -1108,7 +1668,7 @@
 				 entity_dent->d_name);
 
 			printf("DiscoveryAddress: %s\n", entity_dent->d_name);
-			found += print_discovered(disc_dir, info_level);
+			found += print_discovered(db, disc_dir, info_level);
 		} else {
 			char *tmp_port;
 
@@ -1128,13 +1688,13 @@
 	return found;
 }
 
-int idbm_print_all_discovery(int info_level)
+int idbm_print_all_discovery(idbm_t *db, int info_level)
 {
 	discovery_rec_t *drec;
 	int found = 0, tmp;
 
 	if (info_level < 1)
-		return idbm_print_all_st(info_level);
+		return idbm_print_all_st(db, info_level);
 
 	drec = calloc(1, sizeof(*drec));
 	if (!drec)
@@ -1142,7 +1702,7 @@
 
 	tmp = 0;
 	printf("SENDTARGETS:\n");
-	tmp = idbm_print_all_st(info_level);
+	tmp = idbm_print_all_st(db, info_level);
 	if (!tmp)
 		printf("No targets found.\n");
 	found += tmp;
@@ -1150,7 +1710,7 @@
 
 	printf("iSNS:\n");
 	drec->type = DISCOVERY_TYPE_ISNS;
-	tmp = idbm_print_discovered(drec, info_level);
+	tmp = idbm_print_discovered(db, drec, info_level);
 	if (!tmp)
 		printf("No targets found.\n");
 	found += tmp;
@@ -1158,7 +1718,7 @@
 
 	printf("STATIC:\n");
 	drec->type = DISCOVERY_TYPE_STATIC;
-	tmp = idbm_print_discovered(drec, info_level);
+	tmp = idbm_print_discovered(db, drec, info_level);
 	if (!tmp)
 		printf("No targets found.\n");
 	found += tmp;
@@ -1171,7 +1731,7 @@
  * This iterates over the ifaces in use in the nodes dir.
  * It does not iterate over the ifaces setup in /etc/iscsi/ifaces.
  */
-static int idbm_for_each_iface(int *found, void *data,
+static int idbm_for_each_iface(idbm_t *db, int *found, void *data,
 				idbm_iface_op_fn *fn,
 				char *targetname, int tpgt, char *ip, int port)
 {
@@ -1198,11 +1758,11 @@
 		goto free_portal;
 	}
 
-	rc = __idbm_rec_read(&rec, portal);
+	rc = __idbm_rec_read(db, &rec, portal);
 	if (rc)
 		goto free_portal;
 
-	rc = fn(data, &rec);
+	rc = fn(db, data, &rec);
 	if (!rc)
 		(*found)++;
 	else if (rc == -1)
@@ -1228,11 +1788,11 @@
 		memset(portal, 0, PATH_MAX);
 		snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
 			 targetname, ip, port, tpgt, iface_dent->d_name);
-		if (__idbm_rec_read(&rec, portal))
+		if (__idbm_rec_read(db, &rec, portal))
 			continue;
 
 		/* less than zero means it was not a match */
-		rc = fn(data, &rec);
+		rc = fn(db, data, &rec);
 		if (rc > 0)
 			break;
 		else if (rc == 0)
@@ -1251,8 +1811,8 @@
  * backwards compat
  * The portal could be a file or dir with interfaces
  */
-int idbm_for_each_portal(int *found, void *data, idbm_portal_op_fn *fn,
-			 char *targetname)
+int idbm_for_each_portal(idbm_t *db, int *found, void *data,
+			 idbm_portal_op_fn *fn, char *targetname)
 {
 	DIR *portal_dirfd;
 	struct dirent *portal_dent;
@@ -1286,7 +1846,7 @@
 		if (tmp_tpgt)
 			*tmp_tpgt++ = '\0';
 
-		rc = fn(found, data, targetname,
+		rc = fn(db, found, data, targetname,
 			tmp_tpgt ? atoi(tmp_tpgt) : -1,
 			portal_dent->d_name, atoi(tmp_port));
 		if (rc)
@@ -1298,7 +1858,7 @@
 	return rc;
 }
 
-int idbm_for_each_node(int *found, void *data, idbm_node_op_fn *fn)
+int idbm_for_each_node(idbm_t *db, int *found, void *data, idbm_node_op_fn *fn)
 {
 	DIR *node_dirfd;
 	struct dirent *node_dent;
@@ -1317,7 +1877,7 @@
 			continue;
 
 		log_debug(5, "searching %s\n", node_dent->d_name);
-		rc = fn(found, data, node_dent->d_name);
+		rc = fn(db, found, data, node_dent->d_name);
 		if (rc)
 			break;
 	}
@@ -1326,26 +1886,26 @@
 	return rc;
 }
 
-static int iface_fn(void *data, node_rec_t *rec)
+static int iface_fn(idbm_t *db, void *data, node_rec_t *rec)
 {
 	struct rec_op_data *op_data = data;
 
-	return op_data->fn(op_data->data, rec);
+	return op_data->fn(db, op_data->data, rec);
 }
 
-static int portal_fn(int *found, void *data, char *targetname,
+static int portal_fn(idbm_t *db, int *found, void *data, char *targetname,
 		     int tpgt, char *ip, int port)
 {
-	return idbm_for_each_iface(found, data, iface_fn, targetname,
+	return idbm_for_each_iface(db, found, data, iface_fn, targetname,
 				   tpgt, ip, port);
 }
 
-static int node_fn(int *found, void *data, char *targetname)
+static int node_fn(idbm_t *db, int *found, void *data, char *targetname)
 {
-	return idbm_for_each_portal(found, data, portal_fn, targetname);
+	return idbm_for_each_portal(db, found, data, portal_fn, targetname);
 }
 
-int idbm_for_each_rec(int *found, void *data, idbm_iface_op_fn *fn)
+int idbm_for_each_rec(idbm_t *db, int *found, void *data, idbm_iface_op_fn *fn)
 {
 	struct rec_op_data op_data;
 
@@ -1353,11 +1913,11 @@
 	op_data.data = data;
 	op_data.fn = fn;
 
-	return idbm_for_each_node(found, &op_data, node_fn);
+	return idbm_for_each_node(db, found, &op_data, node_fn);
 }
 
 int
-idbm_discovery_read(discovery_rec_t *out_rec, char *addr, int port)
+idbm_discovery_read(idbm_t *db, discovery_rec_t *out_rec, char *addr, int port)
 {
 	recinfo_t *info;
 	char *portal;
@@ -1378,7 +1938,7 @@
 		 addr, port);
 	log_debug(5, "Looking for config file %s\n", portal);
 
-	idbm_lock();
+	idbm_lock(db);
 
 	f = idbm_open_rec_r(portal, ST_CONFIG_NAME);
 	if (!f) {
@@ -1393,7 +1953,7 @@
 	fclose(f);
 
 unlock:	
-	idbm_unlock();
+	idbm_unlock(db);
 free_info:
 	free(portal);
 	free(info);
@@ -1444,7 +2004,7 @@
 	return f;
 }
 
-static int idbm_rec_write(node_rec_t *rec)
+static int idbm_rec_write(idbm_t *db, node_rec_t *rec)
 {
 	struct stat statb;
 	FILE *f;
@@ -1479,7 +2039,7 @@
 		 rec->name, rec->conn[0].address, rec->conn[0].port);
 	log_debug(5, "Looking for config file %s", portal);
 
-	idbm_lock();
+	idbm_lock(db);
 
 	rc = stat(portal, &statb);
 	if (rc) {
@@ -1498,15 +2058,7 @@
 
 	if (!S_ISDIR(statb.st_mode)) {
 		/*
-		 * older iscsiadm versions had you create the config then set
-		 * set the tgpt. In new versions you must pass all the info in
-		 * from the start
-		 */
-		if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN)
-			/* drop down to old style portal as config */
-			goto open_conf;
-		/*
-		 * Old style portal as a file, but with tpgt. Let's update it.
+		 * Old style portal as a file. Let's update it.
 		 */
 		if (unlink(portal)) {
 			log_error("Could not convert %s. err %d\n", portal,
@@ -1542,17 +2094,17 @@
 		goto unlock;
 	}
 
-	idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f);
+	idbm_print(PRINT_TYPE_NODE, rec, 1, f);
 	fclose(f);
 unlock:
-	idbm_unlock();
+	idbm_unlock(db);
 free_portal:
 	free(portal);
 	return rc;
 }
 
 static int
-idbm_discovery_write(discovery_rec_t *rec)
+idbm_discovery_write(idbm_t *db, discovery_rec_t *rec)
 {
 	FILE *f;
 	char *portal;
@@ -1564,7 +2116,7 @@
 		return ENOMEM;
 	}
 
-	idbm_lock();
+	idbm_lock(db);
 	snprintf(portal, PATH_MAX, "%s", ST_CONFIG_DIR);
 	if (access(portal, F_OK) != 0) {
 		if (mkdir(portal, 0660) != 0) {
@@ -1584,21 +2136,21 @@
 		goto free_portal;
 	}
 
-	idbm_print(IDBM_PRINT_TYPE_DISCOVERY, rec, 1, f);
+	idbm_print(PRINT_TYPE_DISCOVERY, rec, 1, f);
 	fclose(f);
 free_portal:
-	idbm_unlock();
+	idbm_unlock(db);
 	free(portal);
 	return rc;
 }
 
 int
-idbm_add_discovery(discovery_rec_t *newrec, int overwrite)
+idbm_add_discovery(idbm_t *db, discovery_rec_t *newrec, int overwrite)
 {
 	discovery_rec_t rec;
 	int rc;
 
-	if (!idbm_discovery_read(&rec, newrec->address,
+	if (!idbm_discovery_read(db, &rec, newrec->address,
 				newrec->port)) {
 		if (!overwrite)
 			return 0;
@@ -1606,7 +2158,7 @@
 	} else
 		log_debug(7, "adding new DB record");
 
-	rc = idbm_discovery_write(newrec);
+	rc = idbm_discovery_write(db, newrec);
 	return rc;
 }
 
@@ -1659,19 +2211,20 @@
 	return rc;
 }
 
-int idbm_add_node(node_rec_t *newrec, discovery_rec_t *drec, int overwrite)
+int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec,
+		  int overwrite)
 {
 	node_rec_t rec;
 	char *node_portal, *disc_portal;
 	int rc;
 
-	if (!idbm_rec_read(&rec, newrec->name, newrec->tpgt,
+	if (!idbm_rec_read(db, &rec, newrec->name, newrec->tpgt,
 			   newrec->conn[0].address, newrec->conn[0].port,
 			   &newrec->iface)) {
 		if (!overwrite)
 			return 0;
 
-		rc = idbm_delete_node(&rec);
+		rc = idbm_delete_node(db, &rec);
 		if (rc)
 			return rc;
 		log_debug(7, "overwriting existing record");
@@ -1684,7 +2237,7 @@
 		strcpy(newrec->disc_address, drec->address);
 	}
 
-	rc = idbm_rec_write(newrec);
+	rc = idbm_rec_write(db, newrec);
 	/*
 	 * if a old app passed in a bogus tpgt then we do not create links
 	 * since it will set a different tpgt in another iscsiadm call
@@ -1707,7 +2260,7 @@
 	log_debug(7, "node addition making link from %s to %s", node_portal,
 		 disc_portal);
 
-	idbm_lock();
+	idbm_lock(db);
 	if (symlink(node_portal, disc_portal)) {
 		if (errno == EEXIST)
 			log_debug(7, "link from %s to %s exists", node_portal,
@@ -1718,7 +2271,7 @@
 				 "node %s", disc_portal, node_portal);
 		}
 	}
-	idbm_unlock();
+	idbm_unlock(db);
 free_portal:
 	free(node_portal);
 	return rc;
@@ -1741,7 +2294,8 @@
 	return 0;
 }
 
-int idbm_bind_ifaces_to_node(struct node_rec *new_rec, struct list_head *ifaces,
+int idbm_bind_ifaces_to_node(idbm_t *db, struct node_rec *new_rec,
+			     struct list_head *ifaces,
 			     struct list_head *bound_recs)
 {
 	struct iface_rec *iface, *tmp;
@@ -1752,17 +2306,12 @@
 		struct list_head def_ifaces;
 
 		INIT_LIST_HEAD(&def_ifaces);
-		iface_link_ifaces(&def_ifaces);
+		iface_link_ifaces(db, &def_ifaces);
 
 		list_for_each_entry_safe(iface, tmp, &def_ifaces, list) {
 			list_del(&iface->list);
-			t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
-			/*
-			 * only auto bind to software iscsi if it is
-			 * not the default iface (that is handled below)
-			 */
-			if (!t || strcmp(t->name, DEFAULT_TRANSPORT) ||
-			    !strcmp(iface->name, DEFAULT_IFACENAME)) {
+			t = get_transport_by_name(iface->transport_name);
+			if (!t || t->caps & CAP_FW_DB) {
 				free(iface);
 				continue;
 			}
@@ -1779,15 +2328,15 @@
 		if (!found) {
 			struct iface_rec def_iface;
 
-			iface_setup_defaults(&def_iface);
+			iface_init(&def_iface);
 			return idbm_bind_iface_to_node(new_rec, &def_iface,
 						       bound_recs);
 		}
 	} else {
 		list_for_each_entry(iface, ifaces, list) {
 			if (strcmp(iface->name, DEFAULT_IFACENAME) &&
-			    !iface_is_valid(iface)) {
-				log_error("iface %s is not valid. Will not "
+			    !iface_is_bound(iface)) {
+				log_error("iface %s is not bound. Will not "
 					  "bind node to it. Iface settings "
 					  iface_fmt, iface->name,
 					  iface_str(iface));
@@ -1806,7 +2355,7 @@
 /*
  * remove this when isns is converted
  */
-int idbm_add_nodes(node_rec_t *newrec, discovery_rec_t *drec,
+int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec,
 		   struct list_head *ifaces, int update)
 {
 	struct iface_rec *iface, *tmp;
@@ -1817,20 +2366,18 @@
 		struct list_head def_ifaces;
 
 		INIT_LIST_HEAD(&def_ifaces);
-		iface_link_ifaces(&def_ifaces);
+		iface_link_ifaces(db, &def_ifaces);
 
 		list_for_each_entry_safe(iface, tmp, &def_ifaces, list) {
 			list_del(&iface->list);
-			t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
-			/* only auto bind to software iscsi */
-			if (!t || strcmp(t->name, DEFAULT_TRANSPORT) ||
-			     !strcmp(iface->name, DEFAULT_IFACENAME)) {
+			t = get_transport_by_name(iface->transport_name);
+			if (!t || t->caps & CAP_FW_DB) {
 				free(iface);
 				continue;
 			}
 
 			iface_copy(&newrec->iface, iface);
-			rc = idbm_add_node(newrec, drec, update);
+			rc = idbm_add_node(db, newrec, drec, update);
 			free(iface);
 			if (rc)
 				return rc;
@@ -1839,14 +2386,14 @@
 
 		/* create default iface with old/default behavior */
 		if (!found) {
-			iface_setup_defaults(&newrec->iface);
-			return idbm_add_node(newrec, drec, update);
+			iface_init(&newrec->iface);
+			return idbm_add_node(db, newrec, drec, update);
 		}
 	} else {
 		list_for_each_entry(iface, ifaces, list) {
 			if (strcmp(iface->name, DEFAULT_IFACENAME) &&
-			    !iface_is_valid(iface)) {
-				log_error("iface %s is not valid. Will not "
+			    !iface_is_bound(iface)) {
+				log_error("iface %s is not bound. Will not "
 					  "bind node to it. Iface settings "
 					  iface_fmt, iface->name,
 					  iface_str(iface));
@@ -1854,7 +2401,7 @@
 			}
 
 			iface_copy(&newrec->iface, iface);
-			rc = idbm_add_node(newrec, drec, update);
+			rc = idbm_add_node(db, newrec, drec, update);
 			if (rc)
 				return rc;
 		}
@@ -1862,7 +2409,7 @@
 	return 0;
 }
 
-static void idbm_rm_disc_node_links(char *disc_dir)
+static void idbm_rm_disc_node_links(idbm_t *db, char *disc_dir)
 {
 	char *target = NULL, *tpgt = NULL, *port = NULL;
 	char *address = NULL, *iface_id = NULL;
@@ -1901,7 +2448,7 @@
 		strncpy(rec->conn[0].address, address, NI_MAXHOST);
 		strncpy(rec->iface.name, iface_id, ISCSI_MAX_IFACE_LEN);
 
-		if (idbm_delete_node(rec))
+		if (idbm_delete_node(db, rec))
 			log_error("Could not delete node %s/%s/%s,%s/%s",
 				  NODE_CONFIG_DIR, target, address, port,
 				  iface_id);
@@ -1912,7 +2459,7 @@
 	free(rec);
 }
 
-int idbm_delete_discovery(discovery_rec_t *drec)
+int idbm_delete_discovery(idbm_t *db, discovery_rec_t *drec)
 {
 	char *portal;
 	struct stat statb;
@@ -1943,7 +2490,7 @@
 	memset(portal, 0, PATH_MAX);
 	snprintf(portal, PATH_MAX, "%s/%s,%d", ST_CONFIG_DIR,
 		 drec->address, drec->port);
-	idbm_rm_disc_node_links(portal);
+	idbm_rm_disc_node_links(db, portal);
 
 	/* rm portal dir */
 	if (S_ISDIR(statb.st_mode)) {
@@ -1963,7 +2510,7 @@
  * if there is no link then this is pre svn 780 version where
  * we did not link the disc source and node
  */
-static int idbm_remove_disc_to_node_link(node_rec_t *rec,
+static int idbm_remove_disc_to_node_link(idbm_t *db, node_rec_t *rec,
 					 char *portal)
 {
 	int rc = 0;
@@ -1979,7 +2526,7 @@
 		 rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt,
 		 rec->iface.name);
 
-	rc = __idbm_rec_read(tmprec, portal);
+	rc = __idbm_rec_read(db, tmprec, portal);
 	if (rc) {
 		/* old style recs will not have tpgt or a link so skip */
 		rc = 0;
@@ -1994,7 +2541,7 @@
 	if (rc)
 		goto done;
 
-	idbm_lock();
+	idbm_lock(db);
 	if (!stat(portal, &statb)) {
 		if (unlink(portal)) {
 			log_error("Could not remove link %s err %d\n",
@@ -2004,14 +2551,14 @@
 			log_debug(7, "rmd %s", portal);
 	} else
 		log_debug(7, "Could not stat %s", portal);
-	idbm_unlock();
+	idbm_unlock(db);
 
 done:
 	free(tmprec);
 	return rc;
 }
 
-int idbm_delete_node(node_rec_t *rec)
+int idbm_delete_node(idbm_t *db, node_rec_t *rec)
 {
 	struct stat statb;
 	char *portal;
@@ -2021,7 +2568,7 @@
 	if (!portal)
 		return ENOMEM;
 
-	rc = idbm_remove_disc_to_node_link(rec, portal);
+	rc = idbm_remove_disc_to_node_link(db, rec, portal);
 	if (rc)
 		goto free_portal;
 
@@ -2031,7 +2578,7 @@
 	log_debug(5, "Removing config file %s iface id %s\n",
 		  portal, rec->iface.name);
 
-	idbm_lock();
+	idbm_lock(db);
 	if (!stat(portal, &statb))
 		goto rm_conf;
 
@@ -2084,28 +2631,28 @@
 		rmdir(portal);
 	}
 unlock:
-	idbm_unlock();
+	idbm_unlock(db);
 free_portal:
 	free(portal);
 	return rc;
 }
 
 void
-idbm_sendtargets_defaults(struct iscsi_sendtargets_config *cfg)
+idbm_sendtargets_defaults(idbm_t *db, struct iscsi_sendtargets_config *cfg)
 {
-	idbm_sync_config();
+	idbm_sync_config(db);
 	memcpy(cfg, &db->drec_st.u.sendtargets,
 	       sizeof(struct iscsi_sendtargets_config));
 }
 
 void
-idbm_slp_defaults(struct iscsi_slp_config *cfg)
+idbm_slp_defaults(idbm_t *db, struct iscsi_slp_config *cfg)
 {
 	memcpy(cfg, &db->drec_slp.u.slp,
 	       sizeof(struct iscsi_slp_config));
 }
 
-int idbm_node_set_param(void *data, node_rec_t *rec)
+int idbm_node_set_param(idbm_t *db, void *data, node_rec_t *rec)
 {
 	struct db_set_param *param = data;
 	recinfo_t *info;
@@ -2120,12 +2667,22 @@
 	rc = idbm_verify_param(info, param->name);
 	if (rc)
 		goto free_info;
-
-	rc = idbm_rec_update_param(info, param->name, param->value, 0);
+	/*
+	 * Another compat hack!!!!: in the future we will have a common
+	 * way to define node wide vs iface wide values and it will
+	 * nicely obey some hierd, but for now this one sits between both
+	 * and if someone tries to set it using the old values then
+	 * we update it for them.
+	 */
+	if (!strcmp("node.transport_name", param->name))
+		rc = idbm_rec_update_param(info, "iface.transport_name",
+					    param->value, 0);
+	else
+		rc = idbm_rec_update_param(info, param->name, param->value, 0);
 	if (rc)
 		goto free_info;
 
-	rc = idbm_rec_write(rec);
+	rc = idbm_rec_write(param->db, rec);
 	if (rc)
 		goto free_info;
 
@@ -2134,28 +2691,32 @@
 	return rc;
 }
 
-int idbm_init(idbm_get_config_file_fn *fn)
+idbm_t*
+idbm_init(idbm_get_config_file_fn *fn)
 {
+	idbm_t *db;
+
 	/* make sure root db dir is there */
 	if (access(ISCSI_CONFIG_ROOT, F_OK) != 0) {
 		if (mkdir(ISCSI_CONFIG_ROOT, 0660) != 0) {
 			log_error("Could not make %s %d\n", ISCSI_CONFIG_ROOT,
 				   errno);
-			return errno;
+			return NULL;
 		}
 	}
 
 	db = malloc(sizeof(idbm_t));
 	if (!db) {
 		log_error("out of memory on idbm allocation");
-		return ENOMEM;
+		return NULL;
 	}
 	memset(db, 0, sizeof(idbm_t));
 	db->get_config_file = fn;
-	return 0;
+	return db;
 }
 
-void idbm_terminate(void)
+void
+idbm_terminate(idbm_t *db)
 {
 	if (db)
 		free(db);
--- open-iscsi-2.0.870~rc3.orig/usr/idbm.h
+++ open-iscsi-2.0.870~rc3/usr/idbm.h
@@ -27,6 +27,7 @@
 #include "config.h"
 
 #define NODE_CONFIG_DIR		ISCSI_CONFIG_ROOT"nodes"
+#define IFACE_CONFIG_DIR	ISCSI_CONFIG_ROOT"ifaces"
 #define SLP_CONFIG_DIR		ISCSI_CONFIG_ROOT"slp"
 #define ISNS_CONFIG_DIR		ISCSI_CONFIG_ROOT"isns"
 #define STATIC_CONFIG_DIR	ISCSI_CONFIG_ROOT"static"
@@ -78,12 +79,13 @@
 struct db_set_param {
 	char *name;
 	char *value;
+	struct idbm *db;
 };
 
-typedef int (idbm_iface_op_fn)(void *data, node_rec_t *rec);
-typedef int (idbm_portal_op_fn)(int *found,  void *data,
+typedef int (idbm_iface_op_fn)(idbm_t *db, void *data, node_rec_t *rec);
+typedef int (idbm_portal_op_fn)(idbm_t *db,int *found,  void *data,
 				char *targetname, int tpgt, char *ip, int port);
-typedef int (idbm_node_op_fn)(int *found, void *data,
+typedef int (idbm_node_op_fn)(idbm_t *db, int *found, void *data,
 			      char *targetname);
 
 struct rec_op_data {
@@ -91,64 +93,81 @@
 	node_rec_t *match_rec;
 	idbm_iface_op_fn *fn;
 };
-extern int idbm_for_each_portal(int *found, void *data,
+extern int idbm_for_each_portal(idbm_t *db, int *found, void *data,
 				idbm_portal_op_fn *fn, char *targetname);
-extern int idbm_for_each_node(int *found, void *data,
+extern int idbm_for_each_node(idbm_t *db, int *found, void *data,
 			      idbm_node_op_fn *fn);
-extern int idbm_for_each_rec(int *found, void *data,
+extern int idbm_for_each_rec(idbm_t *db, int *found, void *data,
 			     idbm_iface_op_fn *fn);
 
 extern char* get_iscsi_initiatorname(char *pathname);
 extern char* get_iscsi_initiatoralias(char *pathname);
-extern int idbm_init(idbm_get_config_file_fn *fn);
+extern idbm_t *idbm_init(idbm_get_config_file_fn *fn);
 
-extern void idbm_node_setup_from_conf(node_rec_t *rec);
-extern void idbm_terminate(void);
-extern int idbm_print_iface_info(void *data, struct iface_rec *iface);
-extern int idbm_print_node_info(void *data, node_rec_t *rec);
-extern int idbm_print_node_flat(void *data, node_rec_t *rec);
-extern int idbm_print_node_tree(void *data, node_rec_t *rec);
-extern int idbm_print_discovery_info(discovery_rec_t *rec, int show);
-extern int idbm_print_all_discovery(int info_level);
-extern int idbm_print_discovered(discovery_rec_t *drec, int info_level);
-extern int idbm_delete_discovery(discovery_rec_t *rec);
+extern void idbm_node_setup_from_conf(idbm_t *db, node_rec_t *rec);
+extern void idbm_terminate(idbm_t *db);
+extern int idbm_print_iface_info(idbm_t *db, void *data,
+				 struct iface_rec *iface);
+extern int idbm_print_node_info(idbm_t *db, void *data, node_rec_t *rec);
+extern int idbm_print_node_flat(idbm_t *db, void *data, node_rec_t *rec);
+extern int idbm_print_node_tree(idbm_t *db, void *data, node_rec_t *rec);
+extern int idbm_print_discovery_info(idbm_t *db, discovery_rec_t *rec,
+				     int show);
+extern int idbm_print_all_discovery(idbm_t *db, int info_level);
+extern int idbm_print_discovered(idbm_t *db, discovery_rec_t *drec,
+				 int info_level);
+extern int idbm_delete_discovery(idbm_t *db, discovery_rec_t *rec);
 extern void idbm_node_setup_defaults(node_rec_t *rec);
-extern int idbm_delete_node(node_rec_t *rec);
-extern int idbm_add_node(node_rec_t *newrec, discovery_rec_t *drec,
+extern int idbm_delete_node(idbm_t *db, node_rec_t *rec);
+extern int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec,
 			 int overwrite);
 struct list_head;
-extern int idbm_bind_ifaces_to_node(struct node_rec *new_rec,
+extern int idbm_bind_ifaces_to_node(idbm_t *db, struct node_rec *new_rec,
 				    struct list_head *ifaces,
 				    struct list_head *bound_recs);
-extern int idbm_add_nodes(node_rec_t *newrec,
+extern int idbm_add_nodes(idbm_t *db, node_rec_t *newrec,
 			  discovery_rec_t *drec, struct list_head *ifaces,
 			  int overwrite);
-extern int idbm_add_discovery(discovery_rec_t *newrec, int overwrite);
-extern void idbm_sendtargets_defaults(struct iscsi_sendtargets_config *cfg);
-extern void idbm_slp_defaults(struct iscsi_slp_config *cfg);
-extern int idbm_discovery_read(discovery_rec_t *rec, char *addr,
+extern int idbm_add_discovery(idbm_t *db, discovery_rec_t *newrec,
+			      int overwrite);
+extern void idbm_sendtargets_defaults(idbm_t *db,
+		      struct iscsi_sendtargets_config *cfg);
+extern void idbm_slp_defaults(idbm_t *db, struct iscsi_slp_config *cfg);
+extern int idbm_discovery_read(idbm_t *db, discovery_rec_t *rec, char *addr,
 				int port);
-extern int idbm_rec_read(node_rec_t *out_rec, char *target_name,
+extern int idbm_rec_read(idbm_t *db, node_rec_t *out_rec, char *target_name,
 			 int tpgt, char *addr, int port,
 			 struct iface_rec *iface);
-extern int idbm_node_set_param(void *data, node_rec_t *rec);
+extern int idbm_node_set_param(idbm_t *db, void *data, node_rec_t *rec);
 
-/* lower level idbm functions for use by iface.c */
-extern void idbm_recinfo_config(recinfo_t *info, FILE *f);
-extern void idbm_recinfo_iface(struct iface_rec *r, recinfo_t *ri);
-extern int idbm_lock(void);
-extern void idbm_unlock(void);
-extern recinfo_t *idbm_recinfo_alloc(int max_keys);
-extern int idbm_verify_param(recinfo_t *info, char *name);
-extern int idbm_rec_update_param(recinfo_t *info, char *name, char *value,
-				 int line_number);
-
-enum {
-	IDBM_PRINT_TYPE_DISCOVERY,
-	IDBM_PRINT_TYPE_NODE,
-	IDBM_PRINT_TYPE_IFACE,
-};
-
-extern void idbm_print(int type, void *rec, int show, FILE *f);
+/* TODO: seperate iface, node and core idbm code */
+extern int iface_id_is_mac(char *iface_id);
+extern void iface_copy(struct iface_rec *dst, struct iface_rec *src);
+extern int iface_is_bound(struct iface_rec *iface);
+extern int iface_match_bind_info(struct iface_rec *pattern,
+				  struct iface_rec *iface);
+extern struct iface_rec *iface_alloc(char *ifname, int *err);
+extern int iface_conf_read(idbm_t *db, struct iface_rec *iface);
+extern void iface_init(struct iface_rec *iface);
+extern int iface_is_bound_by_hwaddr(struct iface_rec *iface);
+extern int iface_is_bound_by_netdev(struct iface_rec *iface);
+extern int iface_is_bound_by_ipaddr(struct iface_rec *iface);
+typedef int (iface_op_fn)(void *data, struct iface_rec *iface);
+extern int iface_for_each_iface(idbm_t *db, void *data, int *nr_found,
+				 iface_op_fn *fn);
+extern int iface_print_flat(void *data, struct iface_rec *iface);
+extern int iface_print_tree(void *data, struct iface_rec *iface);
+extern void iface_setup_host_bindings(idbm_t *db);
+extern int iface_get_by_bind_info(idbm_t *db, struct iface_rec *pattern,
+				 struct iface_rec *out_rec);
+extern int iface_conf_update(idbm_t *db, struct db_set_param *set_param,
+			     struct iface_rec *iface);
+extern int iface_conf_write(idbm_t *db, struct iface_rec *iface);
+extern int iface_conf_delete(idbm_t *db, struct iface_rec *iface);
+
+#define iface_fmt "[hw=%s,ip=%s,net_if=%s,iscsi_if=%s]"
+#define iface_str(_iface) \
+	(_iface)->hwaddress, (_iface)->ipaddress, (_iface)->netdev, \
+	(_iface)->name
 
 #endif /* IDBM_H */
--- open-iscsi-2.0.870~rc3.orig/usr/initiator.c
+++ open-iscsi-2.0.870~rc3/usr/initiator.c
@@ -24,7 +24,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
-#include <sys/time.h>
 
 #include "initiator.h"
 #include "transport.h"
@@ -135,8 +134,8 @@
 
 static void session_online_devs(int host_no, int sid)
 {
-	iscsi_sysfs_for_each_device(host_no, sid,
-				    iscsi_sysfs_set_device_online);
+	sysfs_for_each_device(host_no, sid,
+			      set_device_online);
 }
 
 static conn_login_status_e
@@ -420,14 +419,7 @@
 
 	conn->state = STATE_FREE;
 	conn->session = session;
-	/*
-	 * TODO: we must export the socket_fd/transport_eph from sysfs
-	 * so if iscsid is resyncing up we can pick that up and cleanup up
-	 * the old connection. Right now we leak a connection.
-	 * We can also probably merge these two fields.
-	 */
 	conn->socket_fd = -1;
-	conn->transport_ep_handle = -1;
 	/* connection's timeouts */
 	conn->id = cid;
 	conn->logout_timeout = conn_rec->timeo.logout_timeout;
@@ -554,16 +546,16 @@
 	/* setup authentication variables for the session*/
 	__setup_authentication(session, &rec->session.auth);
 
-	session->param_mask = ~0ULL;
+	session->param_mask = 0xFFFFFFFF;
 	if (!(t->caps & CAP_MULTI_R2T))
-		session->param_mask &= ~ISCSI_MAX_R2T;
+		session->param_mask &= ~(1 << ISCSI_PARAM_MAX_R2T);
 	if (!(t->caps & CAP_HDRDGST))
-		session->param_mask &= ~ISCSI_HDRDGST_EN;
+		session->param_mask &= ~(1 << ISCSI_PARAM_HDRDGST_EN);
 	if (!(t->caps & CAP_DATADGST))
-		session->param_mask &= ~ISCSI_DATADGST_EN;
+		session->param_mask &= ~(1 << ISCSI_PARAM_DATADGST_EN);
 	if (!(t->caps & CAP_MARKERS)) {
-		session->param_mask &= ~ISCSI_IFMARKER_EN;
-		session->param_mask &= ~ISCSI_OFMARKER_EN;
+		session->param_mask &= ~(1 << ISCSI_PARAM_IFMARKER_EN);
+		session->param_mask &= ~(1 << ISCSI_PARAM_OFMARKER_EN);
 	}
 
 	list_add_tail(&session->list, &t->sessions);
@@ -610,15 +602,11 @@
 {
 	iscsi_session_t *session = conn->session;
 
-	log_debug(2, "disconnect conn");
-	/* this will check for a valid interconnect connection */
-	conn->session->t->template->ep_disconnect(conn);
-
 	if (session->id == -1)
-		goto cleanup;
+		goto disconnect_conn;
 
-	if (!iscsi_sysfs_session_has_leadconn(session->id))
-		goto cleanup;
+	if (!sysfs_session_has_leadconn(session->id))
+		goto disconnect_conn;
 
 	if (conn->state == STATE_IN_LOGIN ||
 	    conn->state == STATE_IN_LOGOUT ||
@@ -639,7 +627,11 @@
 		return MGMT_IPC_ERR_INTERNAL;
 	}
 
-cleanup:
+disconnect_conn:
+	log_debug(2, "disconnect conn");
+	/* this will check for a valid interconnect connection */
+	conn->session->t->template->ep_disconnect(conn);
+
 	if (session->id != -1) {
 		log_debug(2, "kdestroy session %u", session->id);
 		if (ipc->destroy_session(session->t->handle, session->id)) {
@@ -694,8 +686,8 @@
 			    conn->host, sizeof(conn->host), serv, sizeof(serv),
 			    NI_NUMERICHOST|NI_NUMERICSERV);
 
-		log_error("cannot make a connection to %s:%s (%d,%d)",
-			  conn->host, serv, rc, errno);
+		log_error("cannot make a connection to %s:%s (%d)",
+			  conn->host, serv, errno);
 		iscsi_conn_context_put(conn_context);
 		return ENOTCONN;
 	}
@@ -725,7 +717,6 @@
 	conn_delete_timers(conn);
 	conn->state = STATE_XPT_WAIT;
 
-	conn->session->t->template->ep_disconnect(conn);
 	if (do_stop) {
 		/* state: STATE_CLEANUP_WAIT */
 		if (ipc->stop_conn(session->t->handle, session->id,
@@ -738,6 +729,7 @@
 		log_debug(3, "connection %d:%d is stopped for recovery",
 			  session->id, conn->id);
 	}
+	conn->session->t->template->ep_disconnect(conn);
 
 	if (!redirected) {
 		delay = session->def_time2wait;
@@ -774,45 +766,13 @@
 	__session_conn_reopen(conn, qtask, do_stop, 0);
 }
 
-static int iscsi_retry_initial_login(struct iscsi_conn *conn)
-{
-	int initial_login_retry_max;
-	struct timeval now, timeout, fail_time;
-
-	initial_login_retry_max =
-			conn->session->nrec.session.initial_login_retry_max;
-
-	memset(&now, 0, sizeof(now));
-	memset(&timeout, 0, sizeof(timeout));
-	memset(&fail_time, 0, sizeof(fail_time));
-
-	timeout.tv_sec = initial_login_retry_max * conn->login_timeout;
-	if (gettimeofday(&now, NULL)) {
-		log_error("Could not get time of day. Dropping down to "
-			  "max retry check.\n");
-		return initial_login_retry_max > conn->session->reopen_cnt;
-	}
-	timeradd(&conn->initial_connect_time, &timeout, &fail_time);
-
-	/*
-	 * if we have been trying for login_retry_max * login_timeout
-	 * then it is time to give up
-	 */
-	if (timercmp(&now, &fail_time, >)) {
-		log_debug(1, "Giving up on initial login attempt after "
-			  "%u seconds.\n",
-			  initial_login_retry_max * conn->login_timeout);
-		return 0;
-	}
-
-	return 1;
-}
-
 static void iscsi_login_eh(struct iscsi_conn *conn, struct queue_task *qtask,
 			   mgmt_ipc_err_e err)
 {
 	struct iscsi_session *session = conn->session;
+	int initial_login_retry_max;
 
+	initial_login_retry_max = session->nrec.session.initial_login_retry_max;
 	log_debug(3, "iscsi_login_eh");
 	/*
 	 * Flush polls and other events
@@ -824,10 +784,12 @@
 		switch (session->r_stage) {
 		case R_STAGE_NO_CHANGE:
 			log_debug(6, "login failed STATE_XPT_WAIT/"
-				  "R_STAGE_NO_CHANGE");
+				  "R_STAGE_NO_CHANGE (%d/%d)",
+				  session->reopen_cnt,
+				  initial_login_retry_max);
 			/* timeout during initial connect.
 			 * clean connection. write ipc rsp or retry */
-			if (!iscsi_retry_initial_login(conn))
+			if (initial_login_retry_max < session->reopen_cnt + 1)
 				session_conn_shutdown(conn, qtask, err);
 			else {
 				session->reopen_cnt++;
@@ -839,10 +801,12 @@
 			break;
 		case R_STAGE_SESSION_REDIRECT:
 			log_debug(6, "login failed STATE_XPT_WAIT/"
-				  "R_STAGE_SESSION_REDIRECT");
+				  "R_STAGE_SESSION_REDIRECT (%d/%d)",
+				  session->reopen_cnt,
+				  initial_login_retry_max);
 			/* timeout during initial redirect connect
 			 * clean connection. write ipc rsp or retry */
-			if (!iscsi_retry_initial_login(conn))
+			if (initial_login_retry_max < session->reopen_cnt + 1)
 				session_conn_shutdown(conn, qtask, err);
 			else
 				session_conn_reopen(conn, qtask, 0);
@@ -874,7 +838,7 @@
 			 * initial redirected connect. Clean connection
 			 * and write rsp or retry.
 			 */
-			if (!iscsi_retry_initial_login(conn))
+			if (initial_login_retry_max < session->reopen_cnt + 1)
 				session_conn_shutdown(conn, qtask, err);
 			else
 				session_conn_reopen(conn, qtask,
@@ -995,15 +959,7 @@
 		    "state (%d)", session->id, conn->id, error,
 		    conn->state);
 	iscsi_conn_context_put(conn_context);
-
-	switch (error) {
-	case ISCSI_ERR_INVALID_HOST:
-		if (session_conn_shutdown(conn, NULL, MGMT_IPC_OK))
-			log_error("BUG: Could not shutdown session.");
-		break;
-	default:
-		__conn_error_handle(session, conn);
-	}
+	__conn_error_handle(session, conn);
 }
 
 static void iscsi_login_timedout(void *data)
@@ -1133,7 +1089,7 @@
 {
 	pid_t pid;
 
-	pid = iscsi_sysfs_scan_host(hostno, 1);
+	pid = scan_host(hostno, 1);
 	if (pid == 0) {
 		mgmt_ipc_write_rsp(qtask, MGMT_IPC_OK);
 		exit(0);
@@ -1168,7 +1124,7 @@
 {
 	struct iscsi_transport *t;
 
-	t = iscsi_sysfs_get_transport_by_hba(host_no);
+	t = get_transport_by_hba(host_no);
 	if (!t)
 		return MGMT_IPC_ERR_TRANS_FAILURE;
 	if (__iscsi_host_set_param(t, host_no, param, value, ISCSI_STRING))
@@ -1176,7 +1132,7 @@
         return MGMT_IPC_OK;
 }
 
-#define MAX_SESSION_PARAMS 30
+#define MAX_SESSION_PARAMS 29
 #define MAX_HOST_PARAMS 3
 
 static void
@@ -1356,10 +1312,6 @@
 			.value = &conn->noop_out_interval,
 			.type = ISCSI_INT,
 			.conn_only = 1,
-		}, {
-			.param = ISCSI_PARAM_IFACE_NAME,
-			.value = session->nrec.iface.name,
-			.type = ISCSI_STRING,
 		},
 	};
 
@@ -1368,8 +1320,7 @@
 	for (i = 0; i < MAX_SESSION_PARAMS; i++) {
 		if (conn->id != 0 && !conntbl[i].conn_only)
 			continue;
-		
-		if (!(session->param_mask & (1ULL << conntbl[i].param)))
+		if (!(session->param_mask & (1 << conntbl[i].param)))
 			continue;
 
 		rc = ipc->set_param(session->t->handle, session->id,
@@ -1656,13 +1607,8 @@
 
 	return;
 retry:
-	/*
-	 * If this is not the initial login attempt force a retry. If this
-	 * is the initial attempt we follow the login_retry count.
-	 */
-	if (session->r_stage != R_STAGE_NO_CHANGE &&
-	    session->r_stage != R_STAGE_SESSION_REDIRECT)
-		session->r_stage = R_STAGE_SESSION_REOPEN;
+	/* force retry */
+	session->r_stage = R_STAGE_SESSION_REOPEN;
 	iscsi_login_eh(conn, c->qtask, MGMT_IPC_ERR_LOGIN_FAILURE);
 	return;
 failed:
@@ -1726,37 +1672,6 @@
 	}
 }
 
-static int session_ipc_create(struct iscsi_session *session)
-{
-	struct iscsi_conn *conn = &session->conn[0];
-	int err = 0, pass_ep = 1;
-	uint32_t host_no = -1;
-
-	if (session->t->template->ep_connect != ktransport_ep_connect)
-		pass_ep = 0;
-retry_create:
-	err = ipc->create_session(session->t->handle,
-				  pass_ep ? conn->transport_ep_handle : 0,
-				  session->nrec.session.initial_cmdsn,
-				  session->nrec.session.cmds_max,
-				  session->nrec.session.queue_depth,
-				  &session->id, &host_no);
-	/*
-	 * Older kernels were not passed the sessions's leading conn ep,
-	 * so we will get -EINVAL || -ENOSYS for iser.
-	 *
-	 * 2.6.22 and earlier would send -EINVAL instead of -ENOSYS.
-	 */
-	if (pass_ep && (err == -ENOSYS || err == -EINVAL)) {
-		pass_ep = 0;
-		goto retry_create;
-	}
-
-	if (!err)
-		session->hostno = host_no;
-	return err;
-}
-
 static void session_conn_poll(void *data)
 {
 	struct iscsi_conn_context *conn_context = data;
@@ -1792,13 +1707,18 @@
 
 		/* do not allocate new connection in case of reopen */
 		if (session->id == -1) {
-			if (conn->id == 0 && session_ipc_create(session)) {
+			if (conn->id == 0 &&
+			    ipc->create_session(session->t->handle,
+					session->nrec.session.initial_cmdsn,
+					session->nrec.session.cmds_max,
+					session->nrec.session.queue_depth,
+					&session->id, &session->hostno)) {
 				log_error("can't create session (%d)", errno);
 				err = MGMT_IPC_ERR_INTERNAL;
 				goto cleanup;
 			}
-			log_debug(3, "created new iSCSI session sid %d host "
-				  "no %u", session->id, session->hostno);
+			log_debug(3, "created new iSCSI session %d",
+				  session->id);
 
 			if (ipc->create_conn(session->t->handle,
 					session->id, conn->id, &conn->id)) {
@@ -1835,7 +1755,7 @@
 		c->buffer = conn->data;
 		c->bufsize = sizeof(conn->data);
 
-		conn->exp_statsn = iscsi_sysfs_get_exp_statsn(session->id);
+		set_exp_statsn(conn);
 
 		if (iscsi_login_begin(session, c)) {
 			iscsi_login_eh(conn, qtask, MGMT_IPC_ERR_LOGIN_FAILURE);
@@ -1912,7 +1832,8 @@
 	return NULL;
 }
 
-static iscsi_session_t* session_find_by_rec(node_rec_t *rec)
+iscsi_session_t*
+session_find_by_rec(node_rec_t *rec)
 {
 	struct iscsi_transport *t;
 	iscsi_session_t *session;
@@ -1940,7 +1861,7 @@
 	if (session_find_by_rec(rec))
 		return 1;
 
-	if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session))
+	if (sysfs_for_each_session(rec, &nr_found, iscsi_match_session))
 		return 1;
 
 	return 0;
@@ -1953,13 +1874,7 @@
 	iscsi_conn_t *conn;
 	struct iscsi_transport *t;
 
-	if (session_is_running(rec)) {
-		log_error("session [%s,%s,%d] already running.", rec->name,
-			  rec->conn[0].address, rec->conn[0].port);
-		return MGMT_IPC_ERR_EXISTS;
-	}
-
-	t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name);
+	t = get_transport_by_name(rec->iface.transport_name);
 	if (!t)
 		return MGMT_IPC_ERR_TRANS_NOT_FOUND;
 	if (set_transport_template(t))
@@ -1969,49 +1884,45 @@
 	     rec->session.iscsi.ERL != 0) ||
 	    (!(t->caps & CAP_RECOVERY_L1) &&
 	     rec->session.iscsi.ERL > 1)) {
-		log_error("Transport '%s' does not support ERL %d."
-			  "Setting ERL to ERL0.\n",
+		log_error("transport '%s' does not support ERL %d",
 			  t->name, rec->session.iscsi.ERL);
-		rec->session.iscsi.ERL = 0;
+		return MGMT_IPC_ERR_TRANS_CAPS;
 	}
 
 	if (!(t->caps & CAP_MULTI_R2T) &&
 	    rec->session.iscsi.MaxOutstandingR2T) {
-		log_error("Transport '%s' does not support "
-			  "MaxOutstandingR2T %d. Setting "
-			  "MaxOutstandingR2T to 1.", t->name,
+		log_error("transport '%s' does not support "
+			  "MaxOutstandingR2T %d", t->name,
 			  rec->session.iscsi.MaxOutstandingR2T);
-		rec->session.iscsi.MaxOutstandingR2T = 1;		
+		return MGMT_IPC_ERR_TRANS_CAPS;
 	}
 
 	if (!(t->caps & CAP_HDRDGST) &&
 	    rec->conn[0].iscsi.HeaderDigest) {
-		log_error("Transport '%s' does not support "
-			  "HeaderDigest != None. Setting HeaderDigest "
-			  "to None.", t->name);
-		rec->conn[0].iscsi.HeaderDigest = CONFIG_DIGEST_NEVER;
+		log_error("transport '%s' does not support "
+			  "HeaderDigest != None", t->name);
+		return MGMT_IPC_ERR_TRANS_CAPS;
 	}
 
 	if (!(t->caps & CAP_DATADGST) &&
 	    rec->conn[0].iscsi.DataDigest) {
-		log_error("Transport '%s' does not support "
-			  "DataDigest != None. Setting DataDigest "
-			  "to None", t->name);
-		rec->conn[0].iscsi.DataDigest = CONFIG_DIGEST_NEVER;
+		log_error("transport '%s' does not support "
+			  "DataDigest != None", t->name);
+		return MGMT_IPC_ERR_TRANS_CAPS;
 	}
 
 	if (!(t->caps & CAP_MARKERS) &&
 	    rec->conn[0].iscsi.IFMarker) {
-		log_error("Transport '%s' does not support IFMarker. "
-			  "Disabling IFMarkers.\n", t->name);
-		rec->conn[0].iscsi.IFMarker = 0;
+		log_error("transport '%s' does not support IFMarker",
+			  t->name);
+		return MGMT_IPC_ERR_TRANS_CAPS;
 	}
 
 	if (!(t->caps & CAP_MARKERS) &&
 	    rec->conn[0].iscsi.OFMarker) {
-		log_error("Transport '%s' does not support OFMarker.",
-			  "Disabling OFMarkers.\n", t->name);
-		rec->conn[0].iscsi.OFMarker = 0;
+		log_error("transport '%s' does not support OFMarker",
+			  t->name);
+		return MGMT_IPC_ERR_TRANS_CAPS;
 	}
 
 	session = __session_create(rec, t);
@@ -2034,11 +1945,6 @@
 		return MGMT_IPC_ERR_TRANS_FAILURE;
 	}
 
-	if (gettimeofday(&conn->initial_connect_time, NULL))
-		log_error("Could not get initial connect time. If "
-			  "login errors iscsid may give up the initial "
-			  "login early. You should manually login.");
-
 	qtask->rsp.command = MGMT_IPC_SESSION_LOGIN;
 	qtask->rsp.err = MGMT_IPC_OK;
 	return MGMT_IPC_OK;
@@ -2065,7 +1971,7 @@
 	struct iscsi_transport *t;
 	int err;
 
-	t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name);
+	t = get_transport_by_name(rec->iface.transport_name);
 	if (!t)
 		return MGMT_IPC_ERR_TRANS_NOT_FOUND;
 	if (set_transport_template(t))
@@ -2076,7 +1982,7 @@
 		return MGMT_IPC_ERR_LOGIN_FAILURE;
 
 	session->id = sid;
-	session->hostno = iscsi_sysfs_get_host_no_from_sid(sid, &err);
+	session->hostno = get_host_no_from_sid(sid, &err);
 	if (err) {
 		log_error("Could not get hostno for session %d\n", sid);
 		err = MGMT_IPC_ERR_NOT_FOUND;
@@ -2119,17 +2025,11 @@
 }
 
 int
-session_logout_task(int sid, queue_task_t *qtask)
+session_logout_task(iscsi_session_t *session, queue_task_t *qtask)
 {
-	iscsi_session_t *session;
 	iscsi_conn_t *conn;
 	mgmt_ipc_err_e rc = MGMT_IPC_OK;
 
-	session = session_find_by_sid(sid);
-	if (!session) {
-                log_debug(1, "session sid %d not found.\n", sid);
-		return MGMT_IPC_ERR_NOT_FOUND;
-	}
 	conn = &session->conn[0];
 	/*
 	 * If syncing up or if this is the initial login and mgmt_ipc
@@ -2180,7 +2080,7 @@
 {
 	struct iscsi_transport *t;
 
-	t = iscsi_sysfs_get_transport_by_hba(host_no);
+	t = get_transport_by_hba(host_no);
 	if (!t || set_transport_template(t)) {
 		log_error("Invalid host no %d for sendtargets\n", host_no);
 		return MGMT_IPC_ERR_TRANS_FAILURE;
@@ -2205,7 +2105,7 @@
 {
 	struct iscsi_transport *transport;
 
-	transport = iscsi_sysfs_get_transport_by_hba(host_no);
+	transport = get_transport_by_hba(host_no);
 	if (!transport)
 		return;
 
--- open-iscsi-2.0.870~rc3.orig/usr/initiator.h
+++ open-iscsi-2.0.870~rc3/usr/initiator.h
@@ -22,7 +22,6 @@
 
 #include <stdint.h>
 #include <net/if.h>
-#include <sys/time.h>
 
 #include "types.h"
 #include "iscsi_proto.h"
@@ -126,7 +125,6 @@
 	iscsi_conn_state_e state;
 	int userspace_nop;
 
-	struct timeval initial_connect_time;
 	actor_t login_timer;
 	actor_t nop_out_timer;
 
@@ -242,7 +240,7 @@
 	int password_in_length;
 	iscsi_conn_t conn[ISCSI_CONN_MAX];
 	int ctrl_fd;
-	uint64_t param_mask;
+	uint32_t param_mask;
 
 	/* connection reopens during recovery */
 	int reopen_cnt;
@@ -327,8 +325,10 @@
 
 /* initiator.c */
 extern int session_login_task(node_rec_t *rec, queue_task_t *qtask);
-extern int session_logout_task(int sid, queue_task_t *qtask);
+extern int session_logout_task(iscsi_session_t *session, queue_task_t *qtask);
 extern iscsi_session_t *session_find_by_sid(int sid);
+extern iscsi_session_t *session_find_by_rec(node_rec_t *rec);
+extern int session_is_running(node_rec_t *rec);
 extern struct iscsi_conn_context *iscsi_conn_context_get(iscsi_conn_t *conn,
 						   int ev_size);
 extern void iscsi_conn_context_put(struct iscsi_conn_context *conn_context);
--- open-iscsi-2.0.870~rc3.orig/usr/io.c
+++ open-iscsi-2.0.870~rc3/usr/io.c
@@ -36,7 +36,6 @@
 #include "log.h"
 #include "transport.h"
 #include "idbm.h"
-#include "iface.h"
 
 #define LOG_CONN_CLOSED(conn) \
 do { \
--- open-iscsi-2.0.870~rc3.orig/usr/iscsi_ipc.h
+++ open-iscsi-2.0.870~rc3/usr/iscsi_ipc.h
@@ -55,10 +55,10 @@
 	int (*sendtargets) (uint64_t transport_handle, uint32_t host_no,
 			    struct sockaddr *addr);
 
-	int (*create_session) (uint64_t transport_handle, uint64_t ep_handle,
+	int (*create_session) (uint64_t transport_handle,
 			       uint32_t initial_cmdsn, uint16_t cmds_max,
 			       uint16_t qdepth, uint32_t *out_sid,
-			       uint32_t *hostno);
+			       uint32_t *out_hostno);
 
 	int (*destroy_session) (uint64_t transport_handle, uint32_t sid);
 
--- open-iscsi-2.0.870~rc3.orig/usr/iscsi_sysfs.c
+++ open-iscsi-2.0.870~rc3/usr/iscsi_sysfs.c
@@ -26,177 +26,30 @@
 #include "log.h"
 #include "initiator.h"
 #include "transport.h"
-#include "idbm.h"
 #include "version.h"
 #include "iscsi_sysfs.h"
-#include "sysdeps.h"
 #include "iscsi_settings.h"
-#include "iface.h"
 
-/*
- * TODO: remove the _DIR defines and search for subsys dirs like
- *  is done in sysfs.c.
- */
 #define ISCSI_TRANSPORT_DIR	"/sys/class/iscsi_transport"
 #define ISCSI_SESSION_DIR	"/sys/class/iscsi_session"
+#define ISCSI_CONN_DIR		"/sys/class/iscsi_connection"
 #define ISCSI_HOST_DIR		"/sys/class/iscsi_host"
-
-#define ISCSI_SYSFS_INVALID_VALUE	"<NULL>"
-#define ISCSI_SESSION_SUBSYS		"iscsi_session"
-#define ISCSI_CONN_SUBSYS		"iscsi_connection"
-#define ISCSI_HOST_SUBSYS		"iscsi_host"
-#define ISCSI_TRANSPORT_SUBSYS		"iscsi_transport"
-#define SCSI_HOST_SUBSYS		"scsi_host"
-#define SCSI_DEVICE_SUBSYS		"scsi_device"
-#define SCSI_SUBSYS			"scsi"
+#define SCSI_HOST_DIR		"/sys/class/scsi_host"
+#define SCSI_DEVICE_DIR		"/sys/bus/scsi/devices"
 
 #define ISCSI_MAX_SYSFS_BUFFER NI_MAXHOST
 
 /*
  * TODO: make this into a real API and check inputs better and add doc.
+ * We should also use a common lib and search sysfs according to the sysfs
+ * doc in the kernel documetnation.
  */
 
-static int num_transports;
+/* tmp buffer used by sysfs functions */
+static char sysfs_file[PATH_MAX];
+int num_transports = 0;
 LIST_HEAD(transports);
 
-static int iscsi_sysfs_get_param(char *id, char *subsys, char *param,
-				 void *ret_value, char *format)
-{
-	char devpath[PATH_SIZE];
-	char *sysfs_value;
-
-	/* set to invalid */
-	if (!strcmp(format, "%s\n"))
-		((char *)ret_value)[0] = '\0';
-	else
-		*((int *)ret_value) = -1;
-
-	if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
-					       subsys, id)) {
-		log_debug(3, "Could not lookup devpath for %s %s\n",
-			  subsys, id);
-		return EIO;
-	}
-
-	sysfs_value = sysfs_attr_get_value(devpath, param);
-	if (!sysfs_value) {
-		log_debug(3, "Could not read attr %s on path %s\n",
-			  param, devpath);
-		return EIO;
-	}
-
-	if (!strncmp(sysfs_value, ISCSI_SYSFS_INVALID_VALUE, 6))
-		return ENODATA;
-
-	sscanf(sysfs_value, format, ret_value);
-	return 0;
-}
-
-#define iscsi_sysfs_get_param_by_str(name, subsys)			\
-static int iscsi_sysfs_get_##name##_param(char *tag, char *param,	\
-					  void *ret_value,		\
-					  char *format)			\
-{									\
-	char id[NAME_SIZE];						\
-									\
-	snprintf(id, sizeof(id), "%s", tag);				\
-	return iscsi_sysfs_get_param(id, subsys, param, ret_value, format);\
-}
-
-#define iscsi_sysfs_get_param_by_int(name, id_format, subsys)		\
-static int iscsi_sysfs_get_##name##_param(int tag, char *param,		\
-					  void *ret_value,		\
-					  char *format)			\
-{									\
-	char id[NAME_SIZE];						\
-									\
-	snprintf(id, sizeof(id), id_format, tag);			\
-	return iscsi_sysfs_get_param(id, subsys, param, ret_value, format);\
-}
-
-iscsi_sysfs_get_param_by_int(session, "session%d", ISCSI_SESSION_SUBSYS);
-iscsi_sysfs_get_param_by_int(conn, "connection%d:0", ISCSI_CONN_SUBSYS);
-iscsi_sysfs_get_param_by_int(iscsi_host, "host%d", ISCSI_HOST_SUBSYS);
-iscsi_sysfs_get_param_by_int(scsi_host, "host%d", SCSI_HOST_SUBSYS);
-
-iscsi_sysfs_get_param_by_str(transport, ISCSI_TRANSPORT_SUBSYS);
-iscsi_sysfs_get_param_by_str(scsi_dev, SCSI_SUBSYS);
-
-static int iscsi_sysfs_set_param(char *id, char *subsys, char *attr_name,
-				 char *write_buf, ssize_t buf_size)
-{
-	struct stat statbuf;
-	char devpath[PATH_SIZE];
-	size_t sysfs_len;
-	char path_full[PATH_SIZE];
-	const char *path;
-	int rc = 0, fd;
-
-	if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
-					       subsys, id)) {
-		log_debug(3, "Could not lookup devpath for %s %s\n",
-			  subsys, id);
-		return EIO;
-	}
-
-	sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
-	if(sysfs_len >= sizeof(path_full))
-		sysfs_len = sizeof(path_full) - 1;
-	path = &path_full[sysfs_len];
-	strlcat(path_full, devpath, sizeof(path_full));
-	strlcat(path_full, "/", sizeof(path_full));
-	strlcat(path_full, attr_name, sizeof(path_full));
-
-	if (lstat(path_full, &statbuf)) {
-		log_debug(3, "Could not stat %s\n", path_full);
-		return errno;
-	}
-
-	if ((statbuf.st_mode & S_IWUSR) == 0) {
-		log_error("Could not write to %s. Invalid permissions.\n",
-			  path_full);
-		return EACCES;
-	}
-
-	fd = open(path_full, O_WRONLY);
-	if (fd < 0) {
-		log_error("Could not open %s err %d\n", path_full, errno);
-		return errno;
-	}
-
-	if (write(fd, write_buf, buf_size) == -1)
-		rc = errno;
-	close(fd);
-	return rc;
-}
-
-#define iscsi_sysfs_set_param_by_str(name, subsys)			\
-static int iscsi_sysfs_set_##name##_param(char *tag, char *attr_name,	\
-					  char *write_buf,		\
-					  ssize_t buf_size)		\
-{									\
-	char id[NAME_SIZE];						\
-									\
-	snprintf(id, sizeof(id), "%s", tag);				\
-	return iscsi_sysfs_set_param(id, subsys, attr_name, write_buf,	\
-				     buf_size);				\
-}
-
-#define iscsi_sysfs_set_param_by_int(name, id_format, subsys)		\
-static int iscsi_sysfs_set_##name##_param(int tag, char *attr_name,	\
-					  char *write_buf,		\
-					  ssize_t buf_size)		\
-{									\
-	char id[NAME_SIZE];						\
-									\
-	snprintf(id, sizeof(id), id_format, tag);			\
-	return iscsi_sysfs_set_param(id, subsys, attr_name, write_buf,	\
-				     buf_size);				\
-}
-
-iscsi_sysfs_set_param_by_int(scsi_host, "host%d", SCSI_HOST_SUBSYS);
-iscsi_sysfs_set_param_by_str(scsi_dev, SCSI_SUBSYS);
-
 /* mini implementation of versionsort for uclibc compatility */
 int direntcmp(const void *d1, const void *d2)
 {
@@ -221,6 +74,29 @@
 	return *a - *b;
 }
 
+int read_sysfs_file(char *filename, void *value, char *format)
+{
+	FILE *file;
+	char buffer[ISCSI_MAX_SYSFS_BUFFER + 1], *line;
+	int err = 0;
+
+	file = fopen(filename, "r");
+	if (file) {
+		line = fgets(buffer, sizeof(buffer), file);
+		if (line && strncmp(line, "<NULL>", 6))
+			sscanf(buffer, format, value);
+		else {
+			log_debug(5, "Could not read %s.\n", filename);
+			err = ENODATA;
+		}
+		fclose(file);
+	} else {
+		log_debug(5, "Could not open %s.\n", filename);
+		err = errno;
+	}
+	return err;
+}
+
 void free_transports(void)
 {
 	struct iscsi_transport *t, *tmp;
@@ -239,7 +115,8 @@
 static int read_transports(void)
 {
 	struct dirent **namelist;
-	int i, n, found;
+	char filename[64];
+	int i, n, found, err = 0;
 	struct iscsi_transport *t;
 
 	log_debug(7, "in %s", __FUNCTION__);
@@ -275,13 +152,16 @@
 		strncpy(t->name, namelist[i]->d_name,
 			ISCSI_TRANSPORT_NAME_MAXLEN);
 
-		if (iscsi_sysfs_get_transport_param(t->name, "handle",
-						    &t->handle, "%llu\n"))
+		sprintf(filename, ISCSI_TRANSPORT_DIR"/%s/handle", t->name);
+		err = read_sysfs_file(filename, &t->handle, "%llu\n");
+		if (err)
 			continue;
 
-		if (iscsi_sysfs_get_transport_param(t->name, "caps",
-						    &t->caps, "0x%x"))
+		sprintf(filename, ISCSI_TRANSPORT_DIR"/%s/caps", t->name);
+		err = read_sysfs_file(filename, &t->caps, "0x%x");
+		if (err)
 			continue;
+
 		/*
 		 * tmp hack for qla4xx compat
 		 */
@@ -301,149 +181,123 @@
 	return 0;
 }
 
+static void get_session_param(int sid, char *param, void *value, char *format)
+{
+	/* set to invalid */
+	if (!strcmp(format, "%s\n"))
+		((char *)value)[0] = '\0';
+	else
+		*((int *)value) = -1;
+
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_SESSION_DIR"/session%d/%s", sid, param);
+	read_sysfs_file(sysfs_file, value, format);
+}
+
+static void get_negotiated_conn_param(int sid, char *param, int *value)
+{
+	/* set to invalid */
+	*value = -1;
+
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%d:0/%s", sid, param);
+	read_sysfs_file(sysfs_file, value, "%d\n");
+}
+
 /* caller must check lengths */
-void iscsi_sysfs_get_auth_conf(int sid, struct iscsi_auth_config *conf)
+void get_auth_conf(int sid, struct iscsi_auth_config *conf)
 {
 	memset(conf, 0, sizeof(*conf));
 
-	iscsi_sysfs_get_session_param(sid, "username", conf->username, "%s\n");
-	iscsi_sysfs_get_session_param(sid, "username_in", conf->username_in,
-				      "%s\n");
-	iscsi_sysfs_get_session_param(sid, "password", conf->password, "%s\n");
+	get_session_param(sid, "username", conf->username, "%s\n");
+	get_session_param(sid, "username_in", conf->username_in, "%s\n");
+	get_session_param(sid, "password", conf->password, "%s\n");
 	if (strlen((char *)conf->password))
 		conf->password_length = strlen((char *)conf->password);
-	iscsi_sysfs_get_session_param(sid, "password_in", conf->password_in,
-				      "%s\n");
+	get_session_param(sid, "password_in", conf->password_in, "%s\n");
 	if (strlen((char *)conf->password_in))
 		conf->password_in_length = strlen((char *)conf->password_in);
 }
 
 /* called must check for -1=invalid value */
-void iscsi_sysfs_get_negotiated_conn_conf(int sid,
-				struct iscsi_conn_operational_config *conf)
+void get_negotiated_conn_conf(int sid,
+			      struct iscsi_conn_operational_config *conf)
 {
 	memset(conf, 0, sizeof(*conf));
 
-	iscsi_sysfs_get_conn_param(sid, "data_digest", &conf->DataDigest,
-				   "%d\n");
-	iscsi_sysfs_get_conn_param(sid, "header_digest", &conf->HeaderDigest,
-				   "%d\n");
-	iscsi_sysfs_get_conn_param(sid, "max_xmit_dlength",
-				   &conf->MaxXmitDataSegmentLength, "%d\n");
-	iscsi_sysfs_get_conn_param(sid, "max_recv_dlength",
-				   &conf->MaxRecvDataSegmentLength, "%d\n");
+	get_negotiated_conn_param(sid, "data_digest",
+				  &conf->DataDigest);
+	get_negotiated_conn_param(sid, "header_digest",
+				  &conf->HeaderDigest);
+	get_negotiated_conn_param(sid, "max_xmit_dlength",
+				  &conf->MaxXmitDataSegmentLength);
+	get_negotiated_conn_param(sid, "max_recv_dlength",
+				  &conf->MaxRecvDataSegmentLength);
 }
 
 /* called must check for -1=invalid value */
-void iscsi_sysfs_get_negotiated_session_conf(int sid,
-				struct iscsi_session_operational_config *conf)
+void get_negotiated_session_conf(int sid,
+				 struct iscsi_session_operational_config *conf)
 {
 	memset(conf, 0, sizeof(*conf));
 
-	iscsi_sysfs_get_session_param(sid, "data_pdu_in_order",
-				      &conf->DataPDUInOrder, "%d\n");
-	iscsi_sysfs_get_session_param(sid, "data_seq_in_order",
-				      &conf->DataSequenceInOrder, "%d\n");
-	iscsi_sysfs_get_session_param(sid, "erl", &conf->ERL, "%d\n");
-	iscsi_sysfs_get_session_param(sid, "first_burst_len",
-				      &conf->FirstBurstLength, "%d\n");
-	iscsi_sysfs_get_session_param(sid, "max_burst_len",
-				      &conf->MaxBurstLength, "%d\n");
-	iscsi_sysfs_get_session_param(sid, "immediate_data",
-				      &conf->ImmediateData, "%d\n");
-	iscsi_sysfs_get_session_param(sid, "initial_r2t",
-				      &conf->InitialR2T, "%d\n");
-	iscsi_sysfs_get_session_param(sid, "max_outstanding_r2t",
-				      &conf->MaxOutstandingR2T, "%d\n");
-}
-
-uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err)
-{
-	struct sysfs_device *session_dev, *host_dev;
-	char devpath[PATH_SIZE];
-	char id[NAME_SIZE];
+	get_session_param(sid, "data_pdu_in_order",
+			  &conf->DataPDUInOrder, "%d\n");
+	get_session_param(sid, "data_seq_in_order",
+			  &conf->DataSequenceInOrder, "%d\n");
+	get_session_param(sid, "erl",
+			  &conf->ERL, "%d\n");
+	get_session_param(sid, "first_burst_len",
+			  &conf->FirstBurstLength, "%d\n");
+	get_session_param(sid, "max_burst_len",
+			  &conf->MaxBurstLength, "%d\n");
+	get_session_param(sid, "immediate_data",
+			  &conf->ImmediateData, "%d\n");
+	get_session_param(sid, "initial_r2t",
+			  &conf->InitialR2T, "%d\n");
+	get_session_param(sid, "max_outstanding_r2t",
+			  &conf->MaxOutstandingR2T, "%d\n");
+}
+
+uint32_t get_host_no_from_sid(uint32_t sid, int *err)
+{
+	char *buf, *path, *tmp;
+	uint32_t host_no;
 
 	*err = 0;
-	snprintf(id, sizeof(id), "session%u", sid);
-	if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
-					       ISCSI_SESSION_SUBSYS, id)) {
-		log_error("Could not lookup devpath for %s. Possible sysfs "
-			  "incompatibility.\n", id);
-		*err = EIO;
-		return 0;
-	}
 
-	session_dev = sysfs_device_get(devpath);
-	if (!session_dev) {
-		log_error("Could not get dev for %s. Possible sysfs "
-			  "incompatibility.\n", id);
-		*err = EIO;
+	buf = calloc(2, PATH_MAX);
+	if (!buf) {
+		*err = ENOMEM;
 		return 0;
 	}
+	path = buf + PATH_MAX;
 
-	/*
-	 * 2.6.27 moved from scsi_host to scsi for the subsys when
-	 * sysfs compat is not on.
-	 */
-	host_dev = sysfs_device_get_parent_with_subsystem(session_dev,
-							  SCSI_SUBSYS);
-	if (!host_dev) {
-		struct sysfs_device *dev_parent;
-
-		dev_parent = sysfs_device_get_parent(session_dev);
-		while (dev_parent != NULL) {
-			if (strncmp(dev_parent->kernel, "host", 4) == 0) {
-				host_dev = dev_parent;
-				break;
-			}
-			dev_parent = sysfs_device_get_parent(dev_parent);
-		}
-
-		if (!host_dev) {
-			log_error("Could not get host dev for %s. Possible "
-				  "sysfs incompatibility.\n", id);
-			*err = EIO;
-			return 0;
-		}
+	sprintf(path, ISCSI_SESSION_DIR"/session%d/device", sid);
+	if (readlink(path, buf, PATH_MAX) < 0) {
+		log_error("Could not get link for %s.", path);
+		*err = errno;
+		goto free_buf;
 	}
 
-	return atol(host_dev->kernel_number);
-}
+	/* buf will be .....bus_info/hostX/sessionY */
 
-/* TODO: merge and make macro */
-static int __get_host_no_from_netdev(void *data, struct host_info *info)
-{
-	struct host_info *ret_info = data;
+	/* find hostX */
+	tmp = strrchr(buf, '/');
+	*tmp = '\0';
 
-	if (!strcmp(ret_info->iface.netdev, info->iface.netdev)) {
-		ret_info->host_no = info->host_no;
-		return 1;
-	}
-	return 0;
-}
+	/* find bus and increment past it */
+	tmp = strrchr(buf, '/');
+	tmp++;
 
-static uint32_t get_host_no_from_netdev(char *netdev, int *rc)
-{
-	uint32_t host_no = -1;
-	struct host_info *info;
-	int nr_found, local_rc;
-
-	*rc = 0;
-
-	info = calloc(1, sizeof(*info));
-	if (!info) {
-		*rc = ENOMEM;
-		return -1;
+	if (sscanf(tmp, "host%u", &host_no) != 1) {
+		log_error("Could not get host for sid %u.", sid);
+		*err = ENXIO;
+		goto free_buf;
 	}
-	strcpy(info->iface.netdev, netdev);
 
-	local_rc = iscsi_sysfs_for_each_host(info, &nr_found,
-					     __get_host_no_from_netdev);
-	if (local_rc == 1)
-		host_no = info->host_no;
-	else
-		*rc = ENODEV;
-	free(info);
+free_buf:
+	free(buf);
 	return host_no;
 }
 
@@ -473,7 +327,7 @@
 	}
 	strcpy(info->iface.hwaddress, address);
 
-	local_rc = iscsi_sysfs_for_each_host(info, &nr_found,
+	local_rc = sysfs_for_each_host(info, &nr_found,
 					__get_host_no_from_hwaddress);
 	if (local_rc == 1)
 		host_no = info->host_no;
@@ -510,8 +364,8 @@
 	}
 	strcpy(info->iface.ipaddress, address);
 
-	local_rc = iscsi_sysfs_for_each_host(info, &nr_found,
-					     __get_host_no_from_ipaddress);
+	local_rc = sysfs_for_each_host(info, &nr_found,
+					__get_host_no_from_ipaddress);
 	if (local_rc == 1)
 		host_no = info->host_no;
 	else
@@ -520,7 +374,7 @@
 	return host_no;
 }
 
-uint32_t iscsi_sysfs_get_host_no_from_iface(struct iface_rec *iface, int *rc)
+uint32_t get_host_no_from_iface(struct iface_rec *iface, int *rc)
 {
 	int tmp_rc;
 	uint32_t host_no = -1;
@@ -531,9 +385,6 @@
 	else if (strlen(iface->ipaddress) &&
 		 strcasecmp(iface->ipaddress, DEFAULT_IPADDRESS))
 		host_no = get_host_no_from_ipaddress(iface->ipaddress, &tmp_rc);
-	else if(strlen(iface->netdev) &&
-		strcasecmp(iface->netdev, DEFAULT_NETDEV))
-		host_no = get_host_no_from_netdev(iface->netdev, &tmp_rc);
 	else
 		tmp_rc = EINVAL;
 
@@ -541,85 +392,12 @@
 	return host_no;
 }
 
-static int sysfs_read_iface(struct iface_rec *iface, int host_no, int sid)
-{
-	struct iscsi_transport *t;
-	int ret;
-
-	/*
-	 * backward compat
-	 * If we cannot get the address we assume we are doing the old
-	 * style and use default.
-	 */
-	ret = iscsi_sysfs_get_iscsi_host_param(host_no, "hwaddress",
-					       iface->hwaddress, "%s\n");
-	if (ret) {
-		sprintf(iface->hwaddress, DEFAULT_HWADDRESS);
-		log_debug(7, "could not read hwaddress for host%d\n", host_no);
-	}
-
-	t = iscsi_sysfs_get_transport_by_hba(host_no);
-	if (!t)
-		log_debug(7, "could not get transport name for host%d",
-			  host_no);
-	else
-		strcpy(iface->transport_name, t->name);
-
-	/* if not found just print out default */
-	ret = iscsi_sysfs_get_iscsi_host_param(host_no, "ipaddress",
-					       iface->ipaddress, "%s\n");
-	if (ret) {
-		sprintf(iface->ipaddress, DEFAULT_IPADDRESS);
-		log_debug(7, "could not read local address for host%d\n",
-			  host_no);
-	}
-
-	/* if not found just print out default */
-	ret = iscsi_sysfs_get_iscsi_host_param(host_no, "netdev",
-					       iface->netdev, "%s\n");
-	if (ret) {
-		sprintf(iface->netdev, DEFAULT_NETDEV);
-		log_debug(7, "could not read netdev for host%d\n", host_no);
-	}
-
-	ret = iscsi_sysfs_get_iscsi_host_param(host_no, "initiatorname",
-					       iface->iname, "%s\n");
-	if (ret)
-		/* default iname is picked up later from initiatorname.iscsi */
-		log_debug(7, "Could not read initiatorname for host%d\n",
-			  host_no);
-
-	/*
-	 * this is on the session, because we support multiple bindings
-	 * per device.
-	 */
-	memset(iface->name, 0, sizeof(iface->name));
-	/*
-	 * this was added after 2.0.869 so we could be doing iscsi_tcp
-	 * session binding, but there may not be a ifacename set
-	 */
-	ret = iscsi_sysfs_get_session_param(sid, "ifacename", iface->name,
-					    "%s\n");
-	if (ret) {
-		log_debug(7, "could not read iface name for sid %u\n", sid);
-		/*
- 		 * if the ifacename file is not there then we are using a older
- 		 * kernel and can try to find the binding by the net info
- 		 * which was used on these older kernels.
- 		 */
-		if (iface_get_by_net_binding(iface, iface))
-			log_debug(7, "Could not find iface for session bound "
-				  "to:" iface_fmt "\n", iface_str(iface));
-	}
-	return ret;
-}
-
-int iscsi_sysfs_for_each_host(void *data, int *nr_found,
-			      iscsi_sysfs_host_op_fn *fn)
+int sysfs_for_each_host(void *data, int *nr_found, sysfs_host_op_fn *fn)
 {
 	struct dirent **namelist;
 	int rc = 0, i, n;
 	struct host_info *info;
+	struct iscsi_transport *t;
 
 	info = calloc(1, sizeof(*info));
 	if (!info)
@@ -638,7 +416,44 @@
 			break;
 		}
 
-		sysfs_read_iface(&info->iface, info->host_no, -1);
+		memset(sysfs_file, 0, PATH_MAX);
+		sprintf(sysfs_file, ISCSI_HOST_DIR"/%s/initiatorname",
+			namelist[i]->d_name);
+		rc = read_sysfs_file(sysfs_file, info->iname, "%s\n");
+		if (rc)
+			log_debug(4, "Could not read initiatorname for host "
+				  "%u. Error %d\n", info->host_no, rc);
+
+		memset(sysfs_file, 0, PATH_MAX);
+		sprintf(sysfs_file, ISCSI_HOST_DIR"/%s/ipaddress",
+			namelist[i]->d_name);
+		rc = read_sysfs_file(sysfs_file, info->iface.ipaddress, "%s\n");
+		if (rc)
+			log_debug(4, "Could not read ipaddress for host %u. "
+				  "Error %d\n", info->host_no, rc);
+
+		memset(sysfs_file, 0, PATH_MAX);
+		sprintf(sysfs_file, ISCSI_HOST_DIR"/%s/hwaddress",
+			namelist[i]->d_name);
+		rc = read_sysfs_file(sysfs_file, info->iface.hwaddress, "%s\n");
+		if (rc)
+			log_debug(4, "Could not read hwaddress for host %u. "
+				  "Error %d\n", info->host_no, rc);
+
+		memset(sysfs_file, 0, PATH_MAX);
+		sprintf(sysfs_file, ISCSI_HOST_DIR"/%s/netdev",
+			namelist[i]->d_name);
+		rc = read_sysfs_file(sysfs_file, info->iface.netdev, "%s\n");
+		if (rc)
+			log_debug(4, "Could not read netdev for host %u. "
+				  "Error %d\n", info->host_no, rc);
+
+		t = get_transport_by_hba(info->host_no);
+		if (!t)
+			log_debug(4, "could not get transport name for host %d",
+				  info->host_no);
+		else
+			strcpy(info->iface.transport_name, t->name);
 
 		rc = fn(data, info);
 		if (rc != 0)
@@ -661,114 +476,62 @@
  *
  * return 1 if session has lead conn and 0 if not.
  */
-int iscsi_sysfs_session_has_leadconn(uint32_t sid)
+int sysfs_session_has_leadconn(uint32_t sid)
 {
-	char devpath[PATH_SIZE];
-	char id[NAME_SIZE];
-
-	snprintf(id, sizeof(id), "connection%u:0", sid);
-	return sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
-						 ISCSI_CONN_SUBSYS, id);
-}
-
-/*
- * iscsi_sysfs_get_sid_from_path - parse a string for the sid
- * @session: session path
- *
- * Given sysfs_device is a directory name of the form:
- *
- * /sys/devices/platform/hostH/sessionS/targetH:B:I/H:B:I:L
- * /sys/devices/platform/hostH/sessionS/targetH:B:I
- * /sys/devices/platform/hostH/sessionS
- *
- * return the sid S. If just the sid is passed in it will be covnerted
- * to a int.
- */
-int iscsi_sysfs_get_sid_from_path(char *session)
-{
-	struct sysfs_device *dev_parent, *dev;
 	struct stat statb;
-	char devpath[PATH_SIZE];
-
-	if (lstat(session, &statb)) {
-		log_debug(1, "Could not stat %s failed with %d",
-			  session, errno);
-		if (index(session, '/')) {
-			log_error("%s is an invalid session path\n", session);
-			exit(1);
-		}
-		return atoi(session);
-	}
 
-	if (!S_ISDIR(statb.st_mode) && !S_ISLNK(statb.st_mode)) {
-		log_error("%s is not a directory", session);
-		exit(1);
-	}
-
-	if (!strncmp(session, "/sys", 4))
-		strncpy(devpath, session + 4, sizeof(devpath));
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%u:0", sid);
+	if (!stat(sysfs_file, &statb))
+		return 1;
 	else
-		strncpy(devpath, session, sizeof(devpath));
-
-	dev = sysfs_device_get(devpath);
-	if (!dev) {
-		log_error("Could not get dev for %s. Possible sysfs "
-			  "incompatibility.\n", devpath);
-		exit(1);
-	}
-
-	if (!strncmp(dev->kernel, "session", 7))
-		return atoi(dev->kernel_number);
-
-	dev_parent = sysfs_device_get_parent(dev);
-	while (dev_parent != NULL) {
-		if (strncmp(dev_parent->kernel, "session", 7) == 0)
-			return atoi(dev_parent->kernel_number);
-		dev_parent = sysfs_device_get_parent(dev_parent);
-	}
-
-	log_error("Unable to find sid in path %s", session);
-	exit(1);
-	return 0;
+		return 0;
 }
 
-int iscsi_sysfs_get_sessioninfo_by_id(struct session_info *info, char *session)
+int get_sessioninfo_by_sysfs_id(struct session_info *info, char *session)
 {
 	int ret, pers_failed = 0;
 	uint32_t host_no;
+	struct iscsi_transport *t;
 
 	if (sscanf(session, "session%d", &info->sid) != 1) {
 		log_error("invalid session '%s'", session);
 		return EINVAL;
 	}
 
-	ret = iscsi_sysfs_get_session_param(info->sid, "targetname",
-					    info->targetname, "%s\n");
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_SESSION_DIR"/%s/targetname", session);
+	ret = read_sysfs_file(sysfs_file, info->targetname, "%s\n");
 	if (ret) {
 		log_error("could not read session targetname: %d", ret);
 		return ret;
 	}
 
-	ret = iscsi_sysfs_get_session_param(info->sid, "tpgt", &info->tpgt,
-					    "%u\n");
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_SESSION_DIR"/%s/tpgt", session);
+	ret = read_sysfs_file(sysfs_file, &info->tpgt, "%u\n");
 	if (ret) {
-		log_error("could not read session tpgt: %u", ret);
+		log_error("could not read session tpgt: %d", ret);
 		return ret;
 	}
 
 	/* some HW drivers do not export addr and port */
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%d:0/"
+		"persistent_address", info->sid);
 	memset(info->persistent_address, 0, NI_MAXHOST);
-	ret = iscsi_sysfs_get_conn_param(info->sid, "persistent_address",
-					 info->persistent_address, "%s\n");
+	ret = read_sysfs_file(sysfs_file, info->persistent_address, "%s\n");
 	if (ret) {
 		pers_failed = 1;
 		/* older qlogic does not support this */
 		log_debug(5, "could not read pers conn addr: %d", ret);
 	}
 
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%d:0/address",
+		 info->sid);
 	memset(info->address, 0, NI_MAXHOST);
-	ret = iscsi_sysfs_get_conn_param(info->sid, "address",
-					 info->address, "%s\n");
+	ret = read_sysfs_file(sysfs_file, info->address, "%s\n");
 	if (ret) {
 		log_debug(5, "could not read curr addr: %d", ret);
 		/* iser did not export this */
@@ -782,17 +545,21 @@
 		strcpy(info->persistent_address, info->address);
 	pers_failed = 0;
 
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%d:0/"
+		"persistent_port", info->sid);
 	info->persistent_port = -1;
-	ret = iscsi_sysfs_get_conn_param(info->sid, "persistent_port",
-					 &info->persistent_port, "%u\n");
+	ret = read_sysfs_file(sysfs_file, &info->persistent_port, "%u\n");
 	if (ret) {
 		pers_failed = 1;
 		log_debug(5, "Could not read pers conn port %d", ret);
 	}
 
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%d:0/port",
+		info->sid);
 	info->port = -1;
-	ret = iscsi_sysfs_get_conn_param(info->sid, "port", &info->port,
-					 "%u\n");
+	ret = read_sysfs_file(sysfs_file, &info->port, "%u\n");
 	if (ret) {
 		/* iser did not export this */
 		if (!pers_failed)
@@ -806,29 +573,69 @@
 		info->persistent_port = info->port;
 
 	ret = 0;
-	host_no = iscsi_sysfs_get_host_no_from_sid(info->sid, &ret);
+	host_no = get_host_no_from_sid(info->sid, &ret);
 	if (ret) {
-		log_error("could not get host_no for session%d err %d.",
-			  info->sid, ret);
+		log_error("could not get host_no for session %d.", ret);
 		return ret;
 	}
 
-	sysfs_read_iface(&info->iface, host_no, info->sid);
- 
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_HOST_DIR"/host%d/initiatorname", host_no);
+	ret = read_sysfs_file(sysfs_file, info->iface.iname, "%s\n");
+	if (ret)
+		log_debug(7, "Could not read initiatorname for %s",
+			 sysfs_file);
+
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_HOST_DIR"/host%u/hwaddress", host_no);
+	/*
+	 * backward compat
+	 * If we cannot get the address we assume we are doing the old
+	 * style and use default.
+	 */
+	sprintf(info->iface.hwaddress, DEFAULT_HWADDRESS);
+	ret = read_sysfs_file(sysfs_file, info->iface.hwaddress, "%s\n");
+	if (ret)
+		log_debug(7, "could not read hwaddress for %s", sysfs_file);
+
+	t = get_transport_by_sid(info->sid);
+	if (!t)
+		log_debug(7, "could not get transport name for session %d",
+			  info->sid);
+	else
+		strcpy(info->iface.transport_name, t->name);
+
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_HOST_DIR"/host%u/ipaddress", host_no);
+	/* if not found just print out default */
+	sprintf(info->iface.ipaddress, DEFAULT_IPADDRESS);
+	ret = read_sysfs_file(sysfs_file, info->iface.ipaddress, "%s\n");
+	if (ret)
+		log_debug(7, "could not read local address for %s",
+			 sysfs_file);
+
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_HOST_DIR"/host%u/netdev", host_no);
+	/* if not found just print out default */
+	sprintf(info->iface.netdev, DEFAULT_NETDEV);
+	ret = read_sysfs_file(sysfs_file, info->iface.netdev, "%s\n");
+	if (ret)
+		log_debug(7, "could not read netdev for %s",
+			 sysfs_file);
+
 	log_debug(7, "found targetname %s address %s pers address %s port %d "
-		 "pers port %d driver %s iface name %s ipaddress %s "
+		 "pers port %d driver %s iface ipaddress %s "
 		 "netdev %s hwaddress %s iname %s",
 		  info->targetname, info->address ? info->address : "NA",
 		  info->persistent_address ? info->persistent_address : "NA",
-		  info->port, info->persistent_port, info->iface.transport_name,
-		  info->iface.name, info->iface.ipaddress,
+		  info->port, info->persistent_port,
+		  info->iface.transport_name, info->iface.ipaddress,
 		  info->iface.netdev, info->iface.hwaddress,
 		  info->iface.iname);
 	return 0;
 }
  
-int iscsi_sysfs_for_each_session(void *data, int *nr_found,
-				 iscsi_sysfs_session_op_fn *fn)
+int sysfs_for_each_session(void *data, int *nr_found, sysfs_session_op_fn *fn)
 {
 	struct dirent **namelist;
 	int rc = 0, n, i;
@@ -838,14 +645,14 @@
 	if (!info)
 		return ENOMEM;
 
-	n = scandir(ISCSI_SESSION_DIR, &namelist, trans_filter,
+	sprintf(sysfs_file, ISCSI_SESSION_DIR);
+	n = scandir(sysfs_file, &namelist, trans_filter,
 		    direntcmp);
 	if (n <= 0)
 		goto free_info;
 
 	for (i = 0; i < n; i++) {
-		rc = iscsi_sysfs_get_sessioninfo_by_id(info,
-						       namelist[i]->d_name);
+		rc = get_sessioninfo_by_sysfs_id(info, namelist[i]->d_name);
 		if (rc) {
 			log_error("could not find session info for %s",
 				   namelist[i]->d_name);
@@ -871,56 +678,37 @@
 	return rc;
 }
 
-int iscsi_sysfs_get_session_state(char *state, int sid)
+int get_session_state(char *state, int sid)
 {
-	return iscsi_sysfs_get_session_param(sid, "state", state, "%s\n");
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, ISCSI_SESSION_DIR"/session%d/state", sid);
+	return read_sysfs_file(sysfs_file, state, "%s\n");
 }
 
-int iscsi_sysfs_get_host_state(char *state, int host_no)
+int get_host_state(char *state, int host_no)
 {
-	return iscsi_sysfs_get_scsi_host_param(host_no, "state", state, "%s\n");
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, SCSI_HOST_DIR"/host%d/state", host_no);
+	return read_sysfs_file(sysfs_file, state, "%s\n");
 }
 
-int iscsi_sysfs_get_device_state(char *state, int host_no, int target, int lun)
+int get_device_state(char *state, int host_no, int target, int lun)
 {
-	char id[NAME_SIZE];
-
-	snprintf(id, sizeof(id), "%d:0:%d:%d", host_no, target, lun);
-	if (iscsi_sysfs_get_scsi_dev_param(id, "state", state, "%s\n")) {
-		log_debug(3, "Could not read attr state for %s\n", id);
-		return EIO;
-	}
-
-	return 0;
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, SCSI_DEVICE_DIR"/%d:0:%d:%d/state",
+		host_no, target, lun);
+	return read_sysfs_file(sysfs_file, state, "%s\n");
 }
 
-char *iscsi_sysfs_get_blockdev_from_lun(int host_no, int target, int lun)
+char *get_blockdev_from_lun(int host_no, int target, int lun)
 {
-	char devpath[PATH_SIZE];
-	char path_full[PATH_SIZE];
-	char *path;
-	char id[NAME_SIZE];
 	DIR *dirfd;
 	struct dirent *dent;
-	size_t sysfs_len;
-	struct stat statbuf;
 	char *blockdev, *blockdup = NULL;
 
-	snprintf(id, sizeof(id), "%d:0:%d:%d", host_no, target, lun);
-	if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
-					       SCSI_SUBSYS, id)) {
-		log_debug(3, "Could not lookup devpath for %s %s\n",
-			  SCSI_SUBSYS, id);
-		return NULL;
-	}
-
-	sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
-	if(sysfs_len >= sizeof(path_full))
-		sysfs_len = sizeof(path_full) - 1;
-	path = &path_full[sysfs_len];
-	strlcat(path_full, devpath, sizeof(path_full));
-
-	dirfd = opendir(path_full);
+	sprintf(sysfs_file, SCSI_DEVICE_DIR"/%d:0:%d:%d",
+		host_no, target, lun);
+	dirfd = opendir(sysfs_file);
 	if (!dirfd)
 		return NULL;
 
@@ -932,47 +720,15 @@
 		if (strncmp(dent->d_name, "block:", 5))
 			continue;
 
-		strlcat(path_full, "/", sizeof(path_full));
-		strlcat(path_full, dent->d_name, sizeof(path_full));
-		/*
-		 * 2.6.25 dropped the symlink and now block is a dir.
-		 */
-		if (lstat(path_full, &statbuf)) {
-			log_error("Could not stat block path %s err %d\n",
-				  path_full, errno);
+		blockdev = strchr(dent->d_name, ':');
+		if (!blockdev)
 			break;
-		}
-
-		if (S_ISLNK(statbuf.st_mode)) {
-			blockdev = strchr(dent->d_name, ':');
-			if (!blockdev)
-				break;
-			/* increment past colon */
-			blockdev++;
-			blockdup = strdup(blockdev);
-		} else if (S_ISDIR(statbuf.st_mode)) {
-			DIR *blk_dirfd;
-			struct dirent *blk_dent;
-
-			/* it should not be this hard should it? :) */
-			blk_dirfd = opendir(path_full);
-			if (!blk_dirfd) {
-				log_debug(3, "Could not open blk path %s\n",
-					  path_full);
-				break;
-			}
-
-			while ((blk_dent = readdir(blk_dirfd))) {
-				if (!strcmp(blk_dent->d_name, ".") ||
-				    !strcmp(blk_dent->d_name, ".."))
-					continue;
-				blockdup = strdup(blk_dent->d_name);
-				break;
-			}
-			closedir(blk_dirfd);
-		}
+		/* increment past colon */
+		blockdev++;
 
+		blockdup = strdup(blockdev);
 		break;
+
 	}
 	closedir(dirfd);
 	return blockdup;
@@ -980,38 +736,14 @@
 
 static uint32_t get_target_no_from_sid(uint32_t sid, int *err)
 {
-	char devpath[PATH_SIZE];
-	char path_full[PATH_SIZE];
-	char *path;
-	char id[NAME_SIZE];
 	DIR *dirfd;
 	struct dirent *dent;
 	uint32_t host, bus, target = 0;
-	size_t sysfs_len;
 
 	*err = ENODEV;
 
-	snprintf(id, sizeof(id), "session%u", sid);
-	if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
-					       ISCSI_SESSION_SUBSYS, id)) {
-		log_debug(3, "Could not lookup devpath for %s %s\n",
-			  ISCSI_SESSION_SUBSYS, id);
-		return 0;
-	}
-
-	/*
-	 * This does not seem safe from future changes, but we currently
-	 * want /devices/platform/hostY/sessionX, but we come from the
-	 * /class/iscsi_session/sessionX/device.
-	 */
-	sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
-	if(sysfs_len >= sizeof(path_full))
-		sysfs_len = sizeof(path_full) - 1;
-	path = &path_full[sysfs_len];
-	strlcat(path_full, devpath, sizeof(path_full));
-	strlcat(path_full, "/device", sizeof(devpath));
-
-	dirfd = opendir(path_full);
+	sprintf(sysfs_file, ISCSI_SESSION_DIR"/session%u/device/", sid);
+	dirfd = opendir(sysfs_file);
 	if (!dirfd)
 		return 0;
 
@@ -1035,7 +767,7 @@
 
 }
 
-struct iscsi_transport *iscsi_sysfs_get_transport_by_name(char *transport_name)
+struct iscsi_transport *get_transport_by_name(char *transport_name)
 {
 	struct iscsi_transport *t;
 
@@ -1052,7 +784,7 @@
 }
 
 /* TODO: replace the following functions with some decent sysfs links */
-struct iscsi_transport *iscsi_sysfs_get_transport_by_hba(long host_no)
+struct iscsi_transport *get_transport_by_hba(long host_no)
 {
 	char name[ISCSI_TRANSPORT_NAME_MAXLEN];
 	int rc;
@@ -1060,11 +792,11 @@
 	if (host_no == -1)
 		return NULL;
 
-	rc = iscsi_sysfs_get_scsi_host_param(host_no, "proc_name", name,
-					     "%s\n");
+	memset(sysfs_file, 0, PATH_MAX);
+	sprintf(sysfs_file, SCSI_HOST_DIR"/host%lu/proc_name", host_no);
+	rc = read_sysfs_file(sysfs_file, name, "%s\n");
 	if (rc) {
-		log_error("Could not read proc_name for host%ld rc %d.",
-			  host_no, rc);
+		log_error("Could not read %s rc %d.", sysfs_file, rc);
 		return NULL;
 	}
 
@@ -1073,20 +805,20 @@
 	 * the modules are named iscsi_tcp and iscsi_iser
 	 */
 	if (strstr(name, "iscsi_"))
-		return iscsi_sysfs_get_transport_by_name(name + 6);
+		return get_transport_by_name(name + 6);
 	else
-		return iscsi_sysfs_get_transport_by_name(name);
+		return get_transport_by_name(name);
 }
 
-struct iscsi_transport *iscsi_sysfs_get_transport_by_sid(uint32_t sid)
+struct iscsi_transport *get_transport_by_sid(uint32_t sid)
 {
 	uint32_t host_no;
 	int err;
 
-	host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err);
+	host_no = get_host_no_from_sid(sid, &err);
 	if (err)
 		return NULL;
-	return iscsi_sysfs_get_transport_by_hba(host_no);
+	return get_transport_by_hba(host_no);
 }
 
 /*
@@ -1096,42 +828,32 @@
  * This is only called when the connection is halted so exp_statsn is safe
  * to read without racing.
  */
-int iscsi_sysfs_get_exp_statsn(int sid)
+int set_exp_statsn(iscsi_conn_t *conn)
 {
-	uint32_t exp_statsn = 0;
-
-	if (iscsi_sysfs_get_conn_param(sid, "exp_statsn", &exp_statsn,
-				      "%u\n")) {
-		log_error("Could not read expstatsn for sid %d. "
-			  "Using zero for exp_statsn.", sid);
-		exp_statsn = 0;
+	sprintf(sysfs_file,
+		ISCSI_CONN_DIR"/connection%d:%d/exp_statsn",
+		conn->session->id, conn->id);
+	if (read_sysfs_file(sysfs_file, &conn->exp_statsn, "%u\n")) {
+		log_error("Could not read %s. Using zero fpr exp_statsn.",
+			  sysfs_file);
+		conn->exp_statsn = 0;
 	}
-	return exp_statsn;
+	return 0;
 }
 
-int iscsi_sysfs_for_each_device(int host_no, uint32_t sid,
-				void (* fn)(int host_no, int target, int lun))
+int sysfs_for_each_device(int host_no, uint32_t sid,
+			  void (* fn)(int host_no, int target, int lun))
 {
 	struct dirent **namelist;
 	int h, b, t, l, i, n, err = 0, target;
-	char devpath[PATH_SIZE];
-	char id[NAME_SIZE];
-	char path_full[PATH_SIZE];
 
 	target = get_target_no_from_sid(sid, &err);
 	if (err)
 		return err;
-	snprintf(id, sizeof(id), "session%u", sid);
-	if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
-					       ISCSI_SESSION_SUBSYS, id)) {
-		log_debug(3, "Could not lookup devpath for %s %s\n",
-			  ISCSI_SESSION_SUBSYS, id);
-		return EIO;
-	}
 
-	snprintf(path_full, sizeof(path_full), "%s%s/device/target%d:0:%d",
-		 sysfs_path, devpath, host_no, target);
-	n = scandir(path_full, &namelist, trans_filter,
+	sprintf(sysfs_file, ISCSI_SESSION_DIR"/session%d/device/target%d:0:%d",
+		sid, host_no, target);
+	n = scandir(sysfs_file, &namelist, trans_filter,
 		    direntcmp);
 	if (n <= 0)
 		return 0;
@@ -1150,46 +872,71 @@
 	return 0;
 }
 
-void iscsi_sysfs_set_device_online(int hostno, int target, int lun)
+void set_device_online(int hostno, int target, int lun)
 {
-	char *write_buf = "running\n";
-	char id[NAME_SIZE];
-	int err;
-
-	snprintf(id, sizeof(id), "%d:0:%d:%d", hostno, target, lun);
-	log_debug(4, "online device %s", id);
+	int fd;
 
-	err = iscsi_sysfs_set_scsi_dev_param(id, "state", write_buf,
-					     strlen(write_buf));
-	if (err && err != EINVAL)
+	sprintf(sysfs_file, SCSI_DEVICE_DIR"/%d:0:%d:%d/state",
+		hostno, target, lun);
+	fd = open(sysfs_file, O_WRONLY);
+	if (fd < 0)
+		return;
+	log_debug(4, "online device using %s", sysfs_file);
+	if (write(fd, "running\n", 8) == -1 && errno != EINVAL)
 		/* we should read the state */
-		log_error("Could not online LUN %d err %d.", lun, err);
+		log_error("Could not online LUN %d err %d.", lun, errno);
+	close(fd);
+}
+
+/* TODO: remove this when we fix shutdown */
+void delete_device(int hostno, int target, int lun)
+{
+	int fd;
+
+	sprintf(sysfs_file, SCSI_DEVICE_DIR"/%d:0:%d:%d/delete",
+		hostno, target, lun);
+	fd = open(sysfs_file, O_WRONLY);
+	if (fd < 0)
+		return;
+	log_debug(4, "deleting device using %s", sysfs_file);
+	write(fd, "1", 1);
+	close(fd);
 }
 
-void iscsi_sysfs_rescan_device(int hostno, int target, int lun)
+void rescan_device(int hostno, int target, int lun)
 {
-	char *write_buf = "1";
-	char id[NAME_SIZE];
+	int fd;
 
-	snprintf(id, sizeof(id), "%d:0:%d:%d", hostno, target, lun);
-	log_debug(4, "rescanning device %s", id);
-	iscsi_sysfs_set_scsi_dev_param(id, "rescan", write_buf,
-				       strlen(write_buf));
+	sprintf(sysfs_file, SCSI_DEVICE_DIR"/%d:0:%d:%d/rescan",
+		hostno, target, lun);
+	fd = open(sysfs_file, O_WRONLY);
+	if (fd < 0)
+		return;
+	log_debug(4, "rescanning device using %s", sysfs_file);
+	write(fd, "1", 1);
+	close(fd);
 }
 
-pid_t iscsi_sysfs_scan_host(int hostno, int async)
+pid_t scan_host(int hostno, int async)
 {
-	char *write_buf = "- - -";
 	pid_t pid = 0;
+	int fd;
+
+	sprintf(sysfs_file, SCSI_HOST_DIR"/host%d/scan",
+		hostno);
+	fd = open(sysfs_file, O_WRONLY);
+	if (fd < 0) {
+		log_error("could not scan scsi host%d.", hostno);
+		return -1;
+	}
 
 	if (async)
 		pid = fork();
 	if (pid == 0) {
 		/* child */
-		log_debug(4, "scanning host%d", hostno);
-
-		iscsi_sysfs_set_scsi_host_param(hostno, "scan", write_buf,
-					        strlen(write_buf));
+		log_debug(4, "scanning host%d using %s", hostno,
+			  sysfs_file);
+		write(fd, "- - -", 5);
 		log_debug(4, "scanning host%d completed\n", hostno);
 	} else if (pid > 0) {
 		log_debug(4, "scanning host%d from pid %d", hostno, pid);
@@ -1201,10 +948,12 @@
 		log_error("Could not start scanning process for host %d "
 			  "err %d. Try scanning through sysfs.", hostno,
 			  errno);
+
+	close(fd);
 	return pid;
 }
 
-struct iscsi_transport *iscsi_sysfs_get_transport_by_session(char *sys_session)
+struct iscsi_transport *get_transport_by_session(char *sys_session)
 {
 	uint32_t sid;
 
@@ -1213,21 +962,23 @@
                 return NULL;
         }
 
-	return iscsi_sysfs_get_transport_by_sid(sid);
+	return get_transport_by_sid(sid);
 }
 
-char *iscsi_sysfs_get_iscsi_kernel_version(void)
+int get_iscsi_kernel_version(char *buf)
 {
-	return sysfs_attr_get_value("/module/scsi_transport_iscsi", "version");
+	if (read_sysfs_file(ISCSI_VERSION_FILE, buf, "%s\n"))
+		return ENODATA;
+	else
+		return 0;
 }
 
-int iscsi_sysfs_check_class_version(void)
+int check_class_version(void)
 {
-	char *version;
+	char version[20];
 	int i;
 
-	version = iscsi_sysfs_get_iscsi_kernel_version();
-	if (!version)
+	if (get_iscsi_kernel_version(version))
 		goto fail;
 
 	log_warning("transport class version %s. iscsid version %s",
--- open-iscsi-2.0.870~rc3.orig/usr/iscsi_sysfs.h
+++ open-iscsi-2.0.870~rc3/usr/iscsi_sysfs.h
@@ -19,11 +19,6 @@
 
 #include <sys/types.h>
 
-#include "sysfs.h"
-#include "types.h"
-#include "iscsi_proto.h"
-#include "config.h"
-
 struct iscsi_session;
 struct iscsi_conn;
 struct iscsi_session_operational_config;
@@ -48,56 +43,55 @@
 };
 
 struct host_info {
+	char iname[TARGET_NAME_MAXLEN + 1];
 	struct iface_rec iface;
 	int host_no;
 };
 
 extern int direntcmp(const void *d1, const void *d2);
 extern void free_transports(void);
-extern char *iscsi_sysfs_get_iscsi_kernel_version(void);
-extern int iscsi_sysfs_check_class_version(void);
-extern int iscsi_sysfs_get_sessioninfo_by_id(struct session_info *info,
-					     char *sys_session);
-extern int iscsi_sysfs_session_has_leadconn(uint32_t sid);
-
-typedef int (iscsi_sysfs_session_op_fn)(void *, struct session_info *);
-typedef int (iscsi_sysfs_host_op_fn)(void *, struct host_info *);
-
-extern int iscsi_sysfs_for_each_session(void *data, int *nr_found,
-					iscsi_sysfs_session_op_fn *fn);
-extern int iscsi_sysfs_for_each_host(void *data, int *nr_found,
-				     iscsi_sysfs_host_op_fn *fn);
-extern uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err);
-extern uint32_t iscsi_sysfs_get_host_no_from_iface(struct iface_rec *iface,
-						   int *rc);
-extern int iscsi_sysfs_get_sid_from_path(char *session);
-extern char *iscsi_sysfs_get_blockdev_from_lun(int hostno, int target, int sid);
+extern int get_iscsi_kernel_version(char *buf);
+extern int check_class_version(void);
+extern int get_sessioninfo_by_sysfs_id(struct session_info *info,
+				      char *sys_session);
+extern int sysfs_session_has_leadconn(uint32_t sid);
+
+typedef int (sysfs_session_op_fn)(void *, struct session_info *);
+typedef int (sysfs_host_op_fn)(void *, struct host_info *);
+
+extern int sysfs_for_each_session(void *data, int *nr_found,
+				  sysfs_session_op_fn *fn);
+extern int sysfs_for_each_host(void *data, int *nr_found, sysfs_host_op_fn *fn);
+extern uint32_t get_host_no_from_sid(uint32_t sid, int *err);
+extern uint32_t get_host_no_from_iface(struct iface_rec *iface, int *rc);
+extern char *get_blockdev_from_lun(int hostno, int target, int sid);
+extern int set_exp_statsn(struct iscsi_conn *conn);
 
 static inline int is_valid_operational_value(int value)
 {
 	return value != -1;
 }
 
-extern void iscsi_sysfs_get_auth_conf(int sid, struct iscsi_auth_config *conf);
-extern void iscsi_sysfs_get_negotiated_session_conf(int sid,
+extern void get_auth_conf(int sid, struct iscsi_auth_config *conf);
+extern void get_negotiated_session_conf(int sid,
 				struct iscsi_session_operational_config *conf);
-extern void iscsi_sysfs_get_negotiated_conn_conf(int sid,
+extern void get_negotiated_conn_conf(int sid,
 				struct iscsi_conn_operational_config *conf);
-extern pid_t iscsi_sysfs_scan_host(int hostno, int async);
-extern int iscsi_sysfs_get_session_state(char *state, int sid);
-extern int iscsi_sysfs_get_host_state(char *state, int host_no);
-extern int iscsi_sysfs_get_device_state(char *state, int host_no, int target,
-					int lun);
-extern int iscsi_sysfs_get_exp_statsn(int sid);
-extern void iscsi_sysfs_set_device_online(int hostno, int target, int lun);
-extern void iscsi_sysfs_rescan_device(int hostno, int target, int lun);
-extern int iscsi_sysfs_for_each_device(int host_no, uint32_t sid,
-				void (* fn)(int host_no, int target, int lun));
-extern struct iscsi_transport *iscsi_sysfs_get_transport_by_hba(long host_no);
-extern struct iscsi_transport *iscsi_sysfs_get_transport_by_session(char *sys_session);
-extern struct iscsi_transport *iscsi_sysfs_get_transport_by_sid(uint32_t sid);
-extern struct iscsi_transport *iscsi_sysfs_get_transport_by_name(char *transport_name);
+extern pid_t scan_host(int hostno, int async);
+extern int get_session_state(char *state, int sid);
+extern int get_host_state(char *state, int host_no);
+extern int get_device_state(char *state, int host_no, int target, int lun);
+extern void set_device_online(int hostno, int target, int lun);
+extern void delete_device(int hostno, int target, int lun);
+extern void rescan_device(int hostno, int target, int lun);
+extern int sysfs_for_each_device(int host_no, uint32_t sid,
+				 void (* fn)(int host_no, int target, int lun));
+extern struct iscsi_transport *get_transport_by_hba(long host_no);
+extern struct iscsi_transport *get_transport_by_session(char *sys_session);
+extern struct iscsi_transport *get_transport_by_sid(uint32_t sid);
+extern struct iscsi_transport *get_transport_by_name(char *transport_name);
 
 extern struct list_head transports;
+extern int num_transports;
 
 #endif
--- open-iscsi-2.0.870~rc3.orig/usr/iscsiadm.c
+++ open-iscsi-2.0.870~rc3/usr/iscsiadm.c
@@ -40,7 +40,6 @@
 #include "list.h"
 #include "iscsi_settings.h"
 #include "fw_context.h"
-#include "iface.h"
 
 struct iscsi_ipc *ipc = NULL; /* dummy */
 static char program_name[] = "iscsiadm";
@@ -206,18 +205,18 @@
  * (scsi_host and iscsi_sessions are the currently running instance of
  * a iface or node record).
  */
-static int print_ifaces(int info_level)
+static int print_ifaces(idbm_t *db, int info_level)
 {
 	int err, num_found = 0;
 
 	switch (info_level) {
 	case 0:
 	case -1:
-		err = iface_for_each_iface(NULL, &num_found,
+		err = iface_for_each_iface(db, NULL, &num_found,
 					   iface_print_flat);
 		break;
 	case 1:
-		err = iface_for_each_iface(NULL, &num_found,
+		err = iface_for_each_iface(db, NULL, &num_found,
 					   iface_print_tree);
 		break;
 	default:
@@ -232,6 +231,35 @@
 	return err;
 }
 
+static int iscsid_req_async(iscsiadm_cmd_e cmd, node_rec_t *rec, int *fd)
+{
+	iscsiadm_req_t req;
+
+	memset(&req, 0, sizeof(iscsiadm_req_t));
+	req.command = cmd;
+	memcpy(&req.u.session.rec, rec, sizeof(node_rec_t));
+
+	return iscsid_request(fd, &req);
+}
+
+static int iscsid_req_wait(iscsiadm_cmd_e cmd, int fd)
+{
+	iscsiadm_rsp_t rsp;
+
+	memset(&rsp, 0, sizeof(iscsiadm_rsp_t));
+	return iscsid_response(fd, cmd, &rsp);
+}
+
+static int iscsid_req(iscsiadm_cmd_e cmd, node_rec_t *rec)
+{
+	int err, fd;
+
+	err = iscsid_req_async(cmd, rec, &fd);
+	if (err)
+		return err;
+	return iscsid_req_wait(cmd, fd);
+}
+
 static int
 match_startup_mode(node_rec_t *rec, char *mode)
 {
@@ -324,11 +352,11 @@
 }
 
 static int
-for_each_session(struct node_rec *rec, iscsi_sysfs_session_op_fn *fn)
+for_each_session(struct node_rec *rec, sysfs_session_op_fn *fn)
 {
 	int err, num_found = 0;
 
-	err = iscsi_sysfs_for_each_session(rec, &num_found, fn);
+	err = sysfs_for_each_session(rec, &num_found, fn);
 	if (err)
 		log_error("Could not execute operation on all sessions. Err "
 			  "%d.", err);
@@ -384,7 +412,7 @@
 	return 0;
 }
 
-static int link_recs(void *data, struct node_rec *rec)
+static int link_recs(idbm_t *db, void *data, struct node_rec *rec)
 {
 	struct list_head *list = data;
 	struct node_rec *rec_copy;
@@ -401,6 +429,7 @@
 static int __logout_portal(struct session_info *info, struct list_head *list)
 {
 	struct iscsid_async_req *async_req = NULL;
+	struct node_rec tmprec;
 	int fd, rc;
 
 	/* TODO: add fn to add session prefix info like dev_printk */
@@ -408,15 +437,20 @@
 		info->sid, info->targetname, info->persistent_address,
 		info->port);
 
+	memset(&tmprec, 0, sizeof(node_rec_t));
+	strncpy(tmprec.name, info->targetname, TARGET_NAME_MAXLEN);
+	tmprec.conn[0].port = info->persistent_port;
+	strncpy(tmprec.conn[0].address, info->persistent_address, NI_MAXHOST);
+	memcpy(&tmprec.iface, &info->iface, sizeof(struct iface_rec));
+
 	async_req = calloc(1, sizeof(*async_req));
 	if (!async_req) {
 		log_error("Could not allocate memory for async logout "
 			  "handling. Using sequential logout instead.");
-		rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid);
+		rc = iscsid_req(MGMT_IPC_SESSION_LOGOUT, &tmprec);
 	} else {
 		INIT_LIST_HEAD(&async_req->list);
-		rc = iscsid_req_by_sid_async(MGMT_IPC_SESSION_LOGOUT,
-					     info->sid, &fd);
+		rc = iscsid_req_async(MGMT_IPC_SESSION_LOGOUT, &tmprec, &fd);
 	}
 
 	/* we raced with another app or instance of iscsiadm */
@@ -443,8 +477,8 @@
 }
 
 static int
-__logout_portals(void *data, int *nr_found,
-		 int (*logout_fn)(void *, struct list_head *,
+__logout_portals(idbm_t *db, void *data, int *nr_found,
+		 int (*logout_fn)(idbm_t *, void *, struct list_head *,
 				   struct session_info *))
 {
 	struct session_info *curr_info, *tmp;
@@ -460,14 +494,14 @@
 	link_info.match_info = NULL;
 	*nr_found = 0;
 
-	err = iscsi_sysfs_for_each_session(&link_info, nr_found,
+	err = sysfs_for_each_session(&link_info, nr_found,
 				    link_sessions);
 	if (err || !*nr_found)
 		return err;
 
 	*nr_found = 0;
 	list_for_each_entry(curr_info, &session_list, list) {
-		err = logout_fn(data, &logout_list, curr_info);
+		err = logout_fn(db, data, &logout_list, curr_info);
 		if (err > 0 && !ret)
 			ret = err;
 		if (!err)
@@ -486,7 +520,7 @@
 }
 
 static int
-__logout_by_startup(void *data, struct list_head *list,
+__logout_by_startup(idbm_t *db, void *data, struct list_head *list,
 		    struct session_info *info)
 {
 	char *mode = data;
@@ -494,9 +528,23 @@
 	int rc = 0;
 
 	memset(&rec, 0, sizeof(node_rec_t));
-	if (idbm_rec_read(&rec, info->targetname, info->tpgt,
+	if (iface_get_by_bind_info(db, &info->iface, &rec.iface)) {
+		/*
+		 * If someone removed the /etc/iscsi/ifaces file
+		 * between logins then this will fail.
+		 *
+		 * To support that, we would have to throw our ifacename
+		 * into the kernel.
+		 */
+		log_debug(7, "could not read data for [%s,%s.%d]\n",
+			  info->targetname, info->persistent_address,
+			  info->persistent_port);
+		return -1;
+	}
+
+	if (idbm_rec_read(db, &rec, info->targetname, info->tpgt,
 			  info->persistent_address,
-			  info->persistent_port, &info->iface)) {
+			  info->persistent_port, &rec.iface)) {
 		/*
 		 * this is due to a HW driver or some other driver
 		 * not hooked in
@@ -508,8 +556,9 @@
 	}
 
 	/* multiple drivers could be connected to the same portal */
-	if (strcmp(rec.iface.transport_name, info->iface.transport_name))
+	if (!iscsi_match_session(&rec, info))
 		return -1;
+
 	/*
 	 * we always skip on boot because if the user killed this on
 	 * they would not be able to do anything
@@ -523,7 +572,7 @@
 }
 
 static int
-logout_by_startup(char *mode)
+logout_by_startup(idbm_t *db, char *mode)
 {
 	int nr_found;
 
@@ -534,16 +583,17 @@
 		return EINVAL;
 	}
 
-	return __logout_portals(mode, &nr_found, __logout_by_startup);
+	return __logout_portals(db, mode, &nr_found, __logout_by_startup);
 }
 
 static int
-logout_portal(void *data, struct list_head *list, struct session_info *info)
+logout_portal(idbm_t *db, void *data, struct list_head *list,
+	     struct session_info *info)
 {
 	struct node_rec *pattern_rec = data;
 	struct iscsi_transport *t;
 
-	t = iscsi_sysfs_get_transport_by_sid(info->sid);
+	t = get_transport_by_sid(info->sid);
 	if (!t)
 		return -1;
 
@@ -566,11 +616,11 @@
 {
 	int nr_found;
 
-	return __logout_portals(pattern_rec, &nr_found, logout_portal);
+	return __logout_portals(NULL, pattern_rec, &nr_found, logout_portal);
 }
 
 static struct node_rec *
-create_node_record(char *targetname, int tpgt, char *ip, int port,
+create_node_record(idbm_t *db, char *targetname, int tpgt, char *ip, int port,
 		   struct iface_rec *iface, int verbose)
 {
 	struct node_rec *rec;
@@ -591,9 +641,32 @@
 		strncpy(rec->conn[0].address, ip, NI_MAXHOST);
 	memset(&rec->iface, 0, sizeof(struct iface_rec));
 	if (iface) {
-		iface_copy(&rec->iface, iface);
-		if (strlen(iface->name)) {
-			if (iface_conf_read(&rec->iface)) {
+		if (!strlen(iface->name)) {
+			if (!iface_is_bound(iface))
+				/* copy transport name */
+				iface_copy(&rec->iface, iface);
+			else {
+				if (iface_get_by_bind_info(db, iface,
+							   &rec->iface)) {
+					if (verbose)
+						log_error("Could not find "
+							  "iface info.");
+					goto free_rec;
+				}
+			}
+		} else if (!strcmp(iface->name, DEFAULT_IFACENAME))
+			/*
+ 			 * default is a special name and should not be used by
+			 * a real iface
+			 */
+			iface_init(&rec->iface);
+		else {
+			/*
+			 * the initial iface update will not be able to find
+			 * by bind info because there is none.
+			 */
+			iface_copy(&rec->iface, iface);
+			if (iface_conf_read(db, &rec->iface)) {
 				if (verbose)
 					log_error("Could not read iface info "
 						  "for %s.", iface->name);
@@ -627,10 +700,10 @@
 	}
 
 	if (async_req)
-		rc = iscsid_req_by_rec_async(MGMT_IPC_SESSION_LOGIN,
-					     rec, &fd);
+		rc = iscsid_req_async(MGMT_IPC_SESSION_LOGIN,
+				      rec, &fd);
 	else
-		rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec);
+		rc = iscsid_req(MGMT_IPC_SESSION_LOGIN, rec);
 	/* we raced with another app or instance of iscsiadm */
 	if (rc == MGMT_IPC_ERR_EXISTS) {
 		if (async_req)
@@ -705,7 +778,7 @@
 }
 
 static int
-login_by_startup(char *mode)
+login_by_startup(idbm_t *db, char *mode)
 {
 	int nr_found = 0, rc, err;
 	struct list_head rec_list;
@@ -718,7 +791,7 @@
 	}
 
 	INIT_LIST_HEAD(&rec_list);
-	rc = idbm_for_each_rec(&nr_found, &rec_list, link_recs);
+	rc = idbm_for_each_rec(db, &nr_found, &rec_list, link_recs);
 	err = __login_portals(mode, &nr_found, &rec_list,
 			      __login_by_startup);
 	if (err && !rc)
@@ -733,7 +806,7 @@
 	return rc;
 }
 
-static int iface_fn(void *data, node_rec_t *rec)
+static int iface_fn(idbm_t *db, void *data, node_rec_t *rec)
 {
 	struct rec_op_data *op_data = data;
 
@@ -741,10 +814,10 @@
 				   rec->conn[0].address, rec->conn[0].port,
 				   &rec->iface))
 		return -1;
-	return op_data->fn(op_data->data, rec);
+	return op_data->fn(db, op_data->data, rec);
 }
 
-static int __for_each_rec(int verbose, struct node_rec *rec,
+static int __for_each_rec(idbm_t *db, int verbose, struct node_rec *rec,
 			  void *data, idbm_iface_op_fn *fn)
 {
 	struct rec_op_data op_data;
@@ -755,7 +828,7 @@
 	op_data.match_rec = rec;
 	op_data.fn = fn;
 
-	rc = idbm_for_each_rec(&nr_found, &op_data, iface_fn);
+	rc = idbm_for_each_rec(db, &nr_found, &op_data, iface_fn);
 	if (rc) {
 		if (verbose)
 			log_error("Could not execute operation on all "
@@ -769,20 +842,20 @@
 	return rc;
 }
 
-static int for_each_rec(struct node_rec *rec, void *data,
+static int for_each_rec(idbm_t *db, struct node_rec *rec, void *data,
 			idbm_iface_op_fn *fn)
 {
-	return __for_each_rec(1, rec, data, fn);
+	return __for_each_rec(db, 1, rec, data, fn);
 }
 
 
-static int login_portals(struct node_rec *pattern_rec)
+static int login_portals(idbm_t *db, struct node_rec *pattern_rec)
 {
 	struct list_head rec_list;
 	int err, ret, nr_found;
 
 	INIT_LIST_HEAD(&rec_list);
-	ret = for_each_rec(pattern_rec, &rec_list, link_recs);
+	ret = for_each_rec(db, pattern_rec, &rec_list, link_recs);
 	err = __login_portals(NULL, &nr_found, &rec_list,
 			      login_portal);
 	if (err && !ret)
@@ -790,7 +863,7 @@
 	return ret;
 }
 
-static int print_nodes(int info_level, struct node_rec *rec)
+static int print_nodes(idbm_t *db, int info_level, struct node_rec *rec)
 {
 	struct node_rec tmp_rec;
 	int rc = 0;
@@ -798,12 +871,12 @@
 	switch (info_level) {
 	case 0:
 	case -1:
-		if (for_each_rec(rec, NULL, idbm_print_node_flat))
+		if (for_each_rec(db, rec, NULL, idbm_print_node_flat))
 			rc = -1;
 		break;
 	case 1:
 		memset(&tmp_rec, 0, sizeof(node_rec_t));
-		if (for_each_rec(rec, &tmp_rec, idbm_print_node_tree))
+		if (for_each_rec(db, rec, &tmp_rec, idbm_print_node_tree))
 			rc = -1;
 		break;
 	default:
@@ -838,7 +911,7 @@
 static int print_session_flat(void *data, struct session_info *info)
 {
 	struct session_info *match_info = data;
-	struct iscsi_transport *t = iscsi_sysfs_get_transport_by_sid(info->sid);
+	struct iscsi_transport *t = get_transport_by_sid(info->sid);
 
 	if (match_info && match_info->sid != info->sid)
 		return 0;
@@ -895,7 +968,7 @@
 	state = NULL;
 
 	memset(state_buff, 0, SCSI_MAX_STATE_VALUE);
-	if (!iscsi_sysfs_get_session_state(state_buff, sid))
+	if (!get_session_state(state_buff, sid))
 		printf("\t\tiSCSI Session State: %s\n", state_buff);
 	else
 		printf("\t\tiSCSI Session State: Unknown\n");
@@ -913,8 +986,8 @@
 	struct iscsi_session_operational_config session_conf;
 	struct iscsi_conn_operational_config conn_conf;
 
-	iscsi_sysfs_get_negotiated_session_conf(sid, &session_conf);
-	iscsi_sysfs_get_negotiated_conn_conf(sid, &conn_conf);
+	get_negotiated_session_conf(sid, &session_conf);
+	get_negotiated_conn_conf(sid, &conn_conf);
 
 	printf("\t\t************************\n");
 	printf("\t\tNegotiated iSCSI params:\n");
@@ -954,12 +1027,12 @@
 	char *blockdev, state[SCSI_MAX_STATE_VALUE];
 
 	printf("\t\tscsi%d Channel 00 Id %d Lun: %d\n", host_no, target, lun);
-	blockdev = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun);
+	blockdev = get_blockdev_from_lun(host_no, target, lun);
 	if (blockdev) {
 		printf("\t\t\tAttached scsi disk %s\t\t", blockdev);
 		free(blockdev);
 
-		if (!iscsi_sysfs_get_device_state(state, host_no, target, lun))
+		if (!get_device_state(state, host_no, target, lun))
 			printf("State: %s\n", state);
 		else
 			printf("State: Unknown\n");
@@ -975,25 +1048,26 @@
 	printf("\t\tAttached SCSI devices:\n");
 	printf("\t\t************************\n");
 
-	host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err);
+	host_no = get_host_no_from_sid(sid, &err);
 	if (err) {
 		printf("\t\tHost No: Unknown\n");
 		return err;
 	}
 	printf("\t\tHost Number: %d\t", host_no);
-	if (!iscsi_sysfs_get_host_state(state, host_no))
+	if (!get_host_state(state, host_no))
 		printf("State: %s\n", state);
 	else
 		printf("State: Unknown\n");
 
-	iscsi_sysfs_for_each_device(host_no, sid, print_scsi_device_info);
+	sysfs_for_each_device(host_no, sid, print_scsi_device_info);
 	return 0;
 }
 
-static void print_sessions_tree(struct list_head *list, int level)
+static void print_sessions_tree(idbm_t *db, struct list_head *list, int level)
 {
 	struct session_info *curr, *prev = NULL, *tmp;
 	struct iscsi_transport *t;
+	struct iface_rec iface;
 
 	list_for_each_entry(curr, list, list) {
 		if (!prev || strcmp(prev->targetname, curr->targetname)) {
@@ -1021,15 +1095,19 @@
 		} else
 			printf("\n");
 
-		t = iscsi_sysfs_get_transport_by_sid(curr->sid);
+		t = get_transport_by_sid(curr->sid);
 
 		printf("\t\t**********\n");
 		printf("\t\tInterface:\n");
 		printf("\t\t**********\n");
-		if (strlen(curr->iface.name))
-			printf("\t\tIface Name: %s\n", curr->iface.name);
-		else
-			printf("\t\tIface Name: %s\n", UNKNOWN_VALUE);
+		if (iface_is_bound(&curr->iface)) {
+			memset(&iface, 0, sizeof(struct iface_rec));
+			if (iface_get_by_bind_info(db, &curr->iface, &iface))
+				printf("\t\tIface Name: %s\n", UNKNOWN_VALUE);
+			else
+				printf("\t\tIface Name: %s\n", iface.name);
+		} else
+			printf("\t\tIface Name: %s\n", DEFAULT_IFACENAME);
 		printf("\t\tIface Transport: %s\n",
 		       t ? t->name : UNKNOWN_VALUE);
 		printf("\t\tIface Initiatorname: %s\n",
@@ -1063,22 +1141,22 @@
 	}
 }
 
-static int print_sessions(int info_level, struct session_info *match_info)
+static int print_sessions(idbm_t *db, int info_level,
+			  struct session_info *match_info)
 {
 	struct list_head list;
 	int num_found = 0, err = 0;
-	char *version;
+	char version[20];
 
 	switch (info_level) {
 	case 0:
 	case -1:
-		err = iscsi_sysfs_for_each_session(match_info, &num_found,
-						   print_session_flat);
+		err = sysfs_for_each_session(match_info, &num_found,
+					     print_session_flat);
 		break;
 	case 2:
 	case 3:
-		version = iscsi_sysfs_get_iscsi_kernel_version();
-		if (version) {
+		if (!get_iscsi_kernel_version(version)) {
 			printf("iSCSI Transport Class version %s\n",
 				version);
 			printf("%s version %s\n", program_name,
@@ -1093,12 +1171,12 @@
 		link_info.list = &list;
 		link_info.match_info = match_info;
 
-		err = iscsi_sysfs_for_each_session(&link_info, &num_found,
-						   link_sessions);
+		err = sysfs_for_each_session(&link_info, &num_found,
+					    link_sessions);
 		if (err || !num_found)
 			break;
 
-		print_sessions_tree(&list, info_level);
+		print_sessions_tree(db, &list, info_level);
 		break;
 	default:
 		log_error("Invalid info level %d. Try 0 - 3.", info_level);
@@ -1124,16 +1202,15 @@
 		"%s,%d]\n", info->sid, info->targetname,
 		info->persistent_address, info->port);
 
-	host_no = iscsi_sysfs_get_host_no_from_sid(info->sid, &err);
+	host_no = get_host_no_from_sid(info->sid, &err);
 	if (err) {
 		log_error("Could not rescan session sid %d.", info->sid);
 		return err;
 	}
 	/* rescan each device to pick up size changes */
-	iscsi_sysfs_for_each_device(host_no, info->sid,
-				    iscsi_sysfs_rescan_device);
+	sysfs_for_each_device(host_no, info->sid, rescan_device);
 	/* now scan for new devices */
-	iscsi_sysfs_scan_host(host_no, 0);
+	scan_host(host_no, 0);
 	return 0;
 }
 
@@ -1222,7 +1299,7 @@
 	return 0;
 }
 
-static int add_static_rec(int *found, char *targetname, int tpgt,
+static int add_static_rec(idbm_t *db, int *found, char *targetname, int tpgt,
 			  char *ip, int port, struct iface_rec *iface)
 {
 	node_rec_t *rec;
@@ -1244,14 +1321,14 @@
 	}
 	drec->type = DISCOVERY_TYPE_STATIC;
 
-	idbm_node_setup_from_conf(rec);
+	idbm_node_setup_from_conf(db, rec);
 	strncpy(rec->name, targetname, TARGET_NAME_MAXLEN);
 	rec->tpgt = tpgt;
 	rec->conn[0].port = port;
 	strncpy(rec->conn[0].address, ip, NI_MAXHOST);
 
 	if (iface) {
-		rc = iface_conf_read(iface);
+		rc = iface_conf_read(db, iface);
 		if (rc) {
 			log_error("Could not read iface %s. Error %d",
 				  iface->name, rc);
@@ -1261,7 +1338,7 @@
 		iface_copy(&rec->iface, iface);
 	}
 
-	rc = idbm_add_node(rec, drec, 1);
+	rc = idbm_add_node(db, rec, drec, 1);
 	if (!rc) {
 		(*found)++;
 		printf("New iSCSI node [%s:" iface_fmt " %s,%d,%d %s] added\n",
@@ -1275,7 +1352,7 @@
 	return rc;
 }
 
-static int add_static_portal(int *found, void *data,
+static int add_static_portal(idbm_t *db, int *found, void *data,
 			     char *targetname, int tpgt, char *ip, int port)
 {
 	node_rec_t *rec = data;
@@ -1287,11 +1364,11 @@
 	if (rec->conn[0].port != -1 && rec->conn[0].port != port)
 		return 0;
 
-	return add_static_rec(found, targetname, tpgt, ip, port,
+	return add_static_rec(db, found, targetname, tpgt, ip, port,
 			      &rec->iface);
 }
 
-static int add_static_node(int *found, void *data,
+static int add_static_node(idbm_t *db, int *found, void *data,
 			  char *targetname)
 {
 	node_rec_t *rec = data;
@@ -1305,19 +1382,19 @@
 	if (!strlen(rec->conn[0].address))
 		goto search;
 
-	return add_static_rec(found, targetname, rec->tpgt,
+	return add_static_rec(db, found, targetname, rec->tpgt,
 			      rec->conn[0].address,
 			      rec->conn[0].port, &rec->iface);
 search:
-	return idbm_for_each_portal(found, data, add_static_portal,
+	return idbm_for_each_portal(db, found, data, add_static_portal,
 				    targetname);
 }
 
-static int add_static_recs(struct node_rec *rec)
+static int add_static_recs(idbm_t *db, struct node_rec *rec)
 {
 	int rc, nr_found = 0;
 
-	rc = idbm_for_each_node(&nr_found, rec, add_static_node);
+	rc = idbm_for_each_node(db, &nr_found, rec, add_static_node);
 	if (rc) {
 		log_error("Error while adding records. DB may be in an "
 			  "inconsistent state. Err %d", rc);
@@ -1329,7 +1406,7 @@
 
 	/* brand new target */
 	if (strlen(rec->name) && strlen(rec->conn[0].address)) {
-		rc = add_static_rec(&nr_found, rec->name, rec->tpgt,
+		rc = add_static_rec(db, &nr_found, rec->name, rec->tpgt,
 				    rec->conn[0].address, rec->conn[0].port,
 				    &rec->iface);
 		if (rc)
@@ -1346,10 +1423,11 @@
  * particular config
  */
 static int
-do_offload_sendtargets(discovery_rec_t *drec, int host_no, int do_login)
+do_offload_sendtargets(idbm_t *db, discovery_rec_t *drec,
+			int host_no, int do_login)
 {
 	drec->type = DISCOVERY_TYPE_OFFLOAD_SENDTARGETS;
-	return discovery_offload_sendtargets(host_no, do_login, drec);
+	return discovery_offload_sendtargets(db, host_no, do_login, drec);
 }
 
 static int login_discovered_portal(void *data, struct list_head *list,
@@ -1375,12 +1453,12 @@
 static int check_for_session_through_iface(struct node_rec *rec)
 {
 	int nr_found = 0;
-	if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session))
+	if (sysfs_for_each_session(rec, &nr_found, iscsi_match_session))
 		return 1;
 	return 0;
 }
 
-static int delete_node(void *data, struct node_rec *rec)
+static int delete_node(struct idbm *db, void *data, struct node_rec *rec)
 {
 	if (check_for_session_through_iface(rec)) {
 		/*
@@ -1397,10 +1475,10 @@
 		return EINVAL;
 	}
 
-	return idbm_delete_node(rec);
+	return idbm_delete_node(db, rec);
 }
 
-static int delete_stale_recs(void *data, struct node_rec *rec)
+static int delete_stale_recs(struct idbm *db, void *data, struct node_rec *rec)
 {
 	struct list_head *new_rec_list = data;
 	struct node_rec *new_rec;
@@ -1427,12 +1505,12 @@
 			return 0;
 	}
 	/* if there is a error we can continue on */
-	delete_node(NULL, rec);
+	delete_node(db, NULL, rec);
 	return 0;
 }
 
 static int
-update_discovery_recs(discovery_rec_t *drec,
+update_discovery_recs(idbm_t *db, discovery_rec_t *drec,
 		      struct list_head *new_rec_list, struct list_head *ifaces,
 		      int info_level, int do_login, int op)
 {
@@ -1444,7 +1522,7 @@
  
 	/* bind ifaces to node recs so we know what we have */
 	list_for_each_entry(new_rec, new_rec_list, list) {
-		rc = idbm_bind_ifaces_to_node(new_rec, ifaces,
+		rc = idbm_bind_ifaces_to_node(db, new_rec, ifaces,
 					      &bound_rec_list);
 		if (rc)
 			goto free_bound_recs;
@@ -1453,13 +1531,13 @@
 
 	/* clean up node db */
 	if (op & OP_DELETE)
-		idbm_for_each_rec(&found, &bound_rec_list,
+		idbm_for_each_rec(db, &found, &bound_rec_list,
 				  delete_stale_recs);
 
 	if (op & OP_NEW || op & OP_UPDATE) {
 		/* now add/update records */
 		list_for_each_entry(new_rec, &bound_rec_list, list) {
-			rc = idbm_add_node(new_rec, drec, op & OP_UPDATE);
+			rc = idbm_add_node(db, new_rec, drec, op & OP_UPDATE);
 			if (rc)
 				log_error("Could not add/update "
 					  "[%s:" iface_fmt " %s,%d,%d %s]",
@@ -1471,7 +1549,7 @@
 		}
 	}
 
-	idbm_print_discovered(drec, info_level);
+	idbm_print_discovered(db, drec, info_level);
 
 	if (!do_login) {
 		rc = 0;
@@ -1492,8 +1570,8 @@
 }
 
 static int
-do_sofware_sendtargets(discovery_rec_t *drec, struct list_head *ifaces,
-		       int info_level, int do_login,
+do_sofware_sendtargets(idbm_t *db, discovery_rec_t *drec,
+			struct list_head *ifaces, int info_level, int do_login,
 			int op)
 {
 	struct list_head new_rec_list;
@@ -1509,17 +1587,17 @@
 		op = OP_NEW | OP_DELETE | OP_UPDATE;
 
 	drec->type = DISCOVERY_TYPE_SENDTARGETS;
-	rc = discovery_sendtargets(drec, &new_rec_list);
+	rc = discovery_sendtargets(db, drec, &new_rec_list);
 	if (rc)
 		return rc;
 
-	rc = idbm_add_discovery(drec, op & OP_UPDATE);
+	rc = idbm_add_discovery(db, drec, op & OP_UPDATE);
 	if (rc) {
 		log_error("Could not add new discovery record.");
 		goto free_new_recs;
 	}
 
-	rc = update_discovery_recs(drec, &new_rec_list, ifaces,
+	rc = update_discovery_recs(db, drec, &new_rec_list, ifaces,
 				   info_level, do_login, op);
 
 free_new_recs:
@@ -1531,7 +1609,7 @@
 }
 
 static int
-do_sendtargets(discovery_rec_t *drec, struct list_head *ifaces,
+do_sendtargets(idbm_t *db, discovery_rec_t *drec, struct list_head *ifaces,
 	       int info_level, int do_login, int op)
 {
 	struct iface_rec *tmp, *iface;
@@ -1545,7 +1623,7 @@
 
 	/* we allow users to mix hw and sw iscsi so we have to sort it out */
 	list_for_each_entry_safe(iface, tmp, ifaces, list) {
-		rc = iface_conf_read(iface);
+		rc = iface_conf_read(db, iface);
 		if (rc) {
 			log_error("Could not read iface info for %s. "
 				  "Make sure a iface config with the file "
@@ -1556,7 +1634,11 @@
 			continue;
 		}
 
-		host_no = iscsi_sysfs_get_host_no_from_iface(iface, &rc);
+		/* if no binding it must be software */
+		if (!iface_is_bound(iface))
+			continue;
+
+		host_no = get_host_no_from_iface(iface, &rc);
 		if (rc || host_no == -1) {
 			log_debug(1, "Could not match iface" iface_fmt " to "
 				  "host.", iface_str(iface)); 
@@ -1564,7 +1646,7 @@
 			continue;
 		}
 
-		t = iscsi_sysfs_get_transport_by_hba(host_no);
+		t = get_transport_by_hba(host_no);
 		if (!t) {
 			log_error("Could not match hostno %d to "
 				  "transport. Dropping interface %s,"
@@ -1577,7 +1659,8 @@
 		}
 
 		if (t->caps & CAP_SENDTARGETS_OFFLOAD) {
-			do_offload_sendtargets(drec, host_no, do_login);
+			do_offload_sendtargets(db, drec, host_no,
+					       do_login);
 			list_del(&iface->list);
 			free(iface);
 		}
@@ -1587,7 +1670,7 @@
 		return ENODEV;
 
 sw_st:
-	return do_sofware_sendtargets(drec, ifaces, info_level, do_login,
+	return do_sofware_sendtargets(db, drec, ifaces, info_level, do_login,
 				      op);
 }
 
@@ -1597,17 +1680,17 @@
 	switch (info_level) {
 	case -1:
 	case 0:
-		idbm_print_node_flat(NULL, rec);
+		idbm_print_node_flat(NULL, NULL, rec);
 		break;
 	case 1:
-		idbm_print_node_tree(NULL, rec);
+		idbm_print_node_tree(NULL, NULL, rec);
 		break;
 	default:
 		log_error("Invalid print level %d. Try 0 or 1.", info_level);
 	}
 }
 
-static int isns_dev_attr_query(discovery_rec_t *drec,
+static int isns_dev_attr_query(idbm_t *db, discovery_rec_t *drec,
 			       int info_level)
 {
 	iscsiadm_req_t req;
@@ -1622,7 +1705,7 @@
 		iscsid_handle_error(err);
 		return EIO;
 	} else {
-		idbm_print_discovered(drec, info_level);
+		idbm_print_discovered(db, drec, info_level);
 		return 0;
 	}
 }
@@ -1654,7 +1737,7 @@
 }
 
 /* TODO: merge iter helpers and clean them up, so we can use them here */
-static int exec_iface_op(int op, int do_show, int info_level,
+static int exec_iface_op(idbm_t *db, int op, int do_show, int info_level,
 			 struct iface_rec *iface, char *name, char *value)
 {
 	struct db_set_param set_param;
@@ -1669,14 +1752,17 @@
 			return EINVAL;
 		}
 
-		rec = create_node_record(NULL, -1, NULL, -1, iface, 0);
-		if (rec && check_for_session_through_iface(rec)) {
-			rc = EBUSY;
-			goto new_fail;
+		rec = create_node_record(db, NULL, -1, NULL, -1, iface, 0);
+		if (rec && iface_is_bound(&rec->iface)) {
+			if (check_for_session_through_iface(rec)) {
+				rc = EBUSY;
+				goto new_fail;
+			}
+			log_warning("Overwriting existing %s.", iface->name);
 		}
 
-		iface_setup_defaults(iface);
-		rc = iface_conf_write(iface);
+		iface_init(iface);
+		rc = iface_conf_write(db, iface);
 		if (rc)
 			goto new_fail;
 		printf("New interface %s added\n", iface->name);
@@ -1691,18 +1777,20 @@
 			return EINVAL;
 		}
 
-		rec = create_node_record(NULL, -1, NULL, -1, iface, 1);
+		rec = create_node_record(db, NULL, -1, NULL, -1, iface, 1);
 		if (!rec) {
 			rc = EINVAL;
 			goto delete_fail;
 		}
 
-		/* logout and delete records using it first */
-		rc = __for_each_rec(0, rec, NULL, delete_node);
-		if (rc && rc != ENODEV)
-			goto delete_fail;
+		if (iface_is_bound(&rec->iface)) {
+			/* logout and delete records using it first */
+			rc = __for_each_rec(db, 0, rec, NULL, delete_node);
+			if (rc && rc != ENODEV)
+				goto delete_fail;
+		}
 
-		rc = iface_conf_delete(iface);
+		rc = iface_conf_delete(db, iface);
 		if (rc)
 			goto delete_fail;
 
@@ -1720,53 +1808,57 @@
 			break;
 		}
 
-		rec = create_node_record(NULL, -1, NULL, -1, iface, 1);
+		rec = create_node_record(db, NULL, -1, NULL, -1, iface, 1);
 		if (!rec) {
 			rc = EINVAL;
 			goto update_fail;
 		}
 
-		if (check_for_session_through_iface(rec)) {
-			rc = EINVAL;
-			goto update_fail;
-		}
+		if (iface_is_bound(&rec->iface)) {
+			if (check_for_session_through_iface(rec)) {
+				rc = EINVAL;
+				goto update_fail;
+			}
 
-		if (!strcmp(name, "iface.iscsi_ifacename")) {
-			log_error("Can not update "
-				  "iface.iscsi_ifacename. Delete it, "
-				  "and then create a new one.");
-			rc = EINVAL;
-			break;
-		}
+			if (!strcmp(name, "iface.iscsi_ifacename")) {
+				log_error("Can not update "
+					  "iface.iscsi_ifacename. Delete it, "
+					  "and then create a new one.");
+				rc = EINVAL;
+				break;
+			}
 
-		if (iface_is_bound_by_hwaddr(&rec->iface) &&
-		    !strcmp(name, "iface.net_ifacename")) {
-			log_error("Can not update interface binding "
-				  "from hwaddress to net_ifacename. ");
-			log_error("You must delete the interface and "
-				  "create a new one");
-			rc = EINVAL;
-			break;
-		}
+			if (iface_is_bound_by_hwaddr(&rec->iface) &&
+			    !strcmp(name, "iface.net_ifacename")) {
+				log_error("Can not update interface binding "
+					  "from hwaddress to net_ifacename. ");
+				log_error("You must delete the interface and "
+					  "create a new one");
+				rc = EINVAL;
+				break;
+			}
 
-		if (iface_is_bound_by_netdev(&rec->iface) &&
-		    !strcmp(name, "iface.hwaddress")) {
-			log_error("Can not update interface binding "
-				  "from net_ifacename to hwaddress. ");
-			log_error("You must delete the interface and "
-				  "create a new one");
-			rc = EINVAL;
-			break;
+			if (iface_is_bound_by_netdev(&rec->iface) &&
+			    !strcmp(name, "iface.hwaddress")) {
+				log_error("Can not update interface binding "
+					  "from net_ifacename to hwaddress. ");
+				log_error("You must delete the interface and "
+					  "create a new one");
+				rc = EINVAL;
+				break;
+			}
 		}
+		set_param.db = db;
 		set_param.name = name;
 		set_param.value = value;
 
 		/* pass rec's iface because it has the db values */
-		rc = iface_conf_update(&set_param, &rec->iface);
+		rc = iface_conf_update(db, &set_param, &rec->iface);
 		if (rc)
 			goto update_fail;
 
-		rc = __for_each_rec(0, rec, &set_param, idbm_node_set_param);
+		rc = __for_each_rec(db, 0, rec, &set_param,
+				    idbm_node_set_param);
 		if (rc && rc != ENODEV)
 			goto update_fail;
 
@@ -1780,13 +1872,13 @@
 	default:
 		if (!iface) {
 			if (op == OP_NOOP || op == OP_SHOW)
-				rc = print_ifaces(info_level);
+				rc = print_ifaces(db, info_level);
 			else
 				rc = EINVAL;
 		} else {
-			rc = iface_conf_read(iface);
+			rc = iface_conf_read(db, iface);
 			if (!rc)
-				idbm_print_iface_info(&do_show, iface);
+				idbm_print_iface_info(db, &do_show, iface);
 			else
 				log_error("Could not read iface %s (%d).",
 					  iface->name, rc);
@@ -1799,7 +1891,7 @@
 }
 
 /* TODO cleanup arguments */
-static int exec_node_op(int op, int do_login, int do_logout,
+static int exec_node_op(idbm_t *db, int op, int do_login, int do_logout,
 			int do_show, int do_rescan, int do_stats,
 			int info_level, struct node_rec *rec,
 			char *name, char *value)
@@ -1813,7 +1905,7 @@
 			  rec->name, rec->conn[0].address, rec->conn[0].port);
 
 	if (op == OP_NEW) {
-		if (add_static_recs(rec))
+		if (add_static_recs(db, rec))
 			rc = -1;
 		goto out;
 	}
@@ -1846,12 +1938,12 @@
 	if ((!do_login && !do_logout && op == OP_NOOP) &&
 	    (!strlen(rec->name) && !strlen(rec->conn[0].address) &&
 	     !strlen(rec->iface.name))) {
-		rc = print_nodes(info_level, rec);
+		rc = print_nodes(db, info_level, rec);
 		goto out;
 	}
 
 	if (do_login) {
-		if (login_portals(rec))
+		if (login_portals(db, rec))
 			rc = -1;
 		goto out;
 	}
@@ -1863,7 +1955,7 @@
 	}
 
 	if (op == OP_NOOP || (!do_login && !do_logout && op == OP_SHOW)) {
-		if (for_each_rec(rec, &do_show, idbm_print_node_info))
+		if (for_each_rec(db, rec, &do_show, idbm_print_node_info))
 			rc = -1;
 		goto out;
 	}
@@ -1875,44 +1967,31 @@
 			goto out;
 		}
 
-		/* compat - old tools used node and iface transport name */
+		/*
+		 * We do not export the iscsiadm iface.iscsi_ifacename
+		 * in sysfs because it is iscsiadm specific abstraction.
+		 * To work around this, we do some hacky matching by bind
+		 * info. As a result we cannot change the iface binding
+		 * values here and must do it in iface mode which will do
+		 * the right thing.
+		 */
 		if (!strncmp(name, "iface.", 6) &&
-		     strcmp(name, "iface.transport_name")) {
+		    strcmp(name, "iface.transport_name")) {
 			log_error("Cannot modify %s. Use iface mode to update "
 				  "this value.", name);
 			rc = -1;
 			goto out;
 		}
 
-		if (!strcmp(name, "node.transport_name"))
-			name = "iface.transport_name";
-		/*
-		 * tmp hack - we added compat crap above for the transport,
-		 * but want to fix Doran's issue in this release too. However
-		 * his patch is too harsh on many settings and we do not have
-		 * time to update apps so we have this tmp hack until we
-		 * can settle on a good interface that distros can use
-		 * and we can mark stable.
-		 */
-		if (!strcmp(name, "iface.transport_name")) {
-			if (check_for_session_through_iface(rec)) {
-				log_warning("Cannot modify node/iface "
-					    "transport name while a session "
-					    "is using it. Log out the session "
-					    "then update record.");
-				rc = -1;
-				goto out;
-			}
-		}
-
+		set_param.db = db;
 		set_param.name = name;
 		set_param.value = value;
 
-		if (for_each_rec(rec, &set_param, idbm_node_set_param))	
+		if (for_each_rec(db, rec, &set_param, idbm_node_set_param))	
 			rc = -1;
 		goto out;
 	} else if (op == OP_DELETE) {
-		if (for_each_rec(rec, NULL, delete_node))
+		if (for_each_rec(db, rec, NULL, delete_node))
 			rc = -1;
 		goto out;
 	} else {
@@ -1925,12 +2004,12 @@
 }
 
 static struct node_rec *
-fw_create_rec_by_entry(struct boot_context *context)
+fw_create_rec_by_entry(idbm_t *db, struct boot_context *context)
 {
 	struct node_rec *rec;
 
 	/* tpgt hard coded to 1 ??? */
-	rec = create_node_record(context->targetname, 1,
+	rec = create_node_record(db, context->targetname, 1,
 				 context->target_ipaddr, context->target_port,
 				 NULL, 1);
 	if (!rec) {
@@ -1939,7 +2018,7 @@
 	}
 
 	/* todo - grab mac and set that here */
-	iface_setup_defaults(&rec->iface);
+	iface_init(&rec->iface);
 	strncpy(rec->iface.iname, context->initiatorname,
 		sizeof(context->initiatorname));
 	strncpy(rec->session.auth.username, context->chap_name,
@@ -1958,7 +2037,8 @@
 	return rec;
 }
 
-static int exec_fw_op(discovery_rec_t *drec, int do_login, int info_level)
+static int exec_fw_op(idbm_t *db, discovery_rec_t *drec, int do_login,
+		     int info_level)
 {
 	struct boot_context context;
 	struct node_rec *rec;
@@ -1971,7 +2051,7 @@
 		return ret;
 	}
 
-	rec = fw_create_rec_by_entry(&context);
+	rec = fw_create_rec_by_entry(db, &context);
 	if (!rec)
 		return ENODEV;
 
@@ -1980,7 +2060,7 @@
 		print_fw_nodes(rec, info_level);
 
 	if (do_login)
-		ret = login_portal(NULL, NULL, rec);
+		ret = login_portal(db, NULL, rec);
 	free(rec);
 
 	/* print the fw node info if called in fw mode with no params */
@@ -1989,6 +2069,56 @@
 	return ret;
 }
 
+static int parse_sid(char *session)
+{
+	struct stat statb;
+	char sys_session[64], *start, *last;
+	int sid = -1, len;
+
+	if (stat(session, &statb)) {
+		log_debug(1, "Could not stat %s failed with %d",
+			  session, errno);
+		if (index(session, '/')) {
+			log_error("%s is an invalid session path\n", session);
+			exit(1);
+		}
+		return atoi(session);
+	}
+
+	if (!S_ISDIR(statb.st_mode)) {
+		log_error("%s is not a directory", session);
+		exit(1);
+	}
+
+	/*
+	 * Given sysfs_device is a directory name of the form:
+	 *
+	 * /sys/devices/platform/hostH/sessionS/targetH:B:I/H:B:I:L
+	 * /sys/devices/platform/hostH/sessionS/targetH:B:I
+	 * /sys/devices/platform/hostH/sessionS
+	 *
+	 * We want to set sys_session to sessionS
+	 */
+	last = NULL;
+	start = strstr(session, "session");
+	if (start && strncmp(start, "session", 7) == 0) {
+		len = strlen(start);
+		last = index(start, '/');
+		/*
+		 * If '/' not found last is NULL.
+		 */
+		if (last)
+			len = last - start;
+		strncpy(sys_session, start, len);
+	} else {
+		log_error("Unable to find session in %s", session);
+		exit(1);
+	}
+
+	sscanf(sys_session, "session%d", &sid);
+	return sid;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1998,6 +2128,7 @@
 	int rc=0, sid=-1, op=OP_NOOP, type=-1, do_logout=0, do_stats=0;
 	int do_login_all=0, do_logout_all=0, info_level=-1, num_ifaces = 0;
 	int tpgt = PORTAL_GROUP_TAG_UNKNOWN, killiscsid=-1, do_show=0;
+	idbm_t *db = NULL;
 	struct sigaction sa_old;
 	struct sigaction sa_new;
 	discovery_rec_t drec;
@@ -2020,7 +2151,6 @@
 	/* enable stdout logging */
 	log_daemon = 0;
 	log_init(program_name, 1024);
-	sysfs_init();
 
 	optopt = 0;
 	while ((ch = getopt_long(argc, argv, short_options,
@@ -2032,8 +2162,7 @@
 				log_error("Invalid killiscsid priority %d "
 					  "Priority must be greater than or "
 					  "equal to zero.", killiscsid);
-				rc = -1;
-				goto free_ifaces;
+				exit(-1);
 			}
 			break;
 		case 't':
@@ -2044,8 +2173,7 @@
 			if (op == OP_NOOP) {
 				log_error("can not recognize operation: '%s'",
 					optarg);
-				rc = -1;
-				goto free_ifaces;
+				return -1;
 			}
 			break;
 		case 'n':
@@ -2055,12 +2183,11 @@
 			value = optarg;
 			break;
 		case 'r':
-			sid = iscsi_sysfs_get_sid_from_path(optarg);
+			sid = parse_sid(optarg);
 			if (sid < 0) {
 				log_error("invalid sid '%s'",
 					  optarg);
-				rc = -1;
-				goto free_ifaces;
+				return -1;
 			}
 			break;
 		case 'R':
@@ -2129,8 +2256,7 @@
 
 	if (optopt) {
 		log_error("unrecognized character '%c'", optopt);
-		rc = -1;
-		goto free_ifaces;
+		return -1;
 	}
 
 	if (killiscsid >= 0) {
@@ -2146,21 +2272,21 @@
 			log_error("fw mode: option '-%c' is not "
 				  "allowed/supported", rc);
 			rc = -1;
-			goto free_ifaces;
+			goto out;
 		}
 
-		rc = exec_fw_op(NULL, do_login, info_level);
-		goto free_ifaces;
+		rc = exec_fw_op(db, NULL, do_login, info_level);
+		goto out;
 	}
 
 	increase_max_files();
-	if (idbm_init(get_config_file)) {
+	db = idbm_init(get_config_file);
+	if (!db) {
 		log_warning("exiting due to idbm configuration error");
-		rc = -1;
-		goto free_ifaces;
+		return -1;
 	}
 
-	iface_setup_host_bindings();
+	iface_setup_host_bindings(db);
 
 	switch (mode) {
 	case MODE_IFACE:
@@ -2179,7 +2305,7 @@
 					  "interface. Using the first one "
 					  "%s.", iface->name);
 		}
-		rc = exec_iface_op(op, do_show, info_level, iface,
+		rc = exec_iface_op(db, op, do_show, info_level, iface,
 				   name, value);
 		break;
 	case MODE_DISCOVERY:
@@ -2199,11 +2325,11 @@
 			}
 
 			memset(&drec, 0, sizeof(discovery_rec_t));
-			idbm_sendtargets_defaults(&drec.u.sendtargets);
+			idbm_sendtargets_defaults(db, &drec.u.sendtargets);
 			strncpy(drec.address, ip, sizeof(drec.address));
 			drec.port = port;
 
-			if (do_sendtargets(&drec, &ifaces, info_level,
+			if (do_sendtargets(db, &drec, &ifaces, info_level,
 					   do_login, op)) {
 				rc = -1;
 				goto out;
@@ -2217,17 +2343,17 @@
 		case DISCOVERY_TYPE_ISNS:
 			drec.type = DISCOVERY_TYPE_ISNS;
 
-			if (isns_dev_attr_query(&drec, info_level))
+			if (isns_dev_attr_query(db, &drec, info_level))
 				rc = -1;
 			break;
 		case DISCOVERY_TYPE_FWBOOT:
 			drec.type = DISCOVERY_TYPE_FWBOOT;
-			if (exec_fw_op(&drec, do_login, info_level))
+			if (exec_fw_op(db, &drec, do_login, info_level))
 				rc = -1;
 			break;
 		default:
 			if (ip) {
-				if (idbm_discovery_read(&drec, ip, port)) {
+				if (idbm_discovery_read(db, &drec, ip, port)) {
 					log_error("discovery record [%s,%d] "
 						  "not found!", ip, port);
 					rc = -1;
@@ -2235,7 +2361,7 @@
 				}
 				if (do_login &&
 				    drec.type == DISCOVERY_TYPE_SENDTARGETS) {
-					do_sendtargets(&drec, &ifaces,
+					do_sendtargets(db, &drec, &ifaces,
 							info_level, do_login,
 							op);
 				} else if (do_login &&
@@ -2251,13 +2377,13 @@
 					rc = -1;
 					goto out;
 				} else if (op == OP_NOOP || op == OP_SHOW) {
-					if (!idbm_print_discovery_info(&drec,
-								do_show)) {
+					if (!idbm_print_discovery_info(db,
+							&drec, do_show)) {
 						log_error("no records found!");
 						rc = -1;
 					}
 				} else if (op == OP_DELETE) {
-					if (idbm_delete_discovery(&drec)) {
+					if (idbm_delete_discovery(db, &drec)) {
 						log_error("unable to delete "
 							   "record!");
 						rc = -1;
@@ -2269,7 +2395,7 @@
 				}
 
 			} else if (op == OP_NOOP || op == OP_SHOW) {
-				if (!idbm_print_all_discovery(info_level))
+				if (!idbm_print_all_discovery(db, info_level))
 					rc = -1;
 				goto out;
 			} else if (op == OP_DELETE) {
@@ -2296,12 +2422,12 @@
 		}
 
 		if (do_login_all) {
-			rc = login_by_startup(group_session_mgmt_mode);
+			rc = login_by_startup(db, group_session_mgmt_mode);
 			goto out;
 		}
 
 		if (do_logout_all) {
-			rc = logout_by_startup(group_session_mgmt_mode);
+			rc = logout_by_startup(db, group_session_mgmt_mode);
 			goto out;
 		}
 
@@ -2316,13 +2442,14 @@
 					  iface->hwaddress, iface->ipaddress);
 		}
 
-		rec = create_node_record(targetname, tpgt, ip, port, iface, 1);
+		rec = create_node_record(db, targetname, tpgt, ip, port,
+					 iface, 1);
 		if (!rec) {
 			rc = -1;
 			goto out;
 		}
 
-		rc = exec_node_op(op, do_login, do_logout, do_show,
+		rc = exec_node_op(db, op, do_login, do_logout, do_show,
 				  do_rescan, do_stats, info_level, rec,
 				  name, value);
 		break;
@@ -2347,7 +2474,7 @@
 				goto out;
 			}
 
-			rc = iscsi_sysfs_get_sessioninfo_by_id(info, session);
+			rc = get_sessioninfo_by_sysfs_id(info, session);
 			if (rc) {
 				log_error("Could not get session info for sid "
 					  "%d", sid);
@@ -2359,18 +2486,18 @@
 			 * we only support session mode ops if the module
 			 * is loaded and we support that module.
 			 */
-			if (!iscsi_sysfs_get_transport_by_sid(sid))
+			if (!get_transport_by_sid(sid))
 				goto free_info;
 
 			if (!do_logout && !do_rescan && !do_stats &&
 			    op == OP_NOOP && info_level > 0) {
-				rc = print_sessions(info_level, info);
+				rc = print_sessions(db, info_level, info);
 				if (rc)
 					rc = -1;
 				goto free_info;
 			}
 
-			rec = create_node_record(info->targetname,
+			rec = create_node_record(db, info->targetname,
 						 info->tpgt,
 						 info->persistent_address,
 						 info->persistent_port,
@@ -2381,7 +2508,7 @@
 			}
 
 			/* drop down to node ops */
-			rc = exec_node_op(op, do_login, do_logout, do_show,
+			rc = exec_node_op(db, op, do_login, do_logout, do_show,
 					  do_rescan, do_stats, info_level,
 					  rec, name, value);
 free_info:
@@ -2389,13 +2516,13 @@
 			goto out;
 		} else {
 			if (do_logout || do_rescan || do_stats) {
-				rc = exec_node_op(op, do_login, do_logout,
+				rc = exec_node_op(db, op, do_login, do_logout,
 						 do_show, do_rescan, do_stats,
 						 info_level, NULL, name, value);
 				goto out;
 			}
 
-			rc = print_sessions(info_level, NULL);
+			rc = print_sessions(db, info_level, NULL);
 		}
 		break;
 	default:
@@ -2406,13 +2533,12 @@
 out:
 	if (rec)
 		free(rec);
-	idbm_terminate();
+	idbm_terminate(db);
 free_ifaces:
 	list_for_each_entry_safe(iface, tmp, &ifaces, list) {
 		list_del(&iface->list);
 		free(iface);
 	}
 	free_transports();
-	sysfs_cleanup();
 	return rc;
 }
--- open-iscsi-2.0.870~rc3.orig/usr/iscsiadm.h
+++ open-iscsi-2.0.870~rc3/usr/iscsiadm.h
@@ -24,11 +24,12 @@
 #include "config.h"
 
 /* discovery.c */
+struct idbm;
 struct discovery_rec;
 struct list_head;
 
-extern int discovery_sendtargets(struct discovery_rec *drec,
+extern int discovery_sendtargets(struct idbm *db, struct discovery_rec *drec,
 				 struct list_head *rec_list);
-extern int discovery_offload_sendtargets(int host_no, int do_login,
-					 discovery_rec_t *drec);
+extern int discovery_offload_sendtargets(struct idbm *db, int host_no,
+					 int do_login, discovery_rec_t *drec);
 #endif /* ISCSIADM_H */
--- open-iscsi-2.0.870~rc3.orig/usr/iscsid.c
+++ open-iscsi-2.0.870~rc3/usr/iscsid.c
@@ -40,7 +40,6 @@
 #include "idbm.h"
 #include "version.h"
 #include "iscsi_sysfs.h"
-#include "iface.h"
 
 /* global config info */
 struct iscsi_daemon_config daemon_config;
@@ -89,13 +88,14 @@
 }
 
 static void
-setup_rec_from_negotiated_values(node_rec_t *rec, struct session_info *info)
+setup_rec_from_negotiated_values(idbm_t *db, node_rec_t *rec,
+				struct session_info *info)
 {
 	struct iscsi_session_operational_config session_conf;
 	struct iscsi_conn_operational_config conn_conf;
 	struct iscsi_auth_config auth_conf;
 
-	idbm_node_setup_from_conf(rec);
+	idbm_node_setup_from_conf(db, rec);
 	strncpy(rec->name, info->targetname, TARGET_NAME_MAXLEN);
 	rec->conn[0].port = info->persistent_port;
 	strncpy(rec->conn[0].address, info->persistent_address, NI_MAXHOST);
@@ -103,9 +103,9 @@
 	rec->tpgt = info->tpgt;
 	iface_copy(&rec->iface, &info->iface);
 
-	iscsi_sysfs_get_negotiated_session_conf(info->sid, &session_conf);
-	iscsi_sysfs_get_negotiated_conn_conf(info->sid, &conn_conf);
-	iscsi_sysfs_get_auth_conf(info->sid, &auth_conf);
+	get_negotiated_session_conf(info->sid, &session_conf);
+	get_negotiated_conn_conf(info->sid, &conn_conf);
+	get_auth_conf(info->sid, &auth_conf);
 
 	if (strlen(auth_conf.username))
 		strcpy(rec->session.auth.username, auth_conf.username);
@@ -176,6 +176,7 @@
 
 static int sync_session(void *data, struct session_info *info)
 {
+	idbm_t *db = data;
 	node_rec_t rec, sysfsrec;
 	iscsiadm_req_t req;
 	iscsiadm_rsp_t rsp;
@@ -185,7 +186,7 @@
 		  info->targetname, info->persistent_address,
 		  info->port, info->iface.hwaddress);
 
-	t = iscsi_sysfs_get_transport_by_sid(info->sid);
+	t = get_transport_by_sid(info->sid);
 	if (!t)
 		return 0;
 
@@ -197,23 +198,27 @@
 		uint32_t host_no;
 		int err;
 
-		host_no = iscsi_sysfs_get_host_no_from_sid(info->sid, &err);
+		host_no = get_host_no_from_sid(info->sid, &err);
 		if (err) {
 			log_error("Could not get host no from sid %u. Can not "
 				  "sync session. Error %d", info->sid, err);
 			return 0;
 		}
-		iscsi_sysfs_scan_host(host_no, 0);
+		scan_host(host_no, 0);
 		return 0;
 	}
 
 	memset(&rec, 0, sizeof(node_rec_t));
-	if (idbm_rec_read(&rec, info->targetname, info->tpgt,
+	if (iface_get_by_bind_info(db, &info->iface, &rec.iface)) {
+		log_warning("Could not read data from db. Using default and "
+			    "currently negotiated values\n");
+		setup_rec_from_negotiated_values(db, &rec, info);
+	} else if (idbm_rec_read(db, &rec, info->targetname, info->tpgt,
 			  info->persistent_address, info->persistent_port,
-			  &info->iface)) {
+			  &rec.iface)) {
 		log_warning("Could not read data from db. Using default and "
 			    "currently negotiated values\n");
-		setup_rec_from_negotiated_values(&rec, info);
+		setup_rec_from_negotiated_values(db, &rec, info);
 	} else {
 		/*
 		 * we have a valid record and iface so lets merge
@@ -227,7 +232,7 @@
 		 * those values from sysfs.
 		 */
 		memset(&sysfsrec, 0, sizeof(node_rec_t));
-		setup_rec_from_negotiated_values(&sysfsrec, info);
+		setup_rec_from_negotiated_values(db, &sysfsrec, info);
 		/*
 		 * target and portal values have to be the same or
 		 * we would not have found the record, so just copy
@@ -261,6 +266,18 @@
 	return daemon_config.config_file;
 }
 
+static void sync_sessions(void)
+{
+	idbm_t *db;
+	int nr_found = 0;
+
+	db = idbm_init(iscsid_get_config_file);
+	if (!db)
+		return;
+	sysfs_for_each_session(db, &nr_found, sync_session);
+	idbm_terminate(db);
+}
+
 static void iscsid_exit(void)
 {
 	isns_exit();
@@ -373,14 +390,7 @@
 	log_pid = log_init(program_name, DEFAULT_AREA_SIZE);
 	if (log_pid < 0)
 		exit(1);
-
-	sysfs_init();
-	if (idbm_init(iscsid_get_config_file)) {
-		log_close(log_pid);
-		exit(1);
-	}
-
-	if (iscsi_sysfs_check_class_version()) {
+	if (check_class_version()) {
 		log_close(log_pid);
 		exit(1);
 	}
@@ -476,9 +486,8 @@
 
 	pid = fork();
 	if (pid == 0) {
-		int nr_found = 0;
 		/* child */
-		iscsi_sysfs_for_each_session(NULL, &nr_found, sync_session);
+		sync_sessions();
 		exit(0);
 	} else if (pid < 0) {
 		log_error("Fork failed error %d: existing sessions"
@@ -502,7 +511,5 @@
 	isns_fd = isns_init();
 	event_loop(ipc, control_fd, mgmt_ipc_fd, isns_fd);
 	iscsid_shutdown();
-	idbm_terminate();
-	sysfs_cleanup();
 	return 0;
 }
--- open-iscsi-2.0.870~rc3.orig/usr/iscsistart.c
+++ open-iscsi-2.0.870~rc3/usr/iscsistart.c
@@ -314,8 +314,7 @@
 	log_daemon = 0;
 	log_init(program_name, DEFAULT_AREA_SIZE);
 
-	sysfs_init();
-	if (iscsi_sysfs_check_class_version())
+	if (check_class_version())
 		exit(1);
 
 	if (check_params(initiatorname))
@@ -388,7 +387,6 @@
 	ipc->ctldev_close();
 	mgmt_ipc_close(mgmt_ipc_fd);
 	free_initiator();
-	sysfs_cleanup();
 
 	log_debug(1, "iscsi child done");
 	return 0;
--- open-iscsi-2.0.870~rc3.orig/usr/isns.c
+++ open-iscsi-2.0.870~rc3/usr/isns.c
@@ -282,6 +282,7 @@
 	int err;
 	node_rec_t rec;
 	discovery_rec_t drec;
+	idbm_t *db;
 	char dst[INET6_ADDRSTRLEN];
 
 	memset(dst, 0, sizeof(dst));
@@ -296,12 +297,13 @@
 	log_debug(1, "add a new target node:%s %s,%d %d",
 		  targetname, dst, port, tag);
 
-	if (idbm_init(isns_get_config_file)) {
+	db = idbm_init(isns_get_config_file);
+	if (!db) {
 		log_error("Could not add new target node:%s %s,%d",
 			  targetname, dst, port);
 		return;
 	}
-	idbm_node_setup_from_conf(&rec);
+	idbm_node_setup_from_conf(db, &rec);
 	strncpy(rec.name, targetname, TARGET_NAME_MAXLEN);
 	rec.conn[0].port = port;
 	rec.tpgt = tag;
@@ -310,12 +312,12 @@
 	/* TODO?: shoudl we set the address and port of the server ? */
 	memset(&drec, 0, sizeof(discovery_rec_t));
 	drec.type = DISCOVERY_TYPE_ISNS;
-	err = idbm_add_nodes(&rec, &drec, NULL, 0);
+	err = idbm_add_nodes(db, &rec, &drec, NULL, 0);
 	if (err)
 		log_error("Could not add new target node:%s %s,%d",
 			  targetname, dst, port);
 
-	idbm_terminate();
+	idbm_terminate(db);
 }
 
 static int qry_rsp_handle(struct isns_hdr *hdr)
--- open-iscsi-2.0.870~rc3.orig/usr/log.c
+++ open-iscsi-2.0.870~rc3/usr/log.c
@@ -71,14 +71,11 @@
 	logdbg(stderr,"enter logarea_init\n");
 
 	if ((shmid = shmget(IPC_PRIVATE, sizeof(struct logarea),
-			    0644 | IPC_CREAT | IPC_EXCL)) == -1) {
-		syslog(LOG_ERR, "shmget logarea failed %d", errno);
+			    0644 | IPC_CREAT | IPC_EXCL)) == -1)
 		return 1;
-	}
 
 	la = shmat(shmid, NULL, 0);
 	if (!la) {
-		syslog(LOG_ERR, "shmat logarea failed %d", errno);
 		shmctl(shmid, IPC_RMID, NULL);
 		return 1;
 	}
@@ -92,7 +89,6 @@
 
 	if ((shmid = shmget(IPC_PRIVATE, size,
 			    0644 | IPC_CREAT | IPC_EXCL)) == -1) {
-		syslog(LOG_ERR, "shmget msg failed %d", errno);
 		free_logarea();
 		return 1;
 	}
@@ -100,7 +96,6 @@
 
 	la->start = shmat(la->shmid_msg, NULL, 0);
 	if (!la->start) {
-		syslog(LOG_ERR, "shmat msg failed %d", errno);
 		free_logarea();
 		return 1;
 	}
@@ -113,26 +108,22 @@
 
 	if ((shmid = shmget(IPC_PRIVATE, MAX_MSG_SIZE + sizeof(struct logmsg),
 			    0644 | IPC_CREAT | IPC_EXCL)) == -1) {
-		syslog(LOG_ERR, "shmget logmsg failed %d", errno);
 		free_logarea();
 		return 1;
 	}
 	la->buff = shmat(shmid, NULL, 0);
 	if (!la->buff) {
-		syslog(LOG_ERR, "shmat logmsgfailed %d", errno);
 		free_logarea();
 		return 1;
 	}
 
 	if ((la->semid = semget(SEMKEY, 1, 0600 | IPC_CREAT)) < 0) {
-		syslog(LOG_ERR, "semget failed %d", errno);
 		free_logarea();
 		return 1;
 	}
 
 	la->semarg.val=1;
 	if (semctl(la->semid, 0, SETVAL, la->semarg) < 0) {
-		syslog(LOG_ERR, "semctl failed %d", errno);
 		free_logarea();
 		return 1;
 	}
@@ -399,10 +390,8 @@
 		openlog(log_name, 0, LOG_DAEMON);
 		setlogmask (LOG_UPTO (LOG_DEBUG));
 
-		if (logarea_init(size)) {
-			syslog(LOG_ERR, "logarea init failed");
+		if (logarea_init(size))
 			return -1;
-		}
 
 		pid = fork();
 		if (pid < 0) {
--- open-iscsi-2.0.870~rc3.orig/usr/login.c
+++ open-iscsi-2.0.870~rc3/usr/login.c
@@ -188,6 +188,7 @@
 	char *port, *tag;
 	char default_port[NI_MAXSERV];
 	iscsi_session_t *session = conn->session;
+
 	struct sockaddr_storage addr;
 
 	if ((tag = strrchr(address, ','))) {
@@ -204,18 +205,6 @@
 		port = default_port;
 	}
 
-	if (*address == '[') {
-		char *end_bracket;
-
-		if (!(end_bracket = strchr(address, ']'))) {
-			log_error("Invalid IPv6 address with opening bracket, "
-				  "but no closing bracket.");
-			return 0;
-		}
-		*end_bracket = '\0';
-		address++;
-        }
-
 	if (resolve_address(address, port, &addr)) {
 		log_error("cannot resolve host name %s", address);
 		return 0;
--- open-iscsi-2.0.870~rc3.orig/usr/mgmt_ipc.c
+++ open-iscsi-2.0.870~rc3/usr/mgmt_ipc.c
@@ -84,7 +84,15 @@
 static mgmt_ipc_err_e
 mgmt_ipc_session_login(queue_task_t *qtask)
 {
-	return session_login_task(&qtask->req.u.session.rec, qtask);
+	node_rec_t *rec = &qtask->req.u.session.rec;
+
+	if (session_is_running(rec)) {
+		log_error("session [%s,%s,%d] already running.", rec->name,
+			  rec->conn[0].address, rec->conn[0].port);
+		return MGMT_IPC_ERR_EXISTS;
+	}
+
+	return session_login_task(rec, qtask);
 }
 
 static mgmt_ipc_err_e
@@ -127,7 +135,16 @@
 static mgmt_ipc_err_e
 mgmt_ipc_session_logout(queue_task_t *qtask)
 {
-	return session_logout_task(qtask->req.u.session.sid, qtask);
+	node_rec_t *rec = &qtask->req.u.session.rec;
+	iscsi_session_t *session;
+
+	if (!(session = session_find_by_rec(rec))) {
+		log_debug(1, "session [%s,%s,%d] not found!", rec->name,
+			  rec->conn[0].address, rec->conn[0].port);
+		return MGMT_IPC_ERR_NOT_FOUND;
+	}
+
+	return session_logout_task(session, qtask);
 }
 
 static mgmt_ipc_err_e
--- open-iscsi-2.0.870~rc3.orig/usr/netlink.c
+++ open-iscsi-2.0.870~rc3/usr/netlink.c
@@ -25,7 +25,6 @@
 #include <unistd.h>
 #include <stdint.h>
 #include <errno.h>
-#include <inttypes.h>
 #include <asm/types.h>
 #include <sys/socket.h>
 #include <sys/types.h>
@@ -280,18 +279,7 @@
 							 sizeof(*ev), 0)) < 0) {
 					return rc;
 				}
-				if (ev->iferror == -ENOSYS)
-					/* not fatal so let caller handle log */
-					log_debug(1, "Recieved iferror %d: %s",
-						  ev->iferror,
-						  strerror(ev->iferror));
-				else if (ev->iferror < 0)
-					log_error("Received iferror %d: %s",
-						   ev->iferror,
-						   strerror(ev->iferror));
-				else
-					log_error("Received iferror %d",
-						   ev->iferror);
+				log_error("received iferror %d", ev->iferror);
 				return ev->iferror;
 			}
 			/*
@@ -351,9 +339,9 @@
 }
 
 static int
-kcreate_session(uint64_t transport_handle, uint64_t ep_handle,
-		uint32_t initial_cmdsn, uint16_t cmds_max, uint16_t qdepth,
-		uint32_t *out_sid, uint32_t *hostno)
+kcreate_session(uint64_t transport_handle, uint32_t initial_cmdsn,
+		uint16_t cmds_max, uint16_t qdepth,
+		uint32_t *out_sid, uint32_t *out_hostno)
 {
 	int rc;
 	struct iscsi_uevent ev;
@@ -362,26 +350,17 @@
 
 	memset(&ev, 0, sizeof(struct iscsi_uevent));
 
-	if (ep_handle == 0) {
-		ev.type = ISCSI_UEVENT_CREATE_SESSION;
-		ev.transport_handle = transport_handle;
-		ev.u.c_session.initial_cmdsn = initial_cmdsn;
-		ev.u.c_session.cmds_max = cmds_max;
-		ev.u.c_session.queue_depth = qdepth;
-	} else {
-		ev.type = ISCSI_UEVENT_CREATE_BOUND_SESSION;
-		ev.transport_handle = transport_handle;
-		ev.u.c_bound_session.initial_cmdsn = initial_cmdsn;
-		ev.u.c_bound_session.cmds_max = cmds_max;
-		ev.u.c_bound_session.queue_depth = qdepth;
-		ev.u.c_bound_session.ep_handle = ep_handle;
-	}
+	ev.type = ISCSI_UEVENT_CREATE_SESSION;
+	ev.transport_handle = transport_handle;
+	ev.u.c_session.initial_cmdsn = initial_cmdsn;
+	ev.u.c_session.cmds_max = cmds_max;
+	ev.u.c_session.queue_depth = qdepth;
 
 	if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) {
 		return rc;
 	}
 
-	*hostno = ev.r.c_session_ret.host_no;
+	*out_hostno = ev.r.c_session_ret.host_no;
 	*out_sid = ev.r.c_session_ret.sid;
 
 	return 0;
@@ -814,7 +793,7 @@
 
 	log_debug(7, "in %s", __FUNCTION__);
 
-	if (conn->transport_ep_handle == -1)
+	if (conn->transport_ep_handle < 0)
 		return;
 
 	memset(&ev, 0, sizeof(struct iscsi_uevent));
@@ -824,9 +803,8 @@
 	ev.u.ep_disconnect.ep_handle = conn->transport_ep_handle;
 
 	if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) {
-		log_error("connnection %d:%d transport disconnect failed for "
-			  "ep %" PRIu64 " with error %d.", conn->session->id,
-			  conn->id, conn->transport_ep_handle, rc);
+		log_error("conn %p session %p transport disconnect failed %d\n",
+			  conn, conn->session, rc);
 	} else
 		conn->transport_ep_handle = -1;
 }
--- open-iscsi-2.0.870~rc3.orig/usr/transport.c
+++ open-iscsi-2.0.870~rc3/usr/transport.c
@@ -28,6 +28,7 @@
 
 struct iscsi_transport_template iscsi_tcp = {
 	.name		= "tcp",
+	.rdma		= 0,
 	.ep_connect	= iscsi_io_tcp_connect,
 	.ep_poll	= iscsi_io_tcp_poll,
 	.ep_disconnect	= iscsi_io_tcp_disconnect,
@@ -41,21 +42,14 @@
 	.ep_disconnect	= ktransport_ep_disconnect,
 };
 
-struct iscsi_transport_template bnx2i = {
-	.name		= "bnx2i",
-	.ep_connect	= ktransport_ep_connect,
-	.ep_poll	= ktransport_ep_poll,
-	.ep_disconnect	= ktransport_ep_disconnect,
-};
-
 struct iscsi_transport_template qla4xxx = {
 	.name		= "qla4xxx",
+	.rdma		= 0,
 };
 
 static struct iscsi_transport_template *iscsi_transport_templates[] = {
 	&iscsi_tcp,
 	&iscsi_iser,
-	&bnx2i,
 	&qla4xxx,
 	NULL
 };
--- open-iscsi-2.0.870~rc3.orig/usr/transport.h
+++ open-iscsi-2.0.870~rc3/usr/transport.h
@@ -26,9 +26,9 @@
 struct iscsi_transport_template {
 	const char *name;
 	uint8_t rdma;
-	int (*ep_connect) (struct iscsi_conn *conn, int non_blocking);
-	int (*ep_poll) (struct iscsi_conn *conn, int timeout_ms);
-	void (*ep_disconnect) (struct iscsi_conn *conn);
+	int (*ep_connect) (iscsi_conn_t *conn, int non_blocking);
+	int (*ep_poll) (iscsi_conn_t *conn, int timeout_ms);
+	void (*ep_disconnect) (iscsi_conn_t *conn);
 };
 
 /* represents data path provider */
--- open-iscsi-2.0.870~rc3.orig/usr/util.c
+++ open-iscsi-2.0.870~rc3/usr/util.c
@@ -20,7 +20,6 @@
 #include "iscsi_proto.h"
 #include "transport.h"
 #include "idbm.h"
-#include "iface.h"
 
 void daemon_init(void)
 {
@@ -204,56 +203,6 @@
 	return iscsid_response(fd, req->command, rsp);
 }
 
-int iscsid_req_wait(iscsiadm_cmd_e cmd, int fd)
-{
-	iscsiadm_rsp_t rsp;
-
-	memset(&rsp, 0, sizeof(iscsiadm_rsp_t));
-	return iscsid_response(fd, cmd, &rsp);
-}
-
-int iscsid_req_by_rec_async(iscsiadm_cmd_e cmd, node_rec_t *rec, int *fd)
-{
-	iscsiadm_req_t req;
-
-	memset(&req, 0, sizeof(iscsiadm_req_t));
-	req.command = cmd;
-	memcpy(&req.u.session.rec, rec, sizeof(node_rec_t));
-
-	return iscsid_request(fd, &req);
-}
-
-int iscsid_req_by_rec(iscsiadm_cmd_e cmd, node_rec_t *rec)
-{
-	int err, fd;
-
-	err = iscsid_req_by_rec_async(cmd, rec, &fd);
-	if (err)
-		return err;
-	return iscsid_req_wait(cmd, fd);
-}
-
-int iscsid_req_by_sid_async(iscsiadm_cmd_e cmd, int sid, int *fd)
-{
-	iscsiadm_req_t req;
-
-	memset(&req, 0, sizeof(iscsiadm_req_t));
-	req.command = cmd;
-	req.u.session.sid = sid;
-
-	return iscsid_request(fd, &req);
-}
-
-int iscsid_req_by_sid(iscsiadm_cmd_e cmd, int sid)
-{
-	int err, fd;
-
-	err = iscsid_req_by_sid_async(cmd, sid, &fd);
-	if (err)
-		return err;
-	return iscsid_req_wait(cmd, fd);
-}
-
 void idbm_node_setup_defaults(node_rec_t *rec)
 {
 	int i;
@@ -286,7 +235,7 @@
 	rec->session.iscsi.FastAbort = 1;
 
 	for (i=0; i<ISCSI_CONN_MAX; i++) {
-		rec->conn[i].startup = ISCSI_STARTUP_MANUAL;
+		rec->conn[i].startup = 0;
 		rec->conn[i].port = ISCSI_LISTEN_PORT;
 		rec->conn[i].tcp.window_size = TCP_WINDOW_SIZE;
 		rec->conn[i].tcp.type_of_service = 0;
@@ -299,13 +248,13 @@
 
 		rec->conn[i].iscsi.MaxRecvDataSegmentLength =
 						DEF_INI_MAX_RECV_SEG_LEN;
-		rec->conn[i].iscsi.HeaderDigest = CONFIG_DIGEST_NEVER;
+		rec->conn[i].iscsi.HeaderDigest = CONFIG_DIGEST_PREFER_OFF;
 		rec->conn[i].iscsi.DataDigest = CONFIG_DIGEST_NEVER;
 		rec->conn[i].iscsi.IFMarker = 0;
 		rec->conn[i].iscsi.OFMarker = 0;
 	}
 
-	iface_setup_defaults(&rec->iface);
+	iface_init(&rec->iface);
 }
 
 void iscsid_handle_error(mgmt_ipc_err_e err)
@@ -364,7 +313,11 @@
 	if (rec->conn[0].port != -1 && port != rec->conn[0].port)
 		return 0;
 
-	if (!iface_match(&rec->iface, iface))
+	if (iface && strlen(rec->iface.transport_name) &&
+	    strcmp(rec->iface.transport_name, iface->transport_name))
+		return 0;
+
+	if (!iface_match_bind_info(&rec->iface, iface))
 		return 0;
 
 	return 1;
--- open-iscsi-2.0.870~rc3.orig/usr/util.h
+++ open-iscsi-2.0.870~rc3/usr/util.h
@@ -17,11 +17,6 @@
 extern void iscsid_handle_error(int err);
 extern int iscsid_request(int *fd, struct iscsiadm_req *req);
 extern int iscsid_response(int fd, int cmd, struct iscsiadm_rsp *rsp);
-extern int iscsid_req_wait(int cmd, int fd);
-extern int iscsid_req_by_rec_async(int cmd, struct node_rec *rec, int *fd);
-extern int iscsid_req_by_rec(int cmd, struct node_rec *rec);
-extern int iscsid_req_by_sid_async(int cmd, int sid, int *fd);
-extern int iscsid_req_by_sid(int cmd, int sid);
 
 extern char *str_to_ipport(char *str, int *port, int *tgpt);
 extern void idbm_node_setup_defaults(struct node_rec *rec);
