Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 14 Sep 2013 15:29:06 +0000 (UTC)
From:      Edward Tomasz Napierala <trasz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r255570 - in head: etc/defaults etc/rc.d sbin/iscontrol share/man/man4 sys/cam/ctl sys/conf sys/dev/iscsi sys/dev/iscsi_initiator sys/modules sys/modules/ctl sys/modules/iscsi tools/reg...
Message-ID:  <201309141529.r8EFT647098130@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: trasz
Date: Sat Sep 14 15:29:06 2013
New Revision: 255570
URL: http://svnweb.freebsd.org/changeset/base/255570

Log:
  Bring in the new iSCSI target and initiator.
  
  Reviewed by:	ken (parts)
  Approved by:	re (delphij)
  Sponsored by:	FreeBSD Foundation

Added:
  head/etc/rc.d/ctld   (contents, props changed)
  head/etc/rc.d/iscsictl   (contents, props changed)
  head/etc/rc.d/iscsid   (contents, props changed)
  head/sys/cam/ctl/ctl_frontend_iscsi.c   (contents, props changed)
  head/sys/cam/ctl/ctl_frontend_iscsi.h   (contents, props changed)
  head/sys/dev/iscsi/icl.c   (contents, props changed)
  head/sys/dev/iscsi/icl.h   (contents, props changed)
  head/sys/dev/iscsi/icl_proxy.c   (contents, props changed)
  head/sys/dev/iscsi/iscsi.c   (contents, props changed)
  head/sys/dev/iscsi/iscsi.h   (contents, props changed)
  head/sys/dev/iscsi/iscsi_ioctl.h   (contents, props changed)
  head/sys/dev/iscsi/iscsi_proto.h   (contents, props changed)
  head/tools/regression/iscsi/
  head/tools/regression/iscsi/ctl.conf   (contents, props changed)
  head/tools/regression/iscsi/initiator-instructions.txt   (contents, props changed)
  head/tools/regression/iscsi/iscsi-test.sh   (contents, props changed)
  head/usr.bin/iscsictl/
  head/usr.bin/iscsictl/Makefile   (contents, props changed)
  head/usr.bin/iscsictl/iscsictl.8   (contents, props changed)
  head/usr.bin/iscsictl/iscsictl.c   (contents, props changed)
  head/usr.bin/iscsictl/iscsictl.h   (contents, props changed)
  head/usr.bin/iscsictl/parse.y   (contents, props changed)
  head/usr.bin/iscsictl/periphs.c   (contents, props changed)
  head/usr.bin/iscsictl/token.l   (contents, props changed)
  head/usr.sbin/ctld/
  head/usr.sbin/ctld/Makefile   (contents, props changed)
  head/usr.sbin/ctld/ctl.conf.5   (contents, props changed)
  head/usr.sbin/ctld/ctld.8   (contents, props changed)
  head/usr.sbin/ctld/ctld.c   (contents, props changed)
  head/usr.sbin/ctld/ctld.h   (contents, props changed)
  head/usr.sbin/ctld/discovery.c   (contents, props changed)
  head/usr.sbin/ctld/kernel.c   (contents, props changed)
  head/usr.sbin/ctld/keys.c   (contents, props changed)
  head/usr.sbin/ctld/log.c   (contents, props changed)
  head/usr.sbin/ctld/login.c   (contents, props changed)
  head/usr.sbin/ctld/parse.y   (contents, props changed)
  head/usr.sbin/ctld/pdu.c   (contents, props changed)
  head/usr.sbin/ctld/token.l   (contents, props changed)
  head/usr.sbin/iscsid/
  head/usr.sbin/iscsid/Makefile   (contents, props changed)
  head/usr.sbin/iscsid/discovery.c   (contents, props changed)
  head/usr.sbin/iscsid/iscsid.8   (contents, props changed)
  head/usr.sbin/iscsid/iscsid.c   (contents, props changed)
  head/usr.sbin/iscsid/iscsid.h   (contents, props changed)
  head/usr.sbin/iscsid/keys.c   (contents, props changed)
  head/usr.sbin/iscsid/log.c   (contents, props changed)
  head/usr.sbin/iscsid/login.c   (contents, props changed)
  head/usr.sbin/iscsid/pdu.c   (contents, props changed)
Modified:
  head/etc/defaults/rc.conf
  head/etc/rc.d/Makefile
  head/sbin/iscontrol/iscontrol.8
  head/sbin/iscontrol/iscsi.conf.5
  head/share/man/man4/ctl.4
  head/sys/cam/ctl/ctl.c
  head/sys/cam/ctl/ctl_ioctl.h
  head/sys/conf/files
  head/sys/dev/iscsi_initiator/iscsi.c
  head/sys/modules/Makefile
  head/sys/modules/ctl/Makefile
  head/sys/modules/iscsi/Makefile
  head/usr.bin/Makefile
  head/usr.sbin/Makefile
  head/usr.sbin/ctladm/ctladm.8
  head/usr.sbin/ctladm/ctladm.c

Modified: head/etc/defaults/rc.conf
==============================================================================
--- head/etc/defaults/rc.conf	Sat Sep 14 13:12:13 2013	(r255569)
+++ head/etc/defaults/rc.conf	Sat Sep 14 15:29:06 2013	(r255570)
@@ -263,9 +263,13 @@ syslogd_flags="-s"		# Flags to syslogd (
 inetd_enable="NO"		# Run the network daemon dispatcher (YES/NO).
 inetd_program="/usr/sbin/inetd"	# path to inetd, if you want a different one.
 inetd_flags="-wW -C 60"		# Optional flags to inetd
