Merge r5663 from 3.0.x-iser branch

git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/3.0.x@6239 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Bart Van Assche
2015-06-11 15:32:44 +00:00
parent ef830f9335
commit faae8613ce
20 changed files with 925 additions and 269 deletions

View File

@@ -24,6 +24,7 @@ RCDIR := /etc/rc.d
MANDIR ?= $(PREFIX)/man
KMOD := $(shell pwd)/kernel
INCDIR := $(shell pwd)/include
ISERTMOD := $(KMOD)/isert-scst
ifeq ($(KVER),)
ifeq ($(KDIR),)
@@ -50,8 +51,57 @@ INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
all: include/iscsi_scst_itf_ver.h progs mods
ISER_SYMVERS:=$(KMOD)/Module.symvers
OFED_CFLAGS:=
MLNX_OFED:=$(shell if ofed_info -s | grep MLNX >/dev/null 2>/dev/null; then echo true; else echo false; fi)
ifeq ($(MLNX_OFED),true)
# Whether MLNX_OFED for ubuntu has been installed
MLNX_OFED_IB_UBUNTU_INSTALLED:=$(shell if dpkg -s mlnx-ofed-kernel-dkms >/dev/null 2>/dev/null; then echo true; else echo false; fi)
# Whether MLNX_OFED for RedHat has been installed
MLNX_OFED_IB_RH_INSTALLED:=$(shell if rpm -q mlnx-ofa_kernel-devel >&/dev/null; then echo true; else echo false; fi)
# Check if we have custom compiled kernel modules
ifeq ($(MLNX_OFED_IB_RH_INSTALLED),false)
MLNX_OFED_IB_RH_INSTALLED:=$(shell if rpm -q kernel-ib-devel >&/dev/null; then echo true; else echo false; fi)
endif
ifeq ($(MLNX_OFED_IB_UBUNTU_INSTALLED),true)
OFED_VERS=$(shell dpkg -s mlnx-ofed-kernel-dkms | awk -F\- '/Version/ {print $$1}' | awk '{print $$2}')
OFED_CFLAGS:=-I/var/lib/dkms/mlnx-ofed-kernel/$(OFED_VERS)/build/include -include /var/lib/dkms/mlnx-ofed-kernel/$(OFED_VERS)/build/include/linux/compat-2.6.h
ISER_SYMVERS:="$(ISER_SYMVERS) /var/lib/dkms/mlnx-ofed-kernel/$(OFED_VERS)/build/Module.symvers"
endif
ifeq ($(MLNX_OFED_IB_RH_INSTALLED),true)
OFED_CFLAGS:=-I/usr/src/ofa_kernel/default/include -include /usr/src/ofa_kernel/default/include/linux/compat-2.6.h
ISER_SYMVERS:="$(ISER_SYMVERS) /usr/src/ofa_kernel/default/Module.symvers"
endif
else
# Whether or not the OFED kernel-ib-devel RPM has been installed.
OFED_KERNEL_IB_DEVEL_RPM_INSTALLED:=$(shell if rpm -q kernel-ib-devel 2>/dev/null | grep -q $$(uname -r | sed 's/-/_/g'); then echo true; else echo false; fi)
# Whether or not the OFED compat-rdma-devel RPM has been installed.
OFED_COMPAT_RDMA_DEVEL_RPM_INSTALLED:=$(shell if rpm -q compat-rdma-devel 2>/dev/null | grep -q $$(uname -r | sed 's/-/_/g'); then echo true; else echo false; fi)
ifeq ($(OFED_KERNEL_IB_DEVEL_RPM_INSTALLED),true)
# Read OFED's config.mk, which contains the definition of the variable
# BACKPORT_INCLUDES.
include /usr/src/ofa_kernel/config.mk
OFED_CFLAGS:=$(shell echo $(BACKPORT_INCLUDES) -I/usr/src/ofa_kernel/include)
ISER_SYMVERS:="$(ISER_SYMVERS) /usr/src/ofa_kernel/Module.symvers"
endif
ifeq ($(OFED_COMPAT_RDMA_DEVEL_RPM_INSTALLED),true)
OFED_CFLAGS:=-I/usr/src/compat-rdma/include -include /usr/src/compat-rdma/include/linux/compat-2.6.h
ISER_SYMVERS:="$(ISER_SYMVERS) /usr/src/compat-rdma/Module.symvers"
endif
endif
mods: Modules.symvers Module.symvers
$(MAKE) -C $(KDIR) SCST_INC_DIR=$(SCST_INC_DIR) SUBDIRS=$(KMOD) modules
$(MAKE) -C $(KDIR) SCST_INC_DIR=$(SCST_INC_DIR) SUBDIRS=$(ISERTMOD) PRE_CFLAGS="$(OFED_CFLAGS)" KBUILD_EXTRA_SYMBOLS=$(ISER_SYMVERS) modules
progs:
$(MAKE) -C usr SCST_INC_DIR=$(SCST_INC_DIR)
@@ -72,6 +122,8 @@ install: all
$(MAKE) -C $(KDIR) SCST_INC_DIR=$(SCST_INC_DIR) SUBDIRS=$(KMOD) \
$$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \
modules_install
$(MAKE) -C $(KDIR) SCST_INC_DIR=$(SCST_INC_DIR) SUBDIRS=$(ISERTMOD) \
modules_install
uninstall:
rm -f $(DESTDIR)$(SBINDIR)/iscsi-scstd \
@@ -79,7 +131,8 @@ uninstall:
$(DESTDIR)$(MANDIR)/man8/iscsi-scstd.8 \
$(DESTDIR)$(SBINDIR)/iscsi-scst-adm \
$(DESTDIR)$(MANDIR)/man8/iscsi-scst-adm.8 \
$(INSTALL_DIR)/iscsi-scst.ko
$(INSTALL_DIR)/iscsi-scst.ko \
$(INSTALL_DIR)/isert-scst.ko
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Modules.symvers 2>/dev/null)
@@ -87,6 +140,7 @@ ifneq ($(SCST_MOD_VERS),)
Modules.symvers: $(SCST_DIR)/Modules.symvers
echo $(SCST_MOD_VERS)
cp $(SCST_DIR)/Modules.symvers kernel/
cp $(SCST_DIR)/Modules.symvers kernel/isert-scst
else
.PHONY: Modules.symvers
endif
@@ -96,6 +150,7 @@ SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Module.symvers 2>/dev/null)
ifneq ($(SCST_MOD_VERS),)
Module.symvers: $(SCST_DIR)/Module.symvers
cp $(SCST_DIR)/Module.symvers kernel/
cp $(SCST_DIR)/Module.symvers kernel/isert-scst
else
.PHONY: Module.symvers
endif
@@ -103,17 +158,24 @@ endif
clean:
$(MAKE) -C usr $@
$(MAKE) -C $(KDIR) SUBDIRS=$(KMOD) $@
$(MAKE) -C $(KDIR) SUBDIRS=$(ISERTMOD) $@
rm -f kernel/Modules.symvers kernel/Module.symvers \
kernel/Module.markers kernel/modules.order \
kernel/isert-scst/Modules.symvers kernel/isert-scst/Module.symvers \
kernel/isert-scst/Module.markers kernel/isert-scst/modules.order \
include/iscsi_scst_itf_ver.h
extraclean:
$(MAKE) -C usr $@
$(MAKE) -C $(KDIR) SUBDIRS=$(KMOD) clean
$(MAKE) -C $(KDIR) SUBDIRS=$(ISERTMOD) clean
rm -f kernel/Modules.symvers kernel/Module.symvers \
kernel/Module.markers kernel/modules.order \
kernel/isert-scst/Modules.symvers kernel/isert-scst/Module.symvers \
kernel/isert-scst/Module.markers kernel/isert-scst/modules.order \
include/iscsi_scst_itf_ver.h \
kernel/*.orig kernel/*.rej
kernel/*.orig kernel/*.rej \
kernel/isert-scst/*.orig kernel/isert-scst/*.rej
2release:
sed -i.aa s/"^E\?XTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ $(KMOD)/Makefile
@@ -123,6 +185,13 @@ extraclean:
sed -i.aa s/"^E\?XTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions"/ $(KMOD)/Makefile
grep "^#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions" $(KMOD)/Makefile >/dev/null
rm $(KMOD)/Makefile.aa
sed -i.aa s/"^E\?XTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ $(ISERTMOD)/Makefile
grep "^#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS" $(ISERTMOD)/Makefile >/dev/null
sed -i.aa s/"^#\?EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/"EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/ $(ISERTMOD)/Makefile
grep "^EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING" $(ISERTMOD)/Makefile >/dev/null
sed -i.aa s/"^E\?XTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions"/ $(ISERTMOD)/Makefile
grep "^#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions" $(ISERTMOD)/Makefile >/dev/null
rm $(ISERTMOD)/Makefile.aa
2debug:
sed -i.aa s/"^#\?EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ $(KMOD)/Makefile
@@ -132,6 +201,13 @@ extraclean:
sed -i.aa s/"^#\?EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions"/"EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions"/ $(KMOD)/Makefile
grep "^EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions" $(KMOD)/Makefile >/dev/null
rm $(KMOD)/Makefile.aa
sed -i.aa s/"^#\?EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ $(ISERTMOD)/Makefile
grep "^EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS" $(ISERTMOD)/Makefile >/dev/null
sed -i.aa s/"^E\?XTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/ $(ISERTMOD)/Makefile
grep "^#EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING" $(ISERTMOD)/Makefile >/dev/null
sed -i.aa s/"^#\?EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions"/"EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions"/ $(ISERTMOD)/Makefile
grep "^EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions" $(ISERTMOD)/Makefile >/dev/null
rm $(ISERTMOD)/Makefile.aa
2perf:
sed -i.aa s/"^E\?XTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ $(KMOD)/Makefile
@@ -141,6 +217,13 @@ extraclean:
sed -i.aa s/"^E\?XTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions"/ $(KMOD)/Makefile
grep "^#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions" $(KMOD)/Makefile >/dev/null
rm $(KMOD)/Makefile.aa
sed -i.aa s/"^E\?XTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS"/ $(ISERTMOD)/Makefile
grep "^#EXTRA_CFLAGS += \-DCONFIG_SCST_EXTRACHECKS" $(ISERTMOD)/Makefile >/dev/null
sed -i.aa s/"^E\?XTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING"/ $(ISERTMOD)/Makefile
grep "^#EXTRA_CFLAGS += \-DCONFIG_SCST_TRACING" $(ISERTMOD)/Makefile >/dev/null
sed -i.aa s/"^E\?XTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions"/"#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions"/ $(ISERTMOD)/Makefile
grep "^#EXTRA_CFLAGS += \-DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions" $(ISERTMOD)/Makefile >/dev/null
rm $(ISERTMOD)/Makefile.aa
disable_proc:
sed -i.aa s/"^#\?define CONFIG_SCST_PROC"/"\/* #define CONFIG_SCST_PROC *\/"/ $(INCDIR)/iscsi_scst_ver.h

View File

@@ -61,6 +61,13 @@ enum {
key_ifmarker,
key_ofmarkint,
key_ifmarkint,
key_rdma_extensions,
key_target_recv_data_length,
key_initiator_recv_data_length,
key_max_ahs_length,
key_tagged_buffer_for_solicited_data_only,
key_iser_hello_required,
key_max_outstanding_unexpected_pdus,
session_key_last,
};

View File

@@ -37,5 +37,6 @@ EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions
obj-m += iscsi-scst.o
iscsi-scst-objs := iscsi.o nthread.o config.o digest.o \
conn.o session.o target.o event.o param.o
conn.o session.o target.o event.o param.o \
iscsit_transport.o

View File

@@ -20,6 +20,7 @@
#include "iscsi.h"
#include "digest.h"
#include "iscsit_transport.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
#if defined(CONFIG_LOCKDEP) && !defined(CONFIG_SCST_PROC)
@@ -273,7 +274,7 @@ static void conn_sysfs_del(struct iscsi_conn *conn)
return;
}
static int conn_sysfs_add(struct iscsi_conn *conn)
int conn_sysfs_add(struct iscsi_conn *conn)
{
int res;
struct iscsi_session *session = conn->session;
@@ -345,6 +346,7 @@ out_err:
conn_sysfs_del(conn);
goto out;
}
EXPORT_SYMBOL(conn_sysfs_add);
#endif /* CONFIG_SCST_PROC */
@@ -429,7 +431,7 @@ void iscsi_make_conn_wr_active(struct iscsi_conn *conn)
return;
}
void __mark_conn_closed(struct iscsi_conn *conn, int flags)
void iscsi_tcp_mark_conn_closed(struct iscsi_conn *conn, int flags)
{
spin_lock_bh(&conn->conn_thr_pool->rd_lock);
conn->closing = 1;
@@ -442,10 +444,16 @@ void __mark_conn_closed(struct iscsi_conn *conn, int flags)
iscsi_make_conn_rd_active(conn);
}
void __mark_conn_closed(struct iscsi_conn *conn, int flags)
{
conn->transport->iscsit_mark_conn_closed(conn, flags);
}
void mark_conn_closed(struct iscsi_conn *conn)
{
__mark_conn_closed(conn, ISCSI_CONN_ACTIVE_CLOSE);
}
EXPORT_SYMBOL(mark_conn_closed);
static void __iscsi_state_change(struct sock *sk)
{
@@ -752,7 +760,7 @@ void conn_reinst_finished(struct iscsi_conn *conn)
return;
}
static void conn_activate(struct iscsi_conn *conn)
int conn_activate(struct iscsi_conn *conn)
{
TRACE_MGMT_DBG("Enabling conn %p", conn);
@@ -778,7 +786,7 @@ static void conn_activate(struct iscsi_conn *conn)
*/
__iscsi_state_change(conn->sock->sk);
return;
return 0;
}
/*
@@ -820,8 +828,19 @@ out:
return res;
}
void iscsi_tcp_conn_free(struct iscsi_conn *conn)
{
fput(conn->file);
conn->file = NULL;
conn->sock = NULL;
free_page((unsigned long)conn->read_iov);
kmem_cache_free(iscsi_conn_cache, conn);
}
/* target_mutex supposed to be locked */
int conn_free(struct iscsi_conn *conn)
void conn_free(struct iscsi_conn *conn)
{
struct iscsi_session *session = conn->session;
@@ -915,7 +934,7 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
conn->ddigest_type = session->sess_params.data_digest;
res = digest_init(conn);
if (res != 0)
goto out_free_iov;
return res;
conn->target = session->target;
spin_lock_init(&conn->cmd_list_lock);
@@ -950,6 +969,44 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
conn->nop_in_interval + ISCSI_ADD_SCHED_TIME);
}
return 0;
}
EXPORT_SYMBOL(iscsi_init_conn);
/* target_mutex supposed to be locked */
int iscsi_conn_alloc(struct iscsi_session *session,
struct iscsi_kern_conn_info *info, struct iscsi_conn **new_conn,
struct iscsit_transport *t)
{
struct iscsi_conn *conn;
int res = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
lockdep_assert_held(&session->target->target_mutex);
#endif
conn = kmem_cache_zalloc(iscsi_conn_cache, GFP_KERNEL);
if (!conn) {
res = -ENOMEM;
goto out_err;
}
TRACE_MGMT_DBG("Creating connection %p for sid %#Lx, cid %u", conn,
(long long unsigned int)session->sid, info->cid);
conn->transport = t;
/* Changing it, change ISCSI_CONN_IOV_MAX as well !! */
conn->read_iov = (struct iovec *)get_zeroed_page(GFP_KERNEL);
if (conn->read_iov == NULL) {
res = -ENOMEM;
goto out_err_free_conn;
}
res = iscsi_init_conn(session, info, conn);
if (res != 0)
goto out_free_iov;
conn->file = fget(info->fd);
res = conn_setup_sock(conn);
@@ -988,6 +1045,7 @@ int __add_conn(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
struct iscsi_conn *conn, *new_conn = NULL;
int err;
bool reinstatement = false;
struct iscsit_transport *t;
lockdep_assert_held(&session->target->target_mutex);
@@ -1001,7 +1059,16 @@ int __add_conn(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
goto out;
}
err = iscsi_conn_alloc(session, info, &new_conn);
if (session->sess_params.rdma_extensions)
t = iscsit_get_transport(ISCSI_RDMA);
else
t = iscsit_get_transport(ISCSI_TCP);
if (!t) {
err = -ENOENT;
goto out;
}
err = t->iscsit_conn_alloc(session, info, &new_conn, t);
if (err != 0)
goto out;
@@ -1013,7 +1080,7 @@ int __add_conn(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
__mark_conn_closed(conn, 0);
}
conn_activate(new_conn);
err = t->iscsit_conn_activate(new_conn);
out:
return err;

View File

@@ -26,6 +26,7 @@
#include "iscsi.h"
#include "digest.h"
#include "iscsit_transport.h"
#ifndef GENERATING_UPSTREAM_PATCH
#if !defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
@@ -64,11 +65,9 @@ static void cmnd_remove_data_wait_hash(struct iscsi_cmnd *cmnd);
static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status,
bool dropped);
static void iscsi_check_send_delayed_tm_resp(struct iscsi_session *sess);
static void req_cmnd_release(struct iscsi_cmnd *req);
static int cmnd_insert_data_wait_hash(struct iscsi_cmnd *cmnd);
static void iscsi_cmnd_init_write(struct iscsi_cmnd *rsp, int flags);
static void iscsi_set_resid_no_scst_cmd(struct iscsi_cmnd *rsp);
static void iscsi_set_resid(struct iscsi_cmnd *rsp);
static void iscsi_set_not_received_data_len(struct iscsi_cmnd *req,
unsigned int not_received)
@@ -242,7 +241,7 @@ static struct iscsi_cmnd *iscsi_create_tm_clone(struct iscsi_cmnd *cmnd)
TRACE_ENTRY();
tm_clone = cmnd_alloc(cmnd->conn, NULL);
tm_clone = cmnd->conn->transport->iscsit_alloc_cmd(cmnd->conn, NULL);
if (tm_clone != NULL) {
set_bit(ISCSI_CMD_ABORTED, &tm_clone->prelim_compl_flags);
tm_clone->pdu = cmnd->pdu;
@@ -309,14 +308,9 @@ void iscsi_fail_data_waiting_cmnd(struct iscsi_cmnd *cmnd)
return;
}
struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn,
struct iscsi_cmnd *parent)
void iscsi_cmnd_init(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd,
struct iscsi_cmnd *parent)
{
struct iscsi_cmnd *cmnd;
/* ToDo: __GFP_NOFAIL?? */
cmnd = kmem_cache_zalloc(iscsi_cmnd_cache, GFP_KERNEL|__GFP_NOFAIL);
atomic_set(&cmnd->ref_cnt, 1);
cmnd->scst_state = ISCSI_CMD_STATE_NEW;
cmnd->conn = conn;
@@ -325,9 +319,6 @@ struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn,
if (parent == NULL) {
conn_get(conn);
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
atomic_set(&cmnd->net_ref_cnt, 0);
#endif
INIT_LIST_HEAD(&cmnd->rsp_cmd_list);
INIT_LIST_HEAD(&cmnd->rx_ddigest_cmd_list);
cmnd->target_task_tag = ISCSI_RESERVED_TAG_CPU32;
@@ -336,6 +327,24 @@ struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn,
list_add_tail(&cmnd->cmd_list_entry, &conn->cmd_list);
spin_unlock_bh(&conn->cmd_list_lock);
}
}
EXPORT_SYMBOL(iscsi_cmnd_init);
struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn,
struct iscsi_cmnd *parent)
{
struct iscsi_cmnd *cmnd;
/* ToDo: __GFP_NOFAIL?? */
cmnd = kmem_cache_zalloc(iscsi_cmnd_cache, GFP_KERNEL|__GFP_NOFAIL);
iscsi_cmnd_init(conn, cmnd, parent);
if (parent == NULL) {
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
atomic_set(&cmnd->net_ref_cnt, 0);
#endif
}
TRACE_DBG("conn %p, parent %p, cmnd %p", conn, parent, cmnd);
return cmnd;
@@ -496,10 +505,10 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
list_for_each_entry_safe(rsp, t, &cmnd->rsp_cmd_list,
rsp_cmd_list_entry) {
cmnd_free(rsp);
cmnd->conn->transport->iscsit_free_cmd(rsp);
}
cmnd_free(cmnd);
cmnd->conn->transport->iscsit_free_cmd(cmnd);
} else {
struct iscsi_cmnd *parent = cmnd->parent_req;
@@ -532,6 +541,7 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
TRACE_EXIT();
return;
}
EXPORT_SYMBOL(cmnd_done);
/*
* Corresponding conn may also get destroyed after this function, except only
@@ -634,7 +644,7 @@ out:
return;
}
static void req_cmnd_pre_release(struct iscsi_cmnd *req)
void req_cmnd_pre_release(struct iscsi_cmnd *req)
{
struct iscsi_cmnd *c, *t;
@@ -694,12 +704,13 @@ static void req_cmnd_pre_release(struct iscsi_cmnd *req)
TRACE_EXIT();
return;
}
EXPORT_SYMBOL(req_cmnd_pre_release);
/*
* Corresponding conn may also get destroyed after this function, except only
* if it's called from the read thread!
*/
static void req_cmnd_release(struct iscsi_cmnd *req)
void req_cmnd_release(struct iscsi_cmnd *req)
{
TRACE_ENTRY();
@@ -709,6 +720,7 @@ static void req_cmnd_release(struct iscsi_cmnd *req)
TRACE_EXIT();
return;
}
EXPORT_SYMBOL(req_cmnd_release);
/*
* Corresponding conn may also get destroyed after this function, except only
@@ -728,6 +740,7 @@ void rsp_cmnd_release(struct iscsi_cmnd *cmnd)
cmnd_put(cmnd);
return;
}
EXPORT_SYMBOL(rsp_cmnd_release);
static struct iscsi_cmnd *iscsi_alloc_rsp(struct iscsi_cmnd *parent)
{
@@ -735,7 +748,7 @@ static struct iscsi_cmnd *iscsi_alloc_rsp(struct iscsi_cmnd *parent)
TRACE_ENTRY();
rsp = cmnd_alloc(parent->conn, parent);
rsp = parent->conn->transport->iscsit_alloc_cmd(parent->conn, parent);
TRACE_DBG("Adding rsp %p to parent %p", rsp, parent);
list_add_tail(&rsp->rsp_cmd_list_entry, &parent->rsp_cmd_list);
@@ -797,7 +810,7 @@ static void iscsi_cmnds_init_write(struct list_head *send, int flags)
spin_unlock_bh(&conn->write_list_lock);
if (flags & ISCSI_INIT_WRITE_WAKE)
iscsi_make_conn_wr_active(conn);
conn->transport->iscsit_make_conn_wr_active(conn);
return;
}
@@ -876,7 +889,7 @@ static void iscsi_set_resid_no_scst_cmd(struct iscsi_cmnd *rsp)
return;
}
static void iscsi_set_resid(struct iscsi_cmnd *rsp)
void iscsi_set_resid(struct iscsi_cmnd *rsp)
{
struct iscsi_cmnd *req = rsp->parent_req;
struct scst_cmd *scst_cmd = req->scst_cmd;
@@ -930,6 +943,7 @@ out:
TRACE_EXIT();
return;
}
EXPORT_SYMBOL(iscsi_set_resid);
static void send_data_rsp(struct iscsi_cmnd *req, u8 status, int send_status)
{
@@ -992,12 +1006,25 @@ static void send_data_rsp(struct iscsi_cmnd *req, u8 status, int send_status)
return;
}
static void iscsi_tcp_set_sense_data(struct iscsi_cmnd *rsp,
const u8 *sense_buf, int sense_len)
{
struct scatterlist *sg;
sg = rsp->sg = rsp->rsp_sg;
rsp->sg_cnt = 2;
rsp->own_sg = 1;
sg_init_table(sg, 2);
sg_set_buf(&sg[0], &rsp->sense_hdr, sizeof(rsp->sense_hdr));
sg_set_buf(&sg[1], sense_buf, sense_len);
}
static void iscsi_init_status_rsp(struct iscsi_cmnd *rsp,
int status, const u8 *sense_buf, int sense_len)
{
struct iscsi_cmnd *req = rsp->parent_req;
struct iscsi_scsi_rsp_hdr *rsp_hdr;
struct scatterlist *sg;
TRACE_ENTRY();
@@ -1011,16 +1038,11 @@ static void iscsi_init_status_rsp(struct iscsi_cmnd *rsp,
if (scst_sense_valid(sense_buf)) {
TRACE_DBG("%s", "SENSE VALID");
sg = rsp->sg = rsp->rsp_sg;
rsp->sg_cnt = 2;
rsp->own_sg = 1;
sg_init_table(sg, 2);
sg_set_buf(&sg[0], &rsp->sense_hdr, sizeof(rsp->sense_hdr));
sg_set_buf(&sg[1], sense_buf, sense_len);
rsp->sense_hdr.length = cpu_to_be16(sense_len);
rsp->conn->transport->iscsit_set_sense_data(rsp, sense_buf,
sense_len);
rsp->pdu.datasize = sizeof(rsp->sense_hdr) + sense_len;
rsp->bufflen = rsp->pdu.datasize;
} else {
@@ -1032,7 +1054,7 @@ static void iscsi_init_status_rsp(struct iscsi_cmnd *rsp,
return;
}
static inline struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req,
struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req,
int status, const u8 *sense_buf, int sense_len)
{
struct iscsi_cmnd *rsp;
@@ -1048,6 +1070,26 @@ static inline struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req,
TRACE_EXIT_HRES((unsigned long)rsp);
return rsp;
}
EXPORT_SYMBOL(create_status_rsp);
static void iscsi_tcp_send_data_rsp(struct iscsi_cmnd *req, u8 *sense,
int sense_len, u8 status,
int is_send_status)
{
if ((status != SAM_STAT_CHECK_CONDITION) &&
((cmnd_hdr(req)->flags & (ISCSI_CMD_WRITE|ISCSI_CMD_READ)) !=
(ISCSI_CMD_WRITE|ISCSI_CMD_READ))) {
send_data_rsp(req, status, is_send_status);
} else {
struct iscsi_cmnd *rsp;
send_data_rsp(req, 0, 0);
if (is_send_status) {
rsp = create_status_rsp(req, status, sense,
sense_len);
iscsi_cmnd_init_write(rsp, 0);
}
}
}
/*
* Initializes data receive fields. Can be called only when they have not been
@@ -1224,7 +1266,7 @@ static inline int iscsi_get_allowed_cmds(struct iscsi_session *sess)
return res;
}
static __be32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn)
__be32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn)
{
struct iscsi_conn *conn = cmnd->conn;
struct iscsi_session *sess = conn->session;
@@ -1243,6 +1285,7 @@ static __be32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn)
spin_unlock(&sess->sn_lock);
return res;
}
EXPORT_SYMBOL(cmnd_set_sn);
/* Called under sn_lock */
static void update_stat_sn(struct iscsi_cmnd *cmnd)
@@ -1739,7 +1782,7 @@ static int nop_out_start(struct iscsi_cmnd *cmnd)
size = cmnd->pdu.datasize;
if (size) {
if (size && !conn->session->sess_params.rdma_extensions) {
conn->read_msg.msg_iov = conn->read_iov;
if (cmnd->pdu.bhs.itt != ISCSI_RESERVED_TAG) {
struct scatterlist *sg;
@@ -1796,16 +1839,87 @@ out:
return err;
}
int cmnd_rx_continue(struct iscsi_cmnd *req)
int iscsi_cmnd_set_write_buf(struct iscsi_cmnd *req)
{
struct iscsi_conn *conn = req->conn;
struct iscsi_session *session = conn->session;
struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req);
struct scst_cmd *scst_cmd = req->scst_cmd;
scst_data_direction dir;
bool unsolicited_data_expected = false;
int res = 0;
req->bufflen = scst_cmd_get_write_fields(scst_cmd, &req->sg,
&req->sg_cnt);
unsolicited_data_expected = !(req_hdr->flags & ISCSI_CMD_FINAL);
if (unlikely(session->sess_params.initial_r2t &&
unsolicited_data_expected)) {
PRINT_ERROR("Initiator %s violated negotiated "
"parameters: initial R2T is required (ITT %x, "
"op %x)", session->initiator_name,
req->pdu.bhs.itt, req_hdr->scb[0]);
res = -EINVAL;
goto out_close;
}
if (unlikely(!session->sess_params.immediate_data &&
req->pdu.datasize)) {
PRINT_ERROR("Initiator %s violated negotiated "
"parameters: forbidden immediate data sent "
"(ITT %x, op %x)", session->initiator_name,
req->pdu.bhs.itt, req_hdr->scb[0]);
res = -EINVAL;
goto out_close;
}
if (unlikely(session->sess_params.first_burst_length < req->pdu.datasize)) {
PRINT_ERROR("Initiator %s violated negotiated "
"parameters: immediate data len (%d) > "
"first_burst_length (%d) (ITT %x, op %x)",
session->initiator_name,
req->pdu.datasize,
session->sess_params.first_burst_length,
req->pdu.bhs.itt, req_hdr->scb[0]);
res = -EINVAL;
goto out_close;
}
req->r2t_len_to_receive = be32_to_cpu(req_hdr->data_length) -
req->pdu.datasize;
/*
* In case of residual overflow req->r2t_len_to_receive and
* req->pdu.datasize might be > req->bufflen
*/
res = cmnd_insert_data_wait_hash(req);
if (unsolicited_data_expected) {
req->outstanding_r2t = 1;
req->r2t_len_to_send = req->r2t_len_to_receive -
min_t(unsigned int,
session->sess_params.first_burst_length -
req->pdu.datasize,
req->r2t_len_to_receive);
} else
req->r2t_len_to_send = req->r2t_len_to_receive;
if (likely(res == 0))
req_add_to_write_timeout_list(req);
out_close:
return res;
}
EXPORT_SYMBOL(iscsi_cmnd_set_write_buf);
int cmnd_rx_continue(struct iscsi_cmnd *req)
{
struct iscsi_conn *conn = req->conn;
struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req);
struct scst_cmd *scst_cmd = req->scst_cmd;
scst_data_direction dir;
int res = 0;
TRACE_ENTRY();
TRACE_DBG("scsi command: %x", req_hdr->scb[0]);
@@ -1831,48 +1945,7 @@ int cmnd_rx_continue(struct iscsi_cmnd *req)
/* For prelim completed commands sg & K can be already set! */
if (dir & SCST_DATA_WRITE) {
req->bufflen = scst_cmd_get_write_fields(scst_cmd, &req->sg,
&req->sg_cnt);
unsolicited_data_expected = !(req_hdr->flags & ISCSI_CMD_FINAL);
if (unlikely(session->sess_params.initial_r2t &&
unsolicited_data_expected)) {
PRINT_ERROR("Initiator %s violated negotiated "
"parameters: initial R2T is required (ITT %x, "
"op %x)", session->initiator_name,
req->pdu.bhs.itt, req_hdr->scb[0]);
goto out_close;
}
if (unlikely(!session->sess_params.immediate_data &&
req->pdu.datasize)) {
PRINT_ERROR("Initiator %s violated negotiated "
"parameters: forbidden immediate data sent "
"(ITT %x, op %x)", session->initiator_name,
req->pdu.bhs.itt, req_hdr->scb[0]);
goto out_close;
}
if (unlikely(session->sess_params.first_burst_length < req->pdu.datasize)) {
PRINT_ERROR("Initiator %s violated negotiated "
"parameters: immediate data len (%d) > "
"first_burst_length (%d) (ITT %x, op %x)",
session->initiator_name,
req->pdu.datasize,
session->sess_params.first_burst_length,
req->pdu.bhs.itt, req_hdr->scb[0]);
goto out_close;
}
req->r2t_len_to_receive = be32_to_cpu(req_hdr->data_length) -
req->pdu.datasize;
/*
* In case of residual overflow req->r2t_len_to_receive and
* req->pdu.datasize might be > req->bufflen
*/
res = cmnd_insert_data_wait_hash(req);
res = iscsi_cmnd_set_write_buf(req);
if (unlikely(res != 0)) {
/*
* We have to close connection, because otherwise a data
@@ -1883,18 +1956,6 @@ int cmnd_rx_continue(struct iscsi_cmnd *req)
goto out_close;
}
if (unsolicited_data_expected) {
req->outstanding_r2t = 1;
req->r2t_len_to_send = req->r2t_len_to_receive -
min_t(unsigned int,
session->sess_params.first_burst_length -
req->pdu.datasize,
req->r2t_len_to_receive);
} else
req->r2t_len_to_send = req->r2t_len_to_receive;
req_add_to_write_timeout_list(req);
if (req->pdu.datasize) {
res = cmnd_prepare_recv_pdu(conn, req, 0, req->pdu.datasize);
/* For performance better to send R2Ts ASAP */
@@ -1916,11 +1977,9 @@ int cmnd_rx_continue(struct iscsi_cmnd *req)
}
trace:
TRACE_DBG("req=%p, dir=%d, unsolicited_data_expected=%d, "
"r2t_len_to_receive=%d, r2t_len_to_send=%d, bufflen=%d, "
"own_sg %d", req, dir, unsolicited_data_expected,
req->r2t_len_to_receive, req->r2t_len_to_send, req->bufflen,
req->own_sg);
TRACE_DBG("req=%p, dir=%d, r2t_len_to_receive=%d, r2t_len_to_send=%d, "
"bufflen=%d, own_sg %d", req, dir, req->r2t_len_to_receive,
req->r2t_len_to_send, req->bufflen, req->own_sg);
out:
TRACE_EXIT_RES(res);
@@ -1980,7 +2039,8 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
scst_cmd_set_expected_out_transfer_len(scst_cmd,
be32_to_cpu(req_hdr->data_length));
#if !defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
scst_cmd_set_tgt_need_alloc_data_buf(scst_cmd);
if (conn->transport->need_alloc_write_buf)
scst_cmd_set_tgt_need_alloc_data_buf(scst_cmd);
#endif
}
} else if (req_hdr->flags & ISCSI_CMD_READ) {
@@ -1988,7 +2048,8 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
scst_cmd_set_expected(scst_cmd, dir,
be32_to_cpu(req_hdr->data_length));
#if !defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
scst_cmd_set_tgt_need_alloc_data_buf(scst_cmd);
if (conn->transport->need_alloc_write_buf)
scst_cmd_set_tgt_need_alloc_data_buf(scst_cmd);
#endif
} else if (req_hdr->flags & ISCSI_CMD_WRITE) {
dir = SCST_DATA_WRITE;
@@ -2055,7 +2116,7 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
scst_cmd_init_stage1_done(scst_cmd, SCST_CONTEXT_DIRECT, 0);
if (req->scst_state != ISCSI_CMD_STATE_RX_CMD)
res = cmnd_rx_continue(req);
res = req->conn->transport->iscsit_receive_cmnd_data(req);
else {
TRACE_DBG("Delaying req %p post processing (scst_state %d)",
req, req->scst_state);
@@ -2666,6 +2727,14 @@ reject:
return;
}
static void iscsi_tcp_set_req_data(struct iscsi_cmnd *req,
struct iscsi_cmnd *rsp)
{
rsp->sg = req->sg;
rsp->sg_cnt = req->sg_cnt;
rsp->bufflen = req->bufflen;
}
static void nop_out_exec(struct iscsi_cmnd *req)
{
struct iscsi_cmnd *rsp;
@@ -2689,11 +2758,8 @@ static void nop_out_exec(struct iscsi_cmnd *req)
else
sBUG_ON(req->sg != NULL);
if (req->sg) {
rsp->sg = req->sg;
rsp->sg_cnt = req->sg_cnt;
rsp->bufflen = req->bufflen;
}
if (req->bufflen)
req->conn->transport->iscsit_set_req_data(req, rsp);
/* We already checked it in check_segment_length() */
sBUG_ON(get_pgcnt(req->pdu.datasize, 0) > ISCSI_CONN_IOV_MAX);
@@ -3146,6 +3212,7 @@ out:
TRACE_EXIT_RES(res);
return res;
}
EXPORT_SYMBOL(cmnd_rx_start);
void cmnd_rx_end(struct iscsi_cmnd *cmnd)
{
@@ -3177,6 +3244,48 @@ out:
TRACE_EXIT();
return;
}
EXPORT_SYMBOL(cmnd_rx_end);
static ssize_t iscsi_tcp_get_initiator_ip(struct iscsi_conn *conn,
char *buf, int size)
{
int pos;
struct sock *sk;
TRACE_ENTRY();
sk = conn->sock->sk;
switch (sk->sk_family) {
case AF_INET:
pos = scnprintf(buf, size,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
"%u.%u.%u.%u", NIPQUAD(inet_sk(sk)->daddr));
#else
"%pI4", &inet_sk(sk)->inet_daddr);
#endif
break;
case AF_INET6:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
pos = scnprintf(buf, size,
"[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
NIP6(inet6_sk(sk)->daddr));
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
pos = scnprintf(buf, size, "[%p6]", &inet6_sk(sk)->daddr);
#else
pos = scnprintf(buf, size, "[%p6]", &sk->sk_v6_daddr);
#endif
#endif
break;
default:
pos = scnprintf(buf, size, "Unknown family %d",
sk->sk_family);
break;
}
TRACE_EXIT_RES(pos);
return pos;
}
#if !defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
static int iscsi_alloc_data_buf(struct scst_cmd *cmd)
@@ -3194,11 +3303,8 @@ static int iscsi_alloc_data_buf(struct scst_cmd *cmd)
}
#endif
static void iscsi_preprocessing_done(struct scst_cmd *scst_cmd)
static void iscsi_tcp_preprocessing_done(struct iscsi_cmnd *req)
{
struct iscsi_cmnd *req = (struct iscsi_cmnd *)
scst_cmd_get_tgt_priv(scst_cmd);
TRACE_DBG("req %p", req);
if (req->conn->rx_task == current)
@@ -3225,8 +3331,14 @@ static void iscsi_preprocessing_done(struct scst_cmd *scst_cmd)
}
cmnd_put(req);
}
}
return;
static void iscsi_preprocessing_done(struct scst_cmd *scst_cmd)
{
struct iscsi_cmnd *req = (struct iscsi_cmnd *)
scst_cmd_get_tgt_priv(scst_cmd);
req->conn->transport->iscsit_preprocessing_done(req);
}
/* No locks */
@@ -3287,6 +3399,52 @@ static void iscsi_try_local_processing(struct iscsi_cmnd *req)
return;
}
static int iscsi_tcp_send_locally(struct iscsi_cmnd *req,
unsigned int cmd_count)
{
struct iscsi_conn *conn = req->conn;
struct iscsi_cmnd *wr_rsp, *our_rsp;
int ret = 0;
/*
* There's no need for protection, since we are not going to
* dereference them.
*/
wr_rsp = list_first_entry(&conn->write_list, struct iscsi_cmnd,
write_list_entry);
our_rsp = list_first_entry(&req->rsp_cmd_list, struct iscsi_cmnd,
rsp_cmd_list_entry);
if (wr_rsp == our_rsp) {
/*
* This is our rsp, so let's try to process it locally to
* decrease latency. We need to call pre_release before
* processing to handle some error recovery cases.
*/
if (cmd_count <= 2) {
req_cmnd_pre_release(req);
iscsi_try_local_processing(req);
cmnd_put(req);
} else {
/*
* There's too much backend activity, so it could be
* better to push it to the write thread.
*/
ret = 1;
}
} else
ret = 1;
return ret;
}
static void iscsi_tcp_conn_close(struct iscsi_conn *conn, int flags)
{
if (!flags)
conn->sock->sk->sk_prot->disconnect(conn->sock->sk, 0);
else
conn->sock->ops->shutdown(conn->sock, flags);
}
static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
{
int is_send_status = scst_cmd_get_is_send_status(scst_cmd);
@@ -3296,7 +3454,6 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
int status = scst_cmd_get_status(scst_cmd);
u8 *sense = scst_cmd_get_sense_buffer(scst_cmd);
int sense_len = scst_cmd_get_sense_buffer_len(scst_cmd);
struct iscsi_cmnd *wr_rsp, *our_rsp;
EXTRACHECKS_BUG_ON(scst_cmd_atomic(scst_cmd));
@@ -3371,19 +3528,9 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
* so status is valid here, but in future that could change.
* ToDo
*/
if ((status != SAM_STAT_CHECK_CONDITION) &&
((cmnd_hdr(req)->flags & (ISCSI_CMD_WRITE|ISCSI_CMD_READ)) !=
(ISCSI_CMD_WRITE|ISCSI_CMD_READ))) {
send_data_rsp(req, status, is_send_status);
} else {
struct iscsi_cmnd *rsp;
send_data_rsp(req, 0, 0);
if (is_send_status) {
rsp = create_status_rsp(req, status, sense,
sense_len);
iscsi_cmnd_init_write(rsp, 0);
}
}
req->conn->transport->iscsit_send_data_rsp(req, sense,
sense_len, status,
is_send_status);
} else if (is_send_status) {
struct iscsi_cmnd *rsp;
rsp = create_status_rsp(req, status, sense, sense_len);
@@ -3394,32 +3541,7 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
sBUG();
#endif
/*
* There's no need for protection, since we are not going to
* dereference them.
*/
wr_rsp = list_first_entry(&conn->write_list, struct iscsi_cmnd,
write_list_entry);
our_rsp = list_first_entry(&req->rsp_cmd_list, struct iscsi_cmnd,
rsp_cmd_list_entry);
if (wr_rsp == our_rsp) {
/*
* This is our rsp, so let's try to process it locally to
* decrease latency. We need to call pre_release before
* processing to handle some error recovery cases.
*/
if (scst_get_active_cmd_count(scst_cmd) <= 2) {
req_cmnd_pre_release(req);
iscsi_try_local_processing(req);
cmnd_put(req);
} else {
/*
* There's too much backend activity, so it could be
* better to push it to the write thread.
*/
goto out_push_to_wr_thread;
}
} else
if (conn->transport->iscsit_send_locally(req, scst_get_active_cmd_count(scst_cmd)))
goto out_push_to_wr_thread;
out:
@@ -3428,7 +3550,7 @@ out:
out_push_to_wr_thread:
TRACE_DBG("Waking up write thread (conn %p)", conn);
req_cmnd_release(req);
iscsi_make_conn_wr_active(conn);
conn->transport->iscsit_make_conn_wr_active(conn);
goto out;
}
@@ -3631,7 +3753,6 @@ static int iscsi_scsi_aen(struct scst_aen *aen)
bool found;
struct iscsi_cmnd *fake_req, *rsp;
struct iscsi_async_msg_hdr *rsp_hdr;
struct scatterlist *sg;
TRACE_ENTRY();
@@ -3654,7 +3775,7 @@ static int iscsi_scsi_aen(struct scst_aen *aen)
}
/* Create a fake request */
fake_req = cmnd_alloc(conn, NULL);
fake_req = conn->transport->iscsit_alloc_cmd(conn, NULL);
if (fake_req == NULL) {
PRINT_ERROR("%s", "Unable to alloc fake AEN request");
goto out_err_unlock;
@@ -3679,15 +3800,10 @@ static int iscsi_scsi_aen(struct scst_aen *aen)
rsp_hdr->ffffffff = cpu_to_be32(0xffffffff);
rsp_hdr->async_event = ISCSI_ASYNC_SCSI;
sg = rsp->sg = rsp->rsp_sg;
rsp->sg_cnt = 2;
rsp->own_sg = 1;
sg_init_table(sg, 2);
sg_set_buf(&sg[0], &rsp->sense_hdr, sizeof(rsp->sense_hdr));
sg_set_buf(&sg[1], sense, sense_len);
rsp->sense_hdr.length = cpu_to_be16(sense_len);
rsp->conn->transport->iscsit_set_sense_data(rsp, sense, sense_len);
rsp->pdu.datasize = sizeof(rsp->sense_hdr) + sense_len;
rsp->bufflen = rsp->pdu.datasize;
@@ -3809,7 +3925,7 @@ void iscsi_send_nop_in(struct iscsi_conn *conn)
TRACE_ENTRY();
req = cmnd_alloc(conn, NULL);
req = conn->transport->iscsit_alloc_cmd(conn, NULL);
if (req == NULL) {
PRINT_ERROR("%s", "Unable to alloc fake Nop-In request");
goto out_err;
@@ -3951,6 +4067,30 @@ struct scst_tgt_template iscsi_template = {
.get_scsi_transport_version = iscsi_get_scsi_transport_version,
};
static struct iscsit_transport iscsi_tcp_transport = {
.owner = THIS_MODULE,
.name = "iSCSI-TCP",
.transport_type = ISCSI_TCP,
#if !defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
.need_alloc_write_buf = 1,
#endif
.iscsit_conn_alloc = iscsi_conn_alloc,
.iscsit_conn_activate = conn_activate,
.iscsit_conn_free = iscsi_tcp_conn_free,
.iscsit_alloc_cmd = cmnd_alloc,
.iscsit_free_cmd = cmnd_free,
.iscsit_preprocessing_done = iscsi_tcp_preprocessing_done,
.iscsit_send_data_rsp = iscsi_tcp_send_data_rsp,
.iscsit_make_conn_wr_active = iscsi_make_conn_wr_active,
.iscsit_mark_conn_closed = iscsi_tcp_mark_conn_closed,
.iscsit_conn_close = iscsi_tcp_conn_close,
.iscsit_get_initiator_ip = iscsi_tcp_get_initiator_ip,
.iscsit_send_locally = iscsi_tcp_send_locally,
.iscsit_set_sense_data = iscsi_tcp_set_sense_data,
.iscsit_set_req_data = iscsi_tcp_set_req_data,
.iscsit_receive_cmnd_data = cmnd_rx_continue,
};
static void __iscsi_threads_pool_put(struct iscsi_thread_pool *p)
{
struct iscsi_thread *t, *tt;
@@ -4106,6 +4246,10 @@ static int __init iscsi_init(void)
PRINT_INFO("iSCSI SCST Target - version %s", ISCSI_VERSION_STRING);
err = iscsit_register_transport(&iscsi_tcp_transport);
if (err)
goto out;
dummy_page = alloc_pages(GFP_KERNEL, 0);
if (dummy_page == NULL) {
PRINT_ERROR("%s", "Dummy page allocation failed");
@@ -4256,6 +4400,8 @@ static void __exit iscsi_exit(void)
scst_unregister_target_template(&iscsi_template);
iscsit_unregister_transport(&iscsi_tcp_transport);
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
net_set_get_put_page_callbacks(NULL, NULL);
#endif

View File

@@ -32,6 +32,7 @@
#endif
#include "iscsi_hdr.h"
#include "iscsi_dbg.h"
#include "iscsit_transport.h"
#define iscsi_sense_crc_error ABORTED_COMMAND, 0x47, 0x05
#define iscsi_sense_unexpected_unsolicited_data ABORTED_COMMAND, 0x0C, 0x0C
@@ -57,6 +58,9 @@ struct iscsi_sess_params {
int ifmarker;
int ofmarkint;
int ifmarkint;
int rdma_extensions;
int target_recv_data_length;
int initiator_recv_data_length;
};
struct iscsi_tgt_params {
@@ -190,6 +194,8 @@ struct iscsi_session {
#define ISCSI_CONN_WR_STATE_PROCESSING 3
struct iscsi_conn {
struct iscsit_transport *transport;
struct iscsi_session *session; /* owning session */
/* Both protected by session->sn_lock */
@@ -308,6 +314,7 @@ struct iscsi_conn {
#else
struct work_struct nop_in_delayed_work;
#endif
struct work_struct close_work;
unsigned int nop_in_interval; /* in jiffies */
unsigned int nop_in_timeout; /* in jiffies */
struct list_head nop_req_list;
@@ -555,7 +562,7 @@ extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16);
extern void conn_reinst_finished(struct iscsi_conn *);
extern int __add_conn(struct iscsi_session *, struct iscsi_kern_conn_info *);
extern int __del_conn(struct iscsi_session *, struct iscsi_kern_conn_info *);
extern int conn_free(struct iscsi_conn *);
extern void conn_free(struct iscsi_conn *);
extern void iscsi_make_conn_rd_active(struct iscsi_conn *conn);
#define ISCSI_CONN_ACTIVE_CLOSE 1
#define ISCSI_CONN_DELETING 2
@@ -607,6 +614,7 @@ extern void target_del_all(void);
extern int iscsi_procfs_init(void);
extern void iscsi_procfs_exit(void);
#else
extern int conn_sysfs_add(struct iscsi_conn *conn);
extern const struct attribute *iscsi_attrs[];
extern int iscsi_add_attr(struct iscsi_target *target,
const struct iscsi_kern_attr *user_info);
@@ -829,4 +837,24 @@ static inline void iscsi_extracheck_is_rd_thread(struct iscsi_conn *conn) {}
static inline void iscsi_extracheck_is_wr_thread(struct iscsi_conn *conn) {}
#endif
extern int iscsi_conn_alloc(struct iscsi_session *session,
struct iscsi_kern_conn_info *info, struct iscsi_conn **new_conn,
struct iscsit_transport *t);
extern int conn_activate(struct iscsi_conn *conn);
extern void iscsi_tcp_mark_conn_closed(struct iscsi_conn *conn, int flags);
extern void iscsi_tcp_conn_free(struct iscsi_conn *conn);
extern void iscsi_cmnd_init(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd,
struct iscsi_cmnd *parent);
extern struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn);
extern void start_close_conn(struct iscsi_conn *conn);
extern __be32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn);
extern void iscsi_set_resid(struct iscsi_cmnd *rsp);
extern int iscsi_init_conn(struct iscsi_session *session,
struct iscsi_kern_conn_info *info, struct iscsi_conn *conn);
extern void req_cmnd_pre_release(struct iscsi_cmnd *req);
extern void req_cmnd_release(struct iscsi_cmnd *req);
extern struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req,
int status, const u8 *sense_buf, int sense_len);
extern int iscsi_cmnd_set_write_buf(struct iscsi_cmnd *req);
#endif /* __ISCSI_H__ */

View File

@@ -16,6 +16,10 @@
#ifndef ISCSI_DBG_H
#define ISCSI_DBG_H
#ifdef LOG_PREFIX
#undef LOG_PREFIX
#endif
#define LOG_PREFIX "iscsi-scst"
#ifdef INSIDE_KERNEL_TREE
@@ -53,8 +57,10 @@ extern unsigned long iscsi_get_flow_ctrl_or_mgmt_dbg_log_flag(
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
extern unsigned long iscsi_trace_flag;
#ifndef trace_flag
#define trace_flag iscsi_trace_flag
#endif
#endif
#define TRACE_CONN_CLOSE(args...) TRACE_DBG_FLAG(TRACE_DEBUG|TRACE_CONN_OC, args)
#define TRACE_CONN_CLOSE_DBG(args...) TRACE(TRACE_CONN_OC_DBG, args)

View File

@@ -23,6 +23,7 @@
#include "iscsi.h"
#include "digest.h"
#include "iscsit_transport.h"
/* Read data states */
enum rx_state {
@@ -407,10 +408,10 @@ static void close_conn(struct iscsi_conn *conn)
if (conn->active_close) {
/* We want all our already send operations to complete */
conn->sock->ops->shutdown(conn->sock, RCV_SHUTDOWN);
conn->transport->iscsit_conn_close(conn, RCV_SHUTDOWN);
} else {
conn->sock->ops->shutdown(conn->sock,
RCV_SHUTDOWN|SEND_SHUTDOWN);
conn->transport->iscsit_conn_close(conn,
RCV_SHUTDOWN|SEND_SHUTDOWN);
}
mutex_lock(&session->target->target_mutex);
@@ -486,15 +487,13 @@ static void close_conn(struct iscsi_conn *conn)
}
}
iscsi_make_conn_wr_active(conn);
conn->transport->iscsit_make_conn_wr_active(conn);
/* That's for active close only, actually */
if (time_after(jiffies, start_waiting + CONN_WAIT_TIMEOUT) &&
!wait_expired) {
TRACE_CONN_CLOSE("Wait time expired (conn %p, "
"sk_state %d)",
conn, conn->sock->sk->sk_state);
conn->sock->ops->shutdown(conn->sock, SEND_SHUTDOWN);
TRACE_CONN_CLOSE("Wait time expired (conn %p)", conn);
conn->transport->iscsit_conn_close(conn, SEND_SHUTDOWN);
wait_expired = 1;
shut_start_waiting = jiffies;
}
@@ -504,9 +503,8 @@ static void close_conn(struct iscsi_conn *conn)
conn->deleting ? CONN_DEL_SHUT_TIMEOUT :
CONN_REG_SHUT_TIMEOUT)) {
TRACE_CONN_CLOSE("Wait time after shutdown expired "
"(conn %p, sk_state %d)", conn,
conn->sock->sk->sk_state);
conn->sock->sk->sk_prot->disconnect(conn->sock->sk, 0);
"(conn %p)", conn);
conn->transport->iscsit_conn_close(conn, 0);
shut_expired = 1;
}
@@ -522,17 +520,21 @@ static void close_conn(struct iscsi_conn *conn)
trace_conn_close(conn);
/* It might never be called for being closed conn */
__iscsi_write_space_ready(conn);
if (!conn->session->sess_params.rdma_extensions) {
/* It might never be called for being closed conn */
__iscsi_write_space_ready(conn);
iscsi_check_closewait(conn);
iscsi_check_closewait(conn);
}
}
write_lock_bh(&conn->sock->sk->sk_callback_lock);
conn->sock->sk->sk_state_change = conn->old_state_change;
conn->sock->sk->sk_data_ready = conn->old_data_ready;
conn->sock->sk->sk_write_space = conn->old_write_space;
write_unlock_bh(&conn->sock->sk->sk_callback_lock);
if (!conn->session->sess_params.rdma_extensions) {
write_lock_bh(&conn->sock->sk->sk_callback_lock);
conn->sock->sk->sk_state_change = conn->old_state_change;
conn->sock->sk->sk_data_ready = conn->old_data_ready;
conn->sock->sk->sk_write_space = conn->old_write_space;
write_unlock_bh(&conn->sock->sk->sk_callback_lock);
}
while (1) {
bool t;
@@ -595,7 +597,7 @@ static int close_conn_thr(void *arg)
}
/* No locks */
static void start_close_conn(struct iscsi_conn *conn)
void start_close_conn(struct iscsi_conn *conn)
{
struct task_struct *t;
@@ -611,6 +613,7 @@ static void start_close_conn(struct iscsi_conn *conn)
TRACE_EXIT();
return;
}
EXPORT_SYMBOL(start_close_conn);
static inline void iscsi_conn_init_read(struct iscsi_conn *conn,
void __user *data, size_t len)
@@ -635,7 +638,7 @@ static void iscsi_conn_prepare_read_ahs(struct iscsi_conn *conn,
return;
}
static struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn)
struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn)
{
struct iscsi_cmnd *cmnd = NULL;
@@ -674,6 +677,7 @@ static struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn)
out:
return cmnd;
}
EXPORT_SYMBOL(iscsi_get_send_cmnd);
/* Returns number of bytes left to receive or <0 for error */
static int do_recv(struct iscsi_conn *conn)
@@ -831,7 +835,7 @@ static int process_read_io(struct iscsi_conn *conn, int *closed)
switch (conn->read_state) {
case RX_INIT_BHS:
EXTRACHECKS_BUG_ON(conn->read_cmnd != NULL);
cmnd = cmnd_alloc(conn, NULL);
cmnd = conn->transport->iscsit_alloc_cmd(conn, NULL);
conn->read_cmnd = cmnd;
iscsi_conn_init_read(cmnd->conn,
(void __force __user *)&cmnd->pdu.bhs,

View File

@@ -98,12 +98,13 @@ static void log_params(struct iscsi_sess_params *params)
iscsi_get_bool_value(params->data_sequence_inorder),
params->error_recovery_level);
PRINT_INFO(" HeaderDigest %s, DataDigest %s, OFMarker %s, "
"IFMarker %s, OFMarkInt %d, IFMarkInt %d",
"IFMarker %s, OFMarkInt %d, IFMarkInt %d, RDMAExtensions %s",
iscsi_get_digest_name(params->header_digest, hdigest_name),
iscsi_get_digest_name(params->data_digest, ddigest_name),
iscsi_get_bool_value(params->ofmarker),
iscsi_get_bool_value(params->ifmarker),
params->ofmarkint, params->ifmarkint);
params->ofmarkint, params->ifmarkint,
iscsi_get_bool_value(params->rdma_extensions));
}
/* target_mutex supposed to be locked */
@@ -135,6 +136,11 @@ static void sess_params_check(struct iscsi_kern_params_info *info)
CHECK_PARAM(info, iparams, ofmarker, 0, 0);
CHECK_PARAM(info, iparams, ifmarker, 0, 0);
/* iSER related parameters */
CHECK_PARAM(info, iparams, rdma_extensions, 0, 1);
CHECK_PARAM(info, iparams, target_recv_data_length, 512, max_len);
CHECK_PARAM(info, iparams, initiator_recv_data_length, 512, max_len);
return;
}
@@ -163,6 +169,11 @@ static void sess_params_set(struct iscsi_sess_params *params,
SET_PARAM(params, info, iparams, ifmarker);
SET_PARAM(params, info, iparams, ofmarkint);
SET_PARAM(params, info, iparams, ifmarkint);
/* iSER related parameters */
SET_PARAM(params, info, iparams, rdma_extensions);
SET_PARAM(params, info, iparams, target_recv_data_length);
SET_PARAM(params, info, iparams, initiator_recv_data_length);
return;
}
@@ -190,6 +201,11 @@ static void sess_params_get(struct iscsi_sess_params *params,
GET_PARAM(params, info, iparams, ifmarker);
GET_PARAM(params, info, iparams, ofmarkint);
GET_PARAM(params, info, iparams, ifmarkint);
/* iSER related parameters */
GET_PARAM(params, info, iparams, rdma_extensions);
GET_PARAM(params, info, iparams, target_recv_data_length);
GET_PARAM(params, info, iparams, initiator_recv_data_length);
return;
}