+iscsid_enable="NO"		# iSCSI initiator daemon.
+iscsictl_enable="NO"		# iSCSI initiator autostart.
+iscsictl_flags="-Aa"		# Optional flags to iscsictl.
 hastd_enable="NO"		# Run the HAST daemon (YES/NO).
 hastd_program="/sbin/hastd"	# path to hastd, if you want a different one.
 hastd_flags=""			# Optional flags to hastd.
+ctld_enable="NO"		# CAM Target Layer / iSCSI target daemon.
 #
 # named.  It may be possible to run named in a sandbox, man security for
 # details.

Modified: head/etc/rc.d/Makefile
==============================================================================
--- head/etc/rc.d/Makefile	Sat Sep 14 13:12:13 2013	(r255569)
+++ head/etc/rc.d/Makefile	Sat Sep 14 15:29:06 2013	(r255570)
@@ -30,6 +30,7 @@ FILES=	DAEMON \
 	cleanvar \
 	cleartmp \
 	cron \
+	ctld \
 	ddb \
 	defaultroute \
 	devd \
@@ -62,6 +63,8 @@ FILES=	DAEMON \
 	ipnat \
 	ipsec \
 	${_ipxrouted} \
+	iscsictl \
+	iscsid \
 	jail \
 	kadmind \
 	kerberos \

Added: head/etc/rc.d/ctld
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/etc/rc.d/ctld	Sat Sep 14 15:29:06 2013	(r255570)
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: ctld
+# REQUIRE: FILESYSTEMS
+# BEFORE:  DAEMON
+# KEYWORD: nojail
+
+. /etc/rc.subr
+
+name="ctld"
+rcvar="ctld_enable"
+pidfile="/var/run/${name}.pid"
+command="/usr/sbin/${name}"
+required_files="/etc/ctl.conf"
+required_modules="ctl"
+extra_commands="reload"
+
+load_rc_config $name
+run_rc_command "$1"

Added: head/etc/rc.d/iscsictl
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/etc/rc.d/iscsictl	Sat Sep 14 15:29:06 2013	(r255570)
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: iscsictl
+# REQUIRE: NETWORK iscsid
+# BEFORE:  DAEMON
+# KEYWORD: nojail
+
+. /etc/rc.subr
+
+name="iscsictl"
+rcvar="iscsictl_enable"
+command="/usr/bin/${name}"
+command_args="${iscsictl_flags}"
+required_modules="iscsi"
+
+load_rc_config $name
+run_rc_command "$1"

Added: head/etc/rc.d/iscsid
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/etc/rc.d/iscsid	Sat Sep 14 15:29:06 2013	(r255570)
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: iscsid
+# REQUIRE: NETWORK
+# BEFORE:  DAEMON
+# KEYWORD: nojail
+
+. /etc/rc.subr
+
+name="iscsid"
+rcvar="iscsid_enable"
+pidfile="/var/run/${name}.pid"
+command="/usr/sbin/${name}"
+required_modules="iscsi"
+
+load_rc_config $name
+run_rc_command "$1"

Modified: head/sbin/iscontrol/iscontrol.8
==============================================================================
--- head/sbin/iscontrol/iscontrol.8	Sat Sep 14 13:12:13 2013	(r255569)
+++ head/sbin/iscontrol/iscontrol.8	Sat Sep 14 15:29:06 2013	(r255570)
@@ -112,6 +112,7 @@ whatever options are specified, and star
 .Xr iscsi_initiator 4 ,
 .Xr sa 4 ,
 .Xr iscsi.conf 5 ,
+.Xr iscsictl 8 ,
 .Xr camcontrol 8
 .Sh STANDARDS
 RFC 3720

Modified: head/sbin/iscontrol/iscsi.conf.5
==============================================================================
--- head/sbin/iscontrol/iscsi.conf.5	Sat Sep 14 13:12:13 2013	(r255569)
+++ head/sbin/iscontrol/iscsi.conf.5	Sat Sep 14 15:29:06 2013	(r255570)
@@ -201,6 +201,7 @@ The parsing is very primitive, so do not
 error messages.
 .Sh SEE ALSO
 .Xr iscsi_initiator 4 ,
+.Xr iscsictl 8 ,
 .Xr iscontrol 8
 .Sh STANDARDS
 ISCSI RFC 3720

Modified: head/share/man/man4/ctl.4
==============================================================================
--- head/share/man/man4/ctl.4	Sat Sep 14 13:12:13 2013	(r255569)
+++ head/share/man/man4/ctl.4	Sat Sep 14 15:29:06 2013	(r255570)
@@ -75,8 +75,11 @@ Error injection support
 .It
 All I/O handled in-kernel, no userland context switch overhead
 .El
+.Pp
+It also serves as a kernel component of the native iSCSI target.
 .Sh SEE ALSO
 .Xr ctladm 8 ,
+.Xr ctld 8 ,
 .Xr ctlstat 8
 .Sh HISTORY
 The

Modified: head/sys/cam/ctl/ctl.c
==============================================================================
--- head/sys/cam/ctl/ctl.c	Sat Sep 14 13:12:13 2013	(r255569)
+++ head/sys/cam/ctl/ctl.c	Sat Sep 14 15:29:06 2013	(r255570)
@@ -3148,6 +3148,28 @@ ctl_ioctl(struct cdev *dev, u_long cmd, 
 		sbuf_delete(sb);
 		break;
 	}