View File

@@ -331,9 +331,11 @@ void target_del_all_sess(struct iscsi_target *target, int flags)
TRACE_EXIT();
return;
}
EXPORT_SYMBOL(target_del_all_sess);
void target_del_all(void)
{
struct iscsit_transport *transport;
struct iscsi_target *target, *t;
bool first = true;
@@ -341,6 +343,14 @@ void target_del_all(void)
TRACE_MGMT_DBG("%s", "Deleting all targets");
transport = iscsit_get_transport(ISCSI_TCP);
if (transport && transport->iscsit_close_all_portals)
transport->iscsit_close_all_portals();
transport = iscsit_get_transport(ISCSI_RDMA);
if (transport && transport->iscsit_close_all_portals)
transport->iscsit_close_all_portals();
/* Not the best, ToDo */
while (1) {
mutex_lock(&target_mgmt_mutex);

View File

@@ -27,59 +27,17 @@
#include "iscsid.h"
#define CTL_DEVICE "/dev/iscsi-scst-ctl"
#define CTL_DEVICE "iscsi-scst-ctl"
int kernel_open(void)
{
FILE *f;
char devname[256];
char buf[256];
int devn;
int ctlfd = -1;
int err;
struct iscsi_kern_register_info reg;
if (!(f = fopen("/proc/devices", "r"))) {
err = -errno;
perror("Cannot open control path to the driver");
goto out_err;
}
devn = 0;
while (!feof(f)) {
if (!fgets(buf, sizeof(buf), f)) {
break;
}
if (sscanf(buf, "%d %s", &devn, devname) != 2) {
continue;
}
if (!strcmp(devname, "iscsi-scst-ctl")) {
break;
}
devn = 0;
}
fclose(f);
if (!devn) {
err = -ENOENT;
printf("cannot find iscsictl in /proc/devices - "
"make sure the module is loaded\n");
goto out_err;
}
unlink(CTL_DEVICE);
if (mknod(CTL_DEVICE, (S_IFCHR | 0600), (devn << 8))) {
err = -errno;
printf("cannot create %s %s\n", CTL_DEVICE, strerror(errno));
goto out_err;
}
ctlfd = open(CTL_DEVICE, O_RDWR);
if (ctlfd < 0) {
err = -errno;
printf("cannot open %s %s\n", CTL_DEVICE, strerror(errno));
goto out_err;
}
ctlfd = create_and_open_dev(CTL_DEVICE, 0);
if (ctlfd < 0)
goto out;
memset(&reg, 0, sizeof(reg));
reg.version = (uintptr_t)ISCSI_SCST_INTERFACE_VERSION;
@@ -103,7 +61,6 @@ out:
out_close:
close(ctlfd);
out_err:
ctlfd = err;
goto out;
}

View File

@@ -30,6 +30,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -169,6 +170,224 @@ static void create_listen_socket(struct pollfd *array)
exit(1);
}
static struct connection *alloc_and_init_conn(int fd)
{
struct pollfd *pollfd;
struct connection *conn = NULL;
int i;
for (i = 0; i < INCOMING_MAX; i++) {
if (!incoming[i])
break;
}
if (i >= INCOMING_MAX) {
log_error("Unable to find incoming slot? %d\n", i);
goto out;
}
conn = conn_alloc();
if (!conn) {
log_error("Fail to allocate %s", "conn\n");
goto out;
}
conn->fd = fd;
incoming[i] = conn;
pollfd = &poll_array[POLL_INCOMING + i];
pollfd->fd = fd;
pollfd->events = POLLIN;
pollfd->revents = 0;
conn_read_pdu(conn);
set_non_blocking(fd);
out:
return conn;
}
static int transmit_iser(int fd, bool start)
{
int opt = start;
return ioctl(fd, RDMA_CORK, &opt, sizeof(opt));
}
static int cork_transmit_iser(int fd)
{
return transmit_iser(fd, true);
}
static int uncork_transmit_iser(int fd)
{
return transmit_iser(fd, false);
}
static void create_iser_listen_socket(struct pollfd *array)
{
struct addrinfo hints, *res, *res0;
char servname[64];
int rc, i;
int iser_fd;
struct isert_addr_info info;
iser_fd = create_and_open_dev("isert_scst", 1);
poll_array[POLL_ISER_LISTEN].fd = iser_fd;
if (iser_fd != -1) {
poll_array[POLL_ISER_LISTEN].events = POLLIN;
/* RDMAExtensions */
session_keys[key_rdma_extensions].max = 1;
session_keys[key_rdma_extensions].local_def = 1;
} else {
poll_array[POLL_ISER_LISTEN].events = 0;
return;
}
memset(servname, 0, sizeof(servname));
snprintf(servname, sizeof(servname), "%d", server_port);
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
rc = getaddrinfo(server_address, servname, &hints, &res0);
if (rc != 0) {
log_error("Unable to get address info (%s)!",
get_error_str(rc));
exit(1);
}
i = 0;
for (res = res0; res && i < ISERT_MAX_PORTALS; res = res->ai_next) {
memcpy(&info.addr, res->ai_addr, res->ai_addrlen);
info.addr_len = res->ai_addrlen;
rc = ioctl(iser_fd, SET_LISTEN_ADDR, &info);
if (rc != 0) {
log_error("Unable to set address info (%s)!",
strerror(rc));
}
++i;
}
freeaddrinfo(res0);
}
static int iser_getsockname(int fd, struct sockaddr *name, socklen_t *namelen)
{
struct isert_addr_info addr;
int ret;
ret = ioctl(fd, GET_PORTAL_ADDR, &addr, sizeof(addr));
if (ret)
return ret;
memcpy(name, &addr.addr, addr.addr_len);
*namelen = addr.addr_len;
return ret;
}
static int iser_is_discovery(int fd)
{
int val = 1;
return ioctl(fd, DISCOVERY_SESSION, &val, sizeof(val));
}
static void iser_accept(int fd)
{
char buff[256];
int ret, conn_fd;
struct connection *conn;
char target_portal[ISCSI_PORTAL_LEN], target_portal_port[NI_MAXSERV];
struct isert_addr_info addr;
ret = read(fd, buff, sizeof(buff));
if (ret == -1)
goto out;
conn_fd = open(buff, O_RDWR);
if (conn_fd == -1) {
log_error("open(iser_connection) %s failed: %s\n",
buff, strerror(errno));
goto out;
}
ret = ioctl(conn_fd, GET_PORTAL_ADDR, &addr, sizeof(addr));
if (ret) {
log_error("ioctl(GET_PORTAL_ADDR) failed: %s\n",
strerror(errno));
goto out_close;
}
ret = getnameinfo((struct sockaddr *)&addr, sizeof(addr), target_portal,
sizeof(target_portal), target_portal_port,
sizeof(target_portal_port),
NI_NUMERICHOST | NI_NUMERICSERV);
if (ret != 0) {
log_error("Target portal getnameinfo() failed: %s!",
get_error_str(ret));
goto out_close;
}
log_info("iSER Connect to %s:%s", target_portal, target_portal_port);
if (conn_blocked) {
log_warning("Connection refused due to blocking\n");
goto out_close;
}
conn = alloc_and_init_conn(conn_fd);
if (!conn)
goto out_close;
conn->target_portal = strdup(target_portal);
if (conn->target_portal == NULL) {
log_error("Unable to duplicate target portal %s", target_portal);
goto out_free;
}
conn->cork_transmit = cork_transmit_iser;
conn->uncork_transmit = uncork_transmit_iser;
conn->getsockname = iser_getsockname;
conn->is_discovery = iser_is_discovery;
conn->is_iser = true;
incoming_cnt++;
out:
return;
out_free:
conn_free(conn);
out_close:
close(conn_fd);
goto out;
}
static int transmit_sock(int fd, bool start)
{
int opt = start;
return setsockopt(fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt));
}
static int cork_transmit_sock(int fd)
{
return transmit_sock(fd, true);
}
static int uncork_transmit_sock(int fd)
{
return transmit_sock(fd, false);
}
static int tcp_is_discovery(int fd)
{
return 0;
}
static void accept_connection(int listen)
{
union {
@@ -177,9 +396,8 @@ static void accept_connection(int listen)
struct sockaddr_in6 sin6;
} from, to;
socklen_t namesize;
struct pollfd *pollfd;
struct connection *conn;
int fd, i, rc;
int fd, rc;
char initiator_addr[ISCSI_PORTAL_LEN], initiator_port[NI_MAXSERV];
char target_portal[ISCSI_PORTAL_LEN], target_portal_port[NI_MAXSERV];
@@ -238,36 +456,22 @@ static void accept_connection(int listen)
goto out_close;
}
for (i = 0; i < INCOMING_MAX; i++) {
if (!incoming[i])
break;
}
if (i >= INCOMING_MAX) {
log_error("Unable to find incoming slot? %d\n", i);
conn = alloc_and_init_conn(fd);
if (!conn)
goto out_close;
}
if (!(conn = conn_alloc())) {
log_error("Fail to allocate %s", "conn\n");
goto out_close;
}
conn->fd = fd;
conn->target_portal = strdup(target_portal);
if (conn->target_portal == NULL) {
log_error("Unable to duplicate target portal %s", target_portal);
goto out_free;
}
incoming[i] = conn;
conn->cork_transmit = cork_transmit_sock;
conn->uncork_transmit = uncork_transmit_sock;
conn->getsockname = getsockname;
conn->is_discovery = tcp_is_discovery;
conn_read_pdu(conn);
set_non_blocking(fd);
pollfd = &poll_array[POLL_INCOMING + i];
pollfd->fd = fd;
pollfd->events = POLLIN;
pollfd->revents = 0;
incoming_cnt++;
out:
@@ -296,7 +500,7 @@ void isns_set_fd(int isns, int scn_listen, int scn)
static void event_conn(struct connection *conn, struct pollfd *pollfd)
{
int res, opt;
int res;
again:
switch (conn->iostate) {
@@ -367,8 +571,7 @@ again:
case IOSTATE_WRITE_AHS:
case IOSTATE_WRITE_DATA:
write_again:
opt = 1;
setsockopt(pollfd->fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt));
conn->cork_transmit(pollfd->fd);
res = write(pollfd->fd, conn->buffer, conn->rwsize);
if (res < 0) {
if (errno != EINTR && errno != EAGAIN) {
@@ -408,8 +611,7 @@ again:
goto write_again;
}
case IOSTATE_WRITE_DATA:
opt = 0;
setsockopt(pollfd->fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt));
conn->uncork_transmit(pollfd->fd);
cmnd_finish(conn);
switch (conn->state) {
@@ -447,6 +649,7 @@ static void event_loop(void)
int res, i;
create_listen_socket(poll_array + POLL_LISTEN);
create_iser_listen_socket(poll_array);
poll_array[POLL_IPC].fd = ipc_fd;
poll_array[POLL_IPC].events = POLLIN;
@@ -520,6 +723,9 @@ static void event_loop(void)
if (poll_array[POLL_SCN].revents)
isns_scn_handle(0);
if (poll_array[POLL_ISER_LISTEN].revents)
iser_accept(poll_array[POLL_ISER_LISTEN].fd);
for (i = 0; i < INCOMING_MAX; i++) {
struct connection *conn = incoming[i];
struct pollfd *pollfd = &poll_array[POLL_INCOMING + i];

View File

@@ -41,6 +41,10 @@ static struct iscsi_key login_keys[] = {
{"InitiatorAlias",},
{"SessionType",},
{"TargetName",},
{"InitiatorRecvDataSegmentLength",},
{"MaxAHSLength",},
{"TaggedBufferForSolicitedDataOnly",},
{"iSERHelloRequired",},
{NULL,},
};
@@ -369,6 +373,26 @@ static void text_scan_login(struct connection *conn)
}
}
if (conn->is_iser) {
switch (idx) {
case key_rdma_extensions:
if (val != 1) {
login_rsp_ini_err(conn, ISCSI_STATUS_INIT_ERR);
goto out;
}
break;
case key_initial_r2t:
val = 1;
break;
case key_immediate_data:
val = 0;
break;
}
} else if (idx == key_rdma_extensions && val != 0) {
login_rsp_ini_err(conn, ISCSI_STATUS_INIT_ERR);
goto out;
}
params_check_val(session_keys, idx, &val);
params_set_val(session_keys, conn->session_params, idx, &val);
@@ -502,6 +526,11 @@ static void login_start(struct connection *conn)
if (session_type) {
if (!strcmp(session_type, "Discovery")) {
int ret = conn->is_discovery(conn->fd);
if (ret) {
login_rsp_tgt_err(conn, ISCSI_STATUS_MISSING_FIELDS);
return;
}
conn->session_type = SESSION_DISCOVERY;
} else if (strcmp(session_type, "Normal")) {
login_rsp_ini_err(conn, ISCSI_STATUS_INV_SESSION_TYPE);
@@ -613,6 +642,15 @@ static int login_finish(struct connection *conn)
{
int res = 0;
if (conn->is_iser &&
conn->session_params[key_target_recv_data_length].key_state == KEY_STATE_START) {
char buf[32] = "\0";
params_val_to_str(session_keys, key_target_recv_data_length,
session_keys[key_target_recv_data_length].local_def,
buf, sizeof(buf));
text_key_add(conn, "TargetRecvDataSegmentLength", buf);
}
switch (conn->session_type) {
case SESSION_NORMAL:
if (!conn->sess)

View File

@@ -27,8 +27,10 @@
#include "types.h"
#ifdef INSIDE_KERNEL_TREE
#include <scst/iscsi_scst.h>
#include <scst/isert_scst.h>
#else
#include "iscsi_scst.h"
#include "isert_scst.h"
#endif
#include "iscsi_hdr.h"
#include "param.h"
@@ -126,6 +128,13 @@ struct connection {
} auth;
struct __qelem clist;
bool is_iser;
int (*cork_transmit)(int fd);
int (*uncork_transmit)(int fd);
int (*getsockname)(int fd, struct sockaddr *name, socklen_t *namelen);
int (*is_discovery)(int fd);
};
#define IOSTATE_FREE 0
@@ -221,6 +230,7 @@ extern int conn_blocked;
enum {
POLL_LISTEN,
POLL_IPC = POLL_LISTEN + LISTEN_MAX,
POLL_ISER_LISTEN,
POLL_NL,
POLL_ISNS,
POLL_SCN_LISTEN,

View File

@@ -18,9 +18,74 @@
#include <netinet/tcp.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "iscsid.h"
int create_and_open_dev(const char *dev, int readonly)
{
FILE *f;
char devname[256];
char buf[256];
int devn;
int ctlfd = -1;
int err;
int flags;
f = fopen("/proc/devices", "r");
if (!f) {
err = -errno;
perror("Cannot open control path to the driver");
goto out;
}
devn = 0;
while (!feof(f)) {
if (!fgets(buf, sizeof(buf), f))
break;
if (sscanf(buf, "%d %s", &devn, devname) != 2)
continue;
if (!strcmp(devname, dev))
break;
devn = 0;
}
fclose(f);
if (!devn) {
err = -ENOENT;
printf("cannot find %s in /proc/devices - "
"make sure the module is loaded\n", dev);
goto out;
}
sprintf(devname, "/dev/%s", dev);
unlink(devname);
if (mknod(devname, (S_IFCHR | 0600), (devn << 8))) {
err = -errno;
printf("cannot create %s %s\n", devname, strerror(errno));
goto out;
}
if (readonly)
flags = O_RDONLY;
else
flags = O_RDWR;
err = ctlfd = open(devname, flags);
if (ctlfd < 0) {
err = -errno;
printf("cannot open %s %s\n", devname, strerror(errno));
goto out;
}
out:
return err;
}
void set_non_blocking(int fd)
{
int res = fcntl(fd, F_GETFL);

View File

@@ -107,5 +107,6 @@ static inline int list_length_is_one(const struct __qelem *head)
extern void set_non_blocking(int fd);
extern void sock_set_keepalive(int sock, int timeout);
extern int create_and_open_dev(const char *dev, int readonly);
#endif

View File

@@ -382,5 +382,13 @@ struct iscsi_key session_keys[] = {
{"IFMarker", 0, 0, 0, 0, 0, &and_ops},
{"OFMarkInt", 2048, 2048, 1, 65535, 0, &marker_ops},
{"IFMarkInt", 2048, 2048, 1, 65535, 0, &marker_ops},
{"RDMAExtensions", 0, 0, 0, 0, 1, &and_ops},
{"TargetRecvDataSegmentLength", 8192, 512, 512, -1, 0, &minimum_ops},
{"InitiatorRecvDataSegmentLength", 8192, -1, 512, -1, 0, &minimum_ops},
{"MaxAHSLength", 256, 0, 0, -1, 0, &minimum_ops},
{"TaggedBufferForSolicitedDataOnly", 0, 0, 0, 0, 0, &and_ops},
{"iSERHelloRequired", 0, 0, 0, 0, 0, &and_ops},
{"MaxOutstandingUnexpectedPDUs", 0, 0, 0, -1, 0, &minimum_ops},
{NULL,},
};

View File

@@ -238,10 +238,11 @@ void target_list_build(struct connection *conn, char *target_name)
char portal[NI_MAXHOST];
int family, i;
if (getsockname(conn->fd, (struct sockaddr *) &ss1, &slen)) {
if (conn->getsockname(conn->fd, (struct sockaddr *) &ss1, &slen)) {
log_error("getsockname failed: %m");
return;
}
family = ss1.ss_family;
list_for_each_entry(target, &targets_list, tlist) {

View File

@@ -102,6 +102,7 @@ find /lib/modules/%{kver} -name ib_srpt.ko -exec rm {} \;
/lib/modules/%{kver}/extra/fcst.ko
/lib/modules/%{kver}/extra/ib_srpt.ko
/lib/modules/%{kver}/extra/iscsi-scst.ko
/lib/modules/%{kver}/extra/isert-scst.ko
/lib/modules/%{kver}/extra/qla2x00tgt.ko
/lib/modules/%{kver}/extra/qla2xxx_scst.ko
/lib/modules/%{kver}/extra/scst.ko

View File

@@ -159,6 +159,7 @@ parse_scst_conf() {
x86_64|i686)
SCST_OPT_MODULES="crc32c-intel $SCST_OPT_MODULES";;
esac
SCST_MODULES="$SCST_MODULES isert_scst"
SCST_OPT_MODULES="crc32c $SCST_OPT_MODULES"
SCST_DAEMONS="${ISCSI_DAEMON} $SCST_DAEMONS"
fi