+	case CTL_ISCSI: {
+		struct ctl_iscsi *ci;
+		struct ctl_frontend *fe;
+
+		ci = (struct ctl_iscsi *)addr;
+
+		mtx_lock(&softc->ctl_lock);
+		STAILQ_FOREACH(fe, &softc->fe_list, links) {
+			if (strcmp(fe->port_name, "iscsi") == 0)
+				break;
+		}
+		mtx_unlock(&softc->ctl_lock);
+
+		if (fe == NULL) {
+			ci->status = CTL_ISCSI_ERROR;
+			snprintf(ci->error_str, sizeof(ci->error_str), "Backend \"iscsi\" not found.");
+			break;
+		}
+
+		retval = fe->ioctl(dev, cmd, addr, flag, td);
+		break;
+	}
 	default: {
 		/* XXX KDM should we fix this? */
 #if 0

Added: head/sys/cam/ctl/ctl_frontend_iscsi.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/cam/ctl/ctl_frontend_iscsi.c	Sat Sep 14 15:29:06 2013	(r255570)
@@ -0,0 +1,2638 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * CTL frontend for the iSCSI protocol.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/capability.h>
+#include <sys/condvar.h>
+#include <sys/file.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/sbuf.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/unistd.h>
+#include <vm/uma.h>
+
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_da.h>
+#include <cam/ctl/ctl_io.h>
+#include <cam/ctl/ctl.h>
+#include <cam/ctl/ctl_backend.h>
+#include <cam/ctl/ctl_frontend.h>
+#include <cam/ctl/ctl_frontend_internal.h>
+#include <cam/ctl/ctl_debug.h>
+#include <cam/ctl/ctl_ha.h>
+#include <cam/ctl/ctl_ioctl.h>
+#include <cam/ctl/ctl_private.h>
+
+#include "../../dev/iscsi/icl.h"
+#include "../../dev/iscsi/iscsi_proto.h"
+#include "ctl_frontend_iscsi.h"
+
+#ifdef ICL_KERNEL_PROXY
+#include <sys/socketvar.h>
+#endif
+
+static MALLOC_DEFINE(M_CFISCSI, "cfiscsi", "Memory used for CTL iSCSI frontend");
+static uma_zone_t cfiscsi_data_wait_zone;
+
+SYSCTL_NODE(_kern_cam_ctl, OID_AUTO, iscsi, CTLFLAG_RD, 0,
+    "CAM Target Layer iSCSI Frontend");
+static int debug = 3;
+TUNABLE_INT("kern.cam.ctl.iscsi.debug", &debug);
+SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, debug, CTLFLAG_RW,
+    &debug, 1, "Enable debug messages");
+static int ping_timeout = 5;
+TUNABLE_INT("kern.cam.ctl.iscsi.ping_timeout", &ping_timeout);
+SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, ping_timeout, CTLFLAG_RW,
+    &ping_timeout, 5, "Interval between ping (NOP-Out) requests, in seconds");
+static int login_timeout = 60;
+TUNABLE_INT("kern.cam.ctl.iscsi.login_timeout", &login_timeout);
+SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, login_timeout, CTLFLAG_RW,
+    &login_timeout, 60, "Time to wait for ctld(8) to finish Login Phase, in seconds");
+static int maxcmdsn_delta = 256;
+TUNABLE_INT("kern.cam.ctl.iscsi.maxcmdsn_delta", &maxcmdsn_delta);
+SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, maxcmdsn_delta, CTLFLAG_RW,
+    &maxcmdsn_delta, 256, "Number of commands the initiator can send "
+    "without confirmation");
+
+#define	CFISCSI_DEBUG(X, ...)					\
+	if (debug > 1) {					\
+		printf("%s: " X "\n", __func__, ## __VA_ARGS__);\
+	} while (0)
+
+#define	CFISCSI_WARN(X, ...)					\
+	if (debug > 0) {					\
+		printf("WARNING: %s: " X "\n",			\
+		    __func__, ## __VA_ARGS__);			\
+	} while (0)
+
+#define	CFISCSI_SESSION_DEBUG(S, X, ...)			\
+	if (debug > 1) {					\
+		printf("%s: %s (%s): " X "\n",			\
+		    __func__, S->cs_initiator_addr,		\
+		    S->cs_initiator_name, ## __VA_ARGS__);	\
+	} while (0)
+
+#define	CFISCSI_SESSION_WARN(S, X, ...)				\
+	if (debug > 0) {					\
+		printf("WARNING: %s (%s): " X "\n",		\
+		    S->cs_initiator_addr,			\
+		    S->cs_initiator_name, ## __VA_ARGS__);	\
+	} while (0)
+
+#define CFISCSI_SESSION_LOCK(X)		mtx_lock(&X->cs_lock)
+#define CFISCSI_SESSION_UNLOCK(X)	mtx_unlock(&X->cs_lock)
+#define CFISCSI_SESSION_LOCK_ASSERT(X)	mtx_assert(&X->cs_lock, MA_OWNED)
+
+#define	CONN_SESSION(X)			((struct cfiscsi_session *)(X)->ic_prv0)
+#define	PDU_SESSION(X)			CONN_SESSION((X)->ip_conn)
+#define	PDU_EXPDATASN(X)		(X)->ip_prv0
+#define	PDU_TOTAL_TRANSFER_LEN(X)	(X)->ip_prv1
+#define	PDU_R2TSN(X)			(X)->ip_prv2
+
+int		cfiscsi_init(void);
+static void	cfiscsi_online(void *arg);
+static void	cfiscsi_offline(void *arg);
+static int	cfiscsi_targ_enable(void *arg, struct ctl_id targ_id);
+static int	cfiscsi_targ_disable(void *arg, struct ctl_id targ_id);
+static int	cfiscsi_lun_enable(void *arg,
+		    struct ctl_id target_id, int lun_id);
+static int	cfiscsi_lun_disable(void *arg,
+		    struct ctl_id target_id, int lun_id);
+static int	cfiscsi_ioctl(struct cdev *dev,
+		    u_long cmd, caddr_t addr, int flag, struct thread *td);
+static int	cfiscsi_devid(struct ctl_scsiio *ctsio, int alloc_len);
+static void	cfiscsi_datamove(union ctl_io *io);
+static void	cfiscsi_done(union ctl_io *io);
+static uint32_t	cfiscsi_map_lun(void *arg, uint32_t lun);
+static void	cfiscsi_pdu_update_cmdsn(const struct icl_pdu *request);
+static void	cfiscsi_pdu_handle_nop_out(struct icl_pdu *request);
+static void	cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request);
+static void	cfiscsi_pdu_handle_task_request(struct icl_pdu *request);
+static void	cfiscsi_pdu_handle_data_out(struct icl_pdu *request);
+static void	cfiscsi_pdu_handle_logout_request(struct icl_pdu *request);
+static void	cfiscsi_session_terminate(struct cfiscsi_session *cs);
+static struct cfiscsi_target	*cfiscsi_target_find(struct cfiscsi_softc
+		    *softc, const char *name);
+static void	cfiscsi_target_release(struct cfiscsi_target *ct);
+static void	cfiscsi_session_delete(struct cfiscsi_session *cs);
+
+static struct cfiscsi_softc cfiscsi_softc;
+extern struct ctl_softc *control_softc;
+
+static int cfiscsi_module_event_handler(module_t, int /*modeventtype_t*/, void *);
+
+static moduledata_t cfiscsi_moduledata = {
+	"ctlcfiscsi",
+	cfiscsi_module_event_handler,
+	NULL
+};
+
+DECLARE_MODULE(ctlcfiscsi, cfiscsi_moduledata, SI_SUB_CONFIGURE, SI_ORDER_FOURTH);
+MODULE_VERSION(ctlcfiscsi, 1);
+MODULE_DEPEND(ctlcfiscsi, ctl, 1, 1, 1);
+MODULE_DEPEND(ctlcfiscsi, icl, 1, 1, 1);
+
+static struct icl_pdu *
+cfiscsi_pdu_new_response(struct icl_pdu *request, int flags)
+{
+
+	return (icl_pdu_new_bhs(request->ip_conn, flags));
+}
+
+static void
+cfiscsi_pdu_update_cmdsn(const struct icl_pdu *request)
+{
+	const struct iscsi_bhs_scsi_command *bhssc;
+	struct cfiscsi_session *cs;
+	uint32_t cmdsn, expstatsn;
+
+	cs = PDU_SESSION(request);
+
+	/*
+	 * Every incoming PDU - not just NOP-Out - resets the ping timer.
+	 * The purpose of the timeout is to reset the connection when it stalls;
+	 * we don't want this to happen when NOP-In or NOP-Out ends up delayed
+	 * in some queue.
+	 *
+	 * XXX: Locking?
+	 */
+	cs->cs_timeout = 0;
+
+	/*
+	 * Data-Out PDUs don't contain CmdSN.
+	 */
+	if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
+	    ISCSI_BHS_OPCODE_SCSI_DATA_OUT)
+		return;
+
+	/*
+	 * We're only using fields common for all the request
+	 * (initiator -> target) PDUs.
+	 */
+	bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
+	cmdsn = ntohl(bhssc->bhssc_cmdsn);
+	expstatsn = ntohl(bhssc->bhssc_expstatsn);
+
+	CFISCSI_SESSION_LOCK(cs);
+#if 0
+	if (expstatsn != cs->cs_statsn) {
+		CFISCSI_SESSION_DEBUG(cs, "received PDU with ExpStatSN %d, "
+		    "while current StatSN is %d", expstatsn,
+		    cs->cs_statsn);
+	}
+#endif
+
+	/*
+	 * XXX: The target MUST silently ignore any non-immediate command
+	 *	outside of this range or non-immediate duplicates within
+	 *	the range.
+	 */
+	if (cmdsn != cs->cs_cmdsn) {
+		CFISCSI_SESSION_WARN(cs, "received PDU with CmdSN %d, "
+		    "while expected CmdSN was %d", cmdsn, cs->cs_cmdsn);
+		cs->cs_cmdsn = cmdsn + 1;
+		CFISCSI_SESSION_UNLOCK(cs);
+		return;
+	}
+
+	/*
+	 * XXX: The CmdSN of the rejected command PDU (if it is a non-immediate
+	 *	command) MUST NOT be considered received by the target
+	 *	(i.e., a command sequence gap must be assumed for the CmdSN)
+	 */
+
+	if ((request->ip_bhs->bhs_opcode & ISCSI_BHS_OPCODE_IMMEDIATE) == 0)
+		cs->cs_cmdsn++;
+
+	CFISCSI_SESSION_UNLOCK(cs);
+}
+
+static void
+cfiscsi_pdu_handle(struct icl_pdu *request)
+{
+	struct cfiscsi_session *cs;
+
+	cs = PDU_SESSION(request);
+
+	cfiscsi_pdu_update_cmdsn(request);
+
+	/*
+	 * Handle the PDU; this includes e.g. receiving the remaining
+	 * part of PDU and submitting the SCSI command to CTL
+	 * or queueing a reply.  The handling routine is responsible
+	 * for freeing the PDU when it's no longer needed.
+	 */
+	switch (request->ip_bhs->bhs_opcode &
+	    ~ISCSI_BHS_OPCODE_IMMEDIATE) {
+	case ISCSI_BHS_OPCODE_NOP_OUT:
+		cfiscsi_pdu_handle_nop_out(request);
+		break;
+	case ISCSI_BHS_OPCODE_SCSI_COMMAND:
+		cfiscsi_pdu_handle_scsi_command(request);
+		break;
+	case ISCSI_BHS_OPCODE_TASK_REQUEST:
+		cfiscsi_pdu_handle_task_request(request);
+		break;
+	case ISCSI_BHS_OPCODE_SCSI_DATA_OUT:
+		cfiscsi_pdu_handle_data_out(request);
+		break;
+	case ISCSI_BHS_OPCODE_LOGOUT_REQUEST:
+		cfiscsi_pdu_handle_logout_request(request);
+		break;
+	default:
+		CFISCSI_SESSION_WARN(cs, "received PDU with unsupported "
+		    "opcode 0x%x; dropping connection",
+		    request->ip_bhs->bhs_opcode);
+		cfiscsi_session_terminate(cs);
+		icl_pdu_free(request);
+	}
+
+}
+
+static void
+cfiscsi_receive_callback(struct icl_pdu *request)
+{
+	struct cfiscsi_session *cs;
+
+	cs = PDU_SESSION(request);
+
+#ifdef ICL_KERNEL_PROXY
+	if (cs->cs_waiting_for_ctld || cs->cs_login_phase) {
+		if (cs->cs_login_pdu == NULL)
+			cs->cs_login_pdu = request;
+		else
+			icl_pdu_free(request);
+		cv_signal(&cs->cs_login_cv);
+		return;
+	}
+#endif
+
+	cfiscsi_pdu_handle(request);
+}
+
+static void
+cfiscsi_error_callback(struct icl_conn *ic)
+{
+	struct cfiscsi_session *cs;
+
+	cs = CONN_SESSION(ic);
+
+	CFISCSI_SESSION_WARN(cs, "connection error; dropping connection");
+	cfiscsi_session_terminate(cs);
+}
+
+static int
+cfiscsi_pdu_prepare(struct icl_pdu *response)
+{
+	struct cfiscsi_session *cs;
+	struct iscsi_bhs_scsi_response *bhssr;
+	bool advance_statsn = true;
+
+	cs = PDU_SESSION(response);
+
+	CFISCSI_SESSION_LOCK_ASSERT(cs);
+
+	/*
+	 * We're only using fields common for all the response
+	 * (target -> initiator) PDUs.
+	 */
+	bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs;
+
+	/*
+	 * 10.8.3: "The StatSN for this connection is not advanced
+	 * after this PDU is sent."
+	 */
+	if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_R2T)
+		advance_statsn = false;
+
+	/*
+	 * 10.19.2: "However, when the Initiator Task Tag is set to 0xffffffff,
+	 * StatSN for the connection is not advanced after this PDU is sent."
+	 */
+	if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_NOP_IN && 
+	    bhssr->bhssr_initiator_task_tag == 0xffffffff)
+		advance_statsn = false;
+
+	/*
+	 * See the comment below - StatSN is not meaningful and must
+	 * not be advanced.
+	 */
+	if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_SCSI_DATA_IN)
+		advance_statsn = false;
+
+	/*
+	 * 10.7.3: "The fields StatSN, Status, and Residual Count
+	 * only have meaningful content if the S bit is set to 1."
+	 */
+	if (bhssr->bhssr_opcode != ISCSI_BHS_OPCODE_SCSI_DATA_IN)
+		bhssr->bhssr_statsn = htonl(cs->cs_statsn);
+	bhssr->bhssr_expcmdsn = htonl(cs->cs_cmdsn);
+	bhssr->bhssr_maxcmdsn = htonl(cs->cs_cmdsn + maxcmdsn_delta);
+
+	if (advance_statsn)
+		cs->cs_statsn++;
+
+	return (0);
+}
+
+static void
+cfiscsi_pdu_queue(struct icl_pdu *response)
+{
+	struct cfiscsi_session *cs;
+
+	cs = PDU_SESSION(response);
+
+	CFISCSI_SESSION_LOCK(cs);
+	cfiscsi_pdu_prepare(response);
+	icl_pdu_queue(response);
+	CFISCSI_SESSION_UNLOCK(cs);
+}
+
+static uint32_t
+cfiscsi_decode_lun(uint64_t encoded)
+{
+	uint8_t lun[8];
+	uint32_t result;
+
+	/*
+	 * The LUN field in iSCSI PDUs may look like an ordinary 64 bit number,
+	 * but is in fact an evil, multidimensional structure defined
+	 * in SCSI Architecture Model 5 (SAM-5), section 4.6.
+	 */
+	memcpy(lun, &encoded, sizeof(lun));
+	switch (lun[0] & 0xC0) {
+	case 0x00:
+		if ((lun[0] & 0x3f) != 0 || lun[2] != 0 || lun[3] != 0 ||
+		    lun[4] != 0 || lun[5] != 0 || lun[6] != 0 || lun[7] != 0) {
+			CFISCSI_WARN("malformed LUN "
+			    "(peripheral device addressing method): 0x%jx",
+			    (uintmax_t)encoded);
+			result = 0xffffffff;
+			break;
+		}
+		result = lun[1];
+		break;
+	case 0x40:
+		if (lun[2] != 0 || lun[3] != 0 || lun[4] != 0 || lun[5] != 0 ||
+		    lun[6] != 0 || lun[7] != 0) {
+			CFISCSI_WARN("malformed LUN "
+			    "(flat address space addressing method): 0x%jx",
+			    (uintmax_t)encoded);
+			result = 0xffffffff;
+			break;
+		}
+		result = ((lun[0] & 0x3f) << 8) + lun[1];
+		break;
+	case 0xC0:
+		if (lun[0] != 0xD2 || lun[4] != 0 || lun[5] != 0 ||
+		    lun[6] != 0 || lun[7] != 0) {
+			CFISCSI_WARN("malformed LUN (extended flat "
+			    "address space addressing method): 0x%jx",
+			    (uintmax_t)encoded);
+			result = 0xffffffff;
+			break;
+		}
+		result = (lun[1] << 16) + (lun[2] << 8) + lun[3];
+	default:
+		CFISCSI_WARN("unsupported LUN format 0x%jx",
+		    (uintmax_t)encoded);
+		result = 0xffffffff;
+		break;
+	}
+
+	return (result);
+}
+
+static void
+cfiscsi_pdu_handle_nop_out(struct icl_pdu *request)
+{
+	struct cfiscsi_session *cs;
+	struct iscsi_bhs_nop_out *bhsno;
+	struct iscsi_bhs_nop_in *bhsni;
+	struct icl_pdu *response;
+
+	cs = PDU_SESSION(request);
+	bhsno = (struct iscsi_bhs_nop_out *)request->ip_bhs;
+
+	if (bhsno->bhsno_initiator_task_tag == 0xffffffff) {
+		/*
+		 * Nothing to do, iscsi_pdu_update_statsn() already
+		 * zeroed the timeout.
+		 */
+		icl_pdu_free(request);
+		return;
+	}
+
+	response = cfiscsi_pdu_new_response(request, M_NOWAIT);
+	if (response == NULL) {
+		icl_pdu_free(request);
+		return;
+	}
+	bhsni = (struct iscsi_bhs_nop_in *)response->ip_bhs;
+	bhsni->bhsni_opcode = ISCSI_BHS_OPCODE_NOP_IN;
+	bhsni->bhsni_flags = 0x80;
+	bhsni->bhsni_initiator_task_tag = bhsno->bhsno_initiator_task_tag;
+	bhsni->bhsni_target_transfer_tag = 0xffffffff;
+
+#if 0
+	/* XXX */
+	response->ip_data_len = request->ip_data_len;
+	response->ip_data_mbuf = request->ip_data_mbuf;
+	request->ip_data_len = 0;
+	request->ip_data_mbuf = NULL;
+#endif
+
+	icl_pdu_free(request);
+	cfiscsi_pdu_queue(response);
+}
+
+static void
+cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request)
+{
+	struct iscsi_bhs_scsi_command *bhssc;
+	struct cfiscsi_session *cs;
+	union ctl_io *io;
+	int error;
+
+	cs = PDU_SESSION(request);
+	bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs;
+	//CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x",
+	//    bhssc->bhssc_initiator_task_tag);
+
+	if (request->ip_data_len > 0 && cs->cs_immediate_data == false) {
+		CFISCSI_SESSION_WARN(cs, "unsolicited data with "
+		    "ImmediateData=No; dropping connection");
+		cfiscsi_session_terminate(cs);
+		icl_pdu_free(request);
+		return;
+	}
+	io = ctl_alloc_io(cs->cs_target->ct_softc->fe.ctl_pool_ref);
+	if (io == NULL) {
+		CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io");
+		icl_pdu_free(request);
+		return;
+	}
+	ctl_zero_io(io);
+	io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request;
+	io->io_hdr.io_type = CTL_IO_SCSI;
+	io->io_hdr.nexus.initid.id = cs->cs_ctl_initid;
+	io->io_hdr.nexus.targ_port = cs->cs_target->ct_softc->fe.targ_port;
+	io->io_hdr.nexus.targ_target.id = 0;
+	io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhssc->bhssc_lun);
+	io->io_hdr.nexus.lun_map_fn = cfiscsi_map_lun;
+	io->io_hdr.nexus.lun_map_arg = cs;
+	io->scsiio.tag_num = bhssc->bhssc_initiator_task_tag;
+	switch ((bhssc->bhssc_flags & BHSSC_FLAGS_ATTR)) {
+	case BHSSC_FLAGS_ATTR_UNTAGGED:
+		io->scsiio.tag_type = CTL_TAG_UNTAGGED;
+		break;
+	case BHSSC_FLAGS_ATTR_SIMPLE:
+		io->scsiio.tag_type = CTL_TAG_SIMPLE;
+		break;
+	case BHSSC_FLAGS_ATTR_ORDERED:
+        	io->scsiio.tag_type = CTL_TAG_ORDERED;
+		break;
+	case BHSSC_FLAGS_ATTR_HOQ:
+        	io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
+		break;
+	case BHSSC_FLAGS_ATTR_ACA:
+		io->scsiio.tag_type = CTL_TAG_ACA;
+		break;
+	default:
+		io->scsiio.tag_type = CTL_TAG_UNTAGGED;
+		CFISCSI_SESSION_WARN(cs, "unhandled tag type %d",
+		    bhssc->bhssc_flags & BHSSC_FLAGS_ATTR);
+		break;
+	}
+	io->scsiio.cdb_len = sizeof(bhssc->bhssc_cdb); /* Which is 16. */
+	memcpy(io->scsiio.cdb, bhssc->bhssc_cdb, sizeof(bhssc->bhssc_cdb));
+	refcount_acquire(&cs->cs_outstanding_ctl_pdus);
+	error = ctl_queue(io);
+	if (error != CTL_RETVAL_COMPLETE) {
+		CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d", error);
+		ctl_free_io(io);
+		refcount_release(&cs->cs_outstanding_ctl_pdus);
+		icl_pdu_free(request);
+	}
+}
+
+static void
+cfiscsi_pdu_handle_task_request(struct icl_pdu *request)
+{
+	struct iscsi_bhs_task_management_request *bhstmr;
+	struct iscsi_bhs_task_management_response *bhstmr2;
+	struct icl_pdu *response;
+	struct cfiscsi_session *cs;
+	union ctl_io *io;
+	int error;
+
+	cs = PDU_SESSION(request);
+	bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs;
+	io = ctl_alloc_io(cs->cs_target->ct_softc->fe.ctl_pool_ref);
+	if (io == NULL) {
+		CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io");
+		icl_pdu_free(request);
+		return;
+	}
+	ctl_zero_io(io);
+	io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request;
+	io->io_hdr.io_type = CTL_IO_TASK;
+	io->io_hdr.nexus.initid.id = cs->cs_ctl_initid;
+	io->io_hdr.nexus.targ_port = cs->cs_target->ct_softc->fe.targ_port;
+	io->io_hdr.nexus.targ_target.id = 0;
+	io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhstmr->bhstmr_lun);
+	io->io_hdr.nexus.lun_map_fn = cfiscsi_map_lun;
+	io->io_hdr.nexus.lun_map_arg = cs;
+	io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */
+
+	switch (bhstmr->bhstmr_function & ~0x80) {
+	case BHSTMR_FUNCTION_ABORT_TASK:
+#if 0
+		CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_ABORT_TASK");
+#endif
+		io->taskio.task_action = CTL_TASK_ABORT_TASK;
+		io->taskio.tag_num = bhstmr->bhstmr_referenced_task_tag;
+		break;
+	case BHSTMR_FUNCTION_LOGICAL_UNIT_RESET:
+#if 0
+		CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_LOGICAL_UNIT_RESET");
+#endif
+		io->taskio.task_action = CTL_TASK_LUN_RESET;
+		break;
+	case BHSTMR_FUNCTION_TARGET_COLD_RESET:
+#if 0
+		CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_TARGET_COLD_RESET");
+#endif
+		io->taskio.task_action = CTL_TASK_BUS_RESET;
+		break;
+	default:
+		CFISCSI_SESSION_DEBUG(cs, "unsupported function 0x%x",
+		    bhstmr->bhstmr_function & ~0x80);
+		ctl_free_io(io);
+
+		response = cfiscsi_pdu_new_response(request, M_NOWAIT);
+		if (response == NULL) {
+			icl_pdu_free(request);
+			return;
+		}
+		bhstmr2 = (struct iscsi_bhs_task_management_response *)
+		    response->ip_bhs;
+		bhstmr2->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_RESPONSE;
+		bhstmr2->bhstmr_flags = 0x80;
+		bhstmr2->bhstmr_response =
+		    BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED;
+		bhstmr2->bhstmr_initiator_task_tag =
+		    bhstmr->bhstmr_initiator_task_tag;
+		icl_pdu_free(request);
+		cfiscsi_pdu_queue(response);
+		return;
+	}
+
+	refcount_acquire(&cs->cs_outstanding_ctl_pdus);
+	error = ctl_queue(io);
+	if (error != CTL_RETVAL_COMPLETE) {
+		CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d", error);
+		ctl_free_io(io);
+		refcount_release(&cs->cs_outstanding_ctl_pdus);
+		icl_pdu_free(request);
+	}
+}
+
+static bool
+cfiscsi_handle_data_segment(struct icl_pdu *request, struct cfiscsi_data_wait *cdw)
+{
+	struct iscsi_bhs_data_out *bhsdo;
+	struct cfiscsi_session *cs;
+	struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
+	size_t copy_len, off, buffer_offset;
+	int ctl_sg_count;
+	union ctl_io *io;
+
+	cs = PDU_SESSION(request);
+
+	KASSERT((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
+	    ISCSI_BHS_OPCODE_SCSI_DATA_OUT ||
+	    (request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
+	    ISCSI_BHS_OPCODE_SCSI_COMMAND,
+	    ("bad opcode 0x%x", request->ip_bhs->bhs_opcode));
+
+	/*
+	 * We're only using fields common for Data Out and SCSI Command PDUs.
+	 */
+	bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs;
+
+	io = cdw->cdw_ctl_io;
+	KASSERT((io->io_hdr.flags & CTL_FLAG_DATA_MASK) != CTL_FLAG_DATA_IN,
+	    ("CTL_FLAG_DATA_IN"));
+
+#if 0
+	CFISCSI_SESSION_DEBUG(cs, "received %zd bytes out of %d",
+	    request->ip_data_len, io->scsiio.kern_total_len);
+#endif
+
+	if (io->scsiio.kern_sg_entries > 0) {
+		ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
+		ctl_sg_count = io->scsiio.kern_sg_entries;
+	} else {
+		ctl_sglist = &ctl_sg_entry;
+		ctl_sglist->addr = io->scsiio.kern_data_ptr;
+		ctl_sglist->len = io->scsiio.kern_data_len;
+		ctl_sg_count = 1;
+	}
+#if 0
+	if (ctl_sg_count > 1)
+		CFISCSI_SESSION_DEBUG(cs, "ctl_sg_count = %d", ctl_sg_count);
+#endif
+
+	if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
+	    ISCSI_BHS_OPCODE_SCSI_DATA_OUT)
+		buffer_offset = ntohl(bhsdo->bhsdo_buffer_offset);
+	else
+		buffer_offset = 0;
+
+	/*
+	 * Make sure the offset, as sent by the initiator, matches the offset
+	 * we're supposed to be at in the scatter-gather list.
+	 */
+	if (buffer_offset != io->scsiio.ext_data_filled) {
+		CFISCSI_SESSION_WARN(cs, "received bad buffer offset %zd, "
+		    "expected %zd", buffer_offset,
+		    (size_t)io->scsiio.ext_data_filled);
+		cfiscsi_session_terminate(cs);
+		return (true);
+	}
+
+	off = 0;
+	for (;;) {
+		KASSERT(cdw->cdw_sg_index < ctl_sg_count,
+		    ("cdw->cdw_sg_index >= ctl_sg_count"));
+		if (cdw->cdw_sg_len == 0) {
+			cdw->cdw_sg_addr = ctl_sglist[cdw->cdw_sg_index].addr;
+			cdw->cdw_sg_len = ctl_sglist[cdw->cdw_sg_index].len;
+		}
+		copy_len = icl_pdu_data_segment_length(request) - off;
+		if (copy_len > cdw->cdw_sg_len)
+			copy_len = cdw->cdw_sg_len;
+
+		icl_pdu_get_data(request, off, cdw->cdw_sg_addr, copy_len);
+		cdw->cdw_sg_addr += copy_len;
+		cdw->cdw_sg_len -= copy_len;
+		off += copy_len;
+		io->scsiio.ext_data_filled += copy_len;
+
+		if (cdw->cdw_sg_len == 0) {
+			if (cdw->cdw_sg_index == ctl_sg_count - 1)
+				break;
+			cdw->cdw_sg_index++;
+		}
+		if (off == icl_pdu_data_segment_length(request))
+			break;
+	}
+
+	if (off < icl_pdu_data_segment_length(request)) {
+		CFISCSI_SESSION_WARN(cs, "received too much data: got %zd bytes, "
+		    "expected %zd", icl_pdu_data_segment_length(request), off);
+		cfiscsi_session_terminate(cs);
+		return (true);
+	}
+
+	if (bhsdo->bhsdo_flags & BHSDO_FLAGS_F ||
+	    io->scsiio.ext_data_filled == io->scsiio.kern_total_len) {
+		if ((bhsdo->bhsdo_flags & BHSDO_FLAGS_F) == 0) {
+			CFISCSI_SESSION_WARN(cs, "got the final packet without "
+			    "the F flag; flags = 0x%x; dropping connection",
+			    bhsdo->bhsdo_flags);
+			cfiscsi_session_terminate(cs);
+			return (true);
+		}
+
+		if (io->scsiio.ext_data_filled != io->scsiio.kern_total_len) {
+			if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
+			    ISCSI_BHS_OPCODE_SCSI_DATA_OUT) {
+				CFISCSI_SESSION_WARN(cs, "got the final packet, but the "
+				    "transmitted size was %zd bytes instead of %d; "
+				    "dropping connection",
+				    (size_t)io->scsiio.ext_data_filled,
+				    io->scsiio.kern_total_len);
+				cfiscsi_session_terminate(cs);
+				return (true);
+			} else {
+				/*
+				 * For SCSI Command PDU, this just means we need to
+				 * solicit more data by sending R2T.
+				 */
+				return (false);
+			}
+		}
+#if 0
+		CFISCSI_SESSION_DEBUG(cs, "no longer expecting Data-Out with target "
+		    "transfer tag 0x%x", cdw->cdw_target_transfer_tag);
+#endif
+
+		return (true);
+	}
+
+	return (false);
+}
+
+static void
+cfiscsi_pdu_handle_data_out(struct icl_pdu *request)
+{
+	struct iscsi_bhs_data_out *bhsdo;
+	struct cfiscsi_session *cs;
+	struct cfiscsi_data_wait *cdw = NULL;
+	union ctl_io *io;
+	bool done;
+
+	cs = PDU_SESSION(request);
+	bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs;
+
+	CFISCSI_SESSION_LOCK(cs);
+	TAILQ_FOREACH(cdw, &cs->cs_waiting_for_data_out, cdw_next) {
+#if 0
+		CFISCSI_SESSION_DEBUG(cs, "have ttt 0x%x, itt 0x%x; looking for "
+		    "ttt 0x%x, itt 0x%x",
+		    bhsdo->bhsdo_target_transfer_tag,
+		    bhsdo->bhsdo_initiator_task_tag,
+		    cdw->cdw_target_transfer_tag, cdw->cdw_initiator_task_tag));
+#endif
+		if (bhsdo->bhsdo_target_transfer_tag ==
+		    cdw->cdw_target_transfer_tag)
+			break;
+	}
+	CFISCSI_SESSION_UNLOCK(cs);
+	if (cdw == NULL) {
+		CFISCSI_SESSION_WARN(cs, "data transfer tag 0x%x, initiator task tag "
+		    "0x%x, not found", bhsdo->bhsdo_target_transfer_tag,
+		    bhsdo->bhsdo_initiator_task_tag);
+		icl_pdu_free(request);
+		cfiscsi_session_terminate(cs);
+		return;
+	}
+
+	io = cdw->cdw_ctl_io;
+	KASSERT((io->io_hdr.flags & CTL_FLAG_DATA_MASK) != CTL_FLAG_DATA_IN,
+	    ("CTL_FLAG_DATA_IN"));
+
+	done = cfiscsi_handle_data_segment(request, cdw);
+	if (done) {
+		CFISCSI_SESSION_LOCK(cs);
+		TAILQ_REMOVE(&cs->cs_waiting_for_data_out, cdw, cdw_next);
+		CFISCSI_SESSION_UNLOCK(cs);
+		uma_zfree(cfiscsi_data_wait_zone, cdw);
+		io->scsiio.be_move_done(io);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201309141529.r8EFT647098130>