summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Leech <cleech@redhat.com>2018-01-16 16:41:31 -0800
committerChris Leech <cleech@redhat.com>2018-01-16 17:02:52 -0800
commite3750e4a38d6e6a3b3e699dad990dee1103f5a68 (patch)
treee1ec0ffeefb82ef0c7e419ab9b1f78560d56652f
parentc6ae303c2cdd34157dfc3a6dface0a7179e0d401 (diff)
downloadopen-iscsi-e3750e4a38d6e6a3b3e699dad990dee1103f5a68.tar.gz
delete old kernel code
The out of tree kernel code in this repo has not been maintained for a very long time. We're only maintaining the user-space tools here, the kernel side is in the Linux kernel.
-rw-r--r--Makefile15
-rw-r--r--kernel/.gitignore11
-rw-r--r--kernel/2.6.14-19_compat.patch1247
-rw-r--r--kernel/2.6.14-23_compat.patch1468
-rw-r--r--kernel/2.6.16-suse.patch864
-rw-r--r--kernel/2.6.20-21_compat.patch1015
-rw-r--r--kernel/2.6.24_compat.patch1177
-rw-r--r--kernel/2.6.26_compat.patch681
-rw-r--r--kernel/2.6.27_compat.patch591
-rw-r--r--kernel/2.6.28-32_compat.patch569
-rw-r--r--kernel/2.6.33-34_compat.patch297
-rw-r--r--kernel/Makefile229
-rw-r--r--kernel/iscsi_tcp.c980
-rw-r--r--kernel/iscsi_tcp.h64
-rw-r--r--kernel/libiscsi.c3462
-rw-r--r--kernel/libiscsi.h450
-rw-r--r--kernel/libiscsi_tcp.c1184
-rw-r--r--kernel/libiscsi_tcp.h133
-rw-r--r--kernel/scsi_transport_iscsi.c2135
-rw-r--r--kernel/scsi_transport_iscsi.h259
20 files changed, 1 insertions, 16830 deletions
diff --git a/Makefile b/Makefile
index c8cd00e..9d56a10 100644
--- a/Makefile
+++ b/Makefile
@@ -59,15 +59,6 @@ iscsiuio/Makefile: iscsiuio/configure iscsiuio/Makefile.in
iscsiuio/configure iscsiuio/Makefile.in: iscsiuio/configure.ac iscsiuio/Makefile.am
cd iscsiuio; autoreconf --install
-kernel: force
- $(MAKE) -C kernel
- @echo "Kernel Compilation complete Output file"
- @echo "----------------------------------- ----------------"
- @echo "Built iSCSI Open Interface module: kernel/scsi_transport_iscsi.ko"
- @echo "Built iSCSI library module: kernel/libiscsi.ko"
- @echo "Built iSCSI over TCP library module: kernel/libiscsi_tcp.ko"
- @echo "Built iSCSI over TCP kernel module: kernel/iscsi_tcp.ko"
-
force: ;
clean:
@@ -75,7 +66,6 @@ clean:
$(MAKE) -C utils/fwparam_ibft clean
$(MAKE) -C utils clean
$(MAKE) -C usr clean
- $(MAKE) -C kernel clean
[ ! -f iscsiuio/Makefile ] || $(MAKE) -C iscsiuio clean
[ ! -f iscsiuio/Makefile ] || $(MAKE) -C iscsiuio distclean
@@ -84,7 +74,7 @@ clean:
# note that make may still execute the blocks in parallel
.NOTPARALLEL: install_user install_programs install_initd \
install_initd_suse install_initd_redhat install_initd_debian \
- install_etc install_iface install_doc install_kernel install_iname
+ install_etc install_iface install_doc install_iname
install: install_programs install_doc install_etc \
install_initd install_iname install_iface
@@ -139,9 +129,6 @@ install_doc: $(MANPAGES)
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
$(INSTALL) -m 644 $^ $(DESTDIR)$(mandir)/man8
-install_kernel:
- $(MAKE) -C kernel install_kernel
-
install_iname:
if [ ! -f $(DESTDIR)/etc/iscsi/initiatorname.iscsi ]; then \
echo "InitiatorName=`$(DESTDIR)/sbin/iscsi-iname`" > $(DESTDIR)/etc/iscsi/initiatorname.iscsi ; \
diff --git a/kernel/.gitignore b/kernel/.gitignore
deleted file mode 100644
index 0b2be3c..0000000
--- a/kernel/.gitignore
+++ /dev/null
@@ -1,11 +0,0 @@
-.*.ko.cmd
-.*.o.cmd
-.tmp_versions
-Module.symvers
-cur_patched
-has_*_patch
-*.ko
-*.mod.*
-open_iscsi_compat.h
-*.orig
-Module.markers
diff --git a/kernel/2.6.14-19_compat.patch b/kernel/2.6.14-19_compat.patch
deleted file mode 100644
index 67f4f74..0000000
--- a/kernel/2.6.14-19_compat.patch
+++ /dev/null
@@ -1,1247 +0,0 @@
-diff --git a/iscsi_tcp.c b/iscsi_tcp.c
-index 8ef3f41..14c6706 100644
---- a/iscsi_tcp.c
-+++ b/iscsi_tcp.c
-@@ -445,11 +445,9 @@ static int iscsi_sw_tcp_pdu_init(struct iscsi_task *task,
- if (!task->sc)
- iscsi_sw_tcp_send_linear_data_prep(conn, task->data, count);
- else {
-- struct scsi_data_buffer *sdb = scsi_out(task->sc);
--
-- err = iscsi_sw_tcp_send_data_prep(conn, sdb->table.sgl,
-- sdb->table.nents, offset,
-- count);
-+ err = iscsi_sw_tcp_send_data_prep(conn, scsi_sglist(task->sc),
-+ scsi_sg_count(task->sc),
-+ offset, count);
- }
-
- if (err) {
-@@ -782,7 +780,11 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
- shost->max_lun = iscsi_max_lun;
- shost->max_id = 0;
- shost->max_channel = 0;
-+#ifndef SCSI_MAX_VARLEN_CDB_SIZE
-+ shost->max_cmd_len = 16;
-+#else
- shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE;
-+#endif
-
- if (iscsi_host_add(shost, NULL))
- goto free_host;
-@@ -830,6 +832,9 @@ static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev)
- }
-
- static struct scsi_host_template iscsi_sw_tcp_sht = {
-+#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,24)
-+ .use_sg_chaining = ENABLE_SG_CHAINING,
-+#endif
- .module = THIS_MODULE,
- .name = "iSCSI Initiator over TCP/IP",
- .queuecommand = iscsi_queuecommand,
-@@ -840,7 +845,7 @@ static struct scsi_host_template iscsi_sw_tcp_sht = {
- .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
- .eh_abort_handler = iscsi_eh_abort,
- .eh_device_reset_handler= iscsi_eh_device_reset,
-- .eh_target_reset_handler= iscsi_eh_target_reset,
-+ .eh_host_reset_handler = iscsi_eh_target_reset,
- .use_clustering = DISABLE_CLUSTERING,
- .slave_configure = iscsi_sw_tcp_slave_configure,
- .proc_name = "iscsi_tcp",
-diff --git a/iscsi_tcp.h b/iscsi_tcp.h
-index f9a4044..ab20530 100644
---- a/iscsi_tcp.h
-+++ b/iscsi_tcp.h
-@@ -22,6 +22,8 @@
- #ifndef ISCSI_SW_TCP_H
- #define ISCSI_SW_TCP_H
-
-+#include "open_iscsi_compat.h"
-+
- #include "libiscsi.h"
- #include "libiscsi_tcp.h"
-
-diff --git a/libiscsi.c b/libiscsi.c
-index 457ecfe..756b171 100644
---- a/libiscsi.c
-+++ b/libiscsi.c
-@@ -24,7 +24,10 @@
- #include <linux/types.h>
- #include <linux/kfifo.h>
- #include <linux/delay.h>
-+#include <linux/version.h>
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
- #include <linux/log2.h>
-+#endif
- #include <asm/unaligned.h>
- #include <net/tcp.h>
- #include <scsi/scsi_cmnd.h>
-@@ -38,6 +41,8 @@
- #include "scsi_transport_iscsi.h"
- #include "libiscsi.h"
-
-+#include "open_iscsi_compat.h"
-+
- /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
- #define SNA32_CHECK 2147483648UL
-
-@@ -199,7 +204,7 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
- sizeof(rlen_ahdr->reserved));
- rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
- rlen_ahdr->reserved = 0;
-- rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
-+ rlen_ahdr->read_length = cpu_to_be32(scsi_bufflen(sc));
-
- debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
- "rlen_ahdr->ahslength(%d)\n",
-@@ -267,7 +272,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- return rc;
- }
- if (sc->sc_data_direction == DMA_TO_DEVICE) {
-- unsigned out_len = scsi_out(sc)->length;
-+ unsigned out_len = scsi_bufflen(sc);
- struct iscsi_r2t_info *r2t = &task->unsol_r2t;
-
- hdr->data_length = cpu_to_be32(out_len);
-@@ -313,7 +318,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- } else {
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- zero_data(hdr->dlength);
-- hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
-+ hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
-
- if (sc->sc_data_direction == DMA_FROM_DEVICE)
- hdr->flags |= ISCSI_FLAG_CMD_READ;
-@@ -340,7 +345,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ?
- "write" : "read", conn->id, sc, sc->cmnd[0], task->itt,
- scsi_bufflen(sc),
-- scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
-+ scsi_bidi_cmnd(sc) ? scsi_bufflen(sc) : 0,
- session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
- return 0;
- }
-@@ -432,12 +437,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
- conn->session->queued_cmdsn--;
-
- sc->result = err;
-- if (!scsi_bidi_cmnd(sc))
-- scsi_set_resid(sc, scsi_bufflen(sc));
-- else {
-- scsi_out(sc)->resid = scsi_out(sc)->length;
-- scsi_in(sc)->resid = scsi_in(sc)->length;
-- }
-+ scsi_set_resid(sc, scsi_bufflen(sc));
-
- if (conn->task == task)
- conn->task = NULL;
-@@ -631,7 +631,7 @@ invalid_datalen:
- goto out;
- }
-
-- senselen = get_unaligned_be16(data);
-+ senselen = be16_to_cpu(get_unaligned((__be16 *) data));
- if (datalen < senselen)
- goto invalid_datalen;
-
-@@ -647,8 +647,8 @@ invalid_datalen:
-
- if (scsi_bidi_cmnd(sc) && res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
-- res_count <= scsi_in(sc)->length))
-- scsi_in(sc)->resid = res_count;
-+ res_count <= scsi_bufflen(sc)))
-+ scsi_set_resid(sc, res_count);
- else
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- }
-@@ -697,8 +697,8 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
-
- if (res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
-- res_count <= scsi_in(sc)->length))
-- scsi_in(sc)->resid = res_count;
-+ res_count <= scsi_bufflen(sc)))
-+ scsi_set_resid(sc, res_count);
- else
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- }
-@@ -1244,10 +1244,9 @@ again:
- return rc;
- }
-
--static void iscsi_xmitworker(struct work_struct *work)
-+static void iscsi_xmitworker(void *data)
- {
-- struct iscsi_conn *conn =
-- container_of(work, struct iscsi_conn, xmitwork);
-+ struct iscsi_conn *conn = data;
- int rc;
- /*
- * serialize Xmit worker on a per-connection basis.
-@@ -1408,12 +1407,7 @@ prepd_fault:
- fault:
- spin_unlock(&session->lock);
- debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
-- if (!scsi_bidi_cmnd(sc))
-- scsi_set_resid(sc, scsi_bufflen(sc));
-- else {
-- scsi_out(sc)->resid = scsi_out(sc)->length;
-- scsi_in(sc)->resid = scsi_in(sc)->length;
-- }
-+ scsi_set_resid(sc, scsi_bufflen(sc));
- done(sc);
- spin_lock(host->host_lock);
- return 0;
-@@ -1998,8 +1992,10 @@ int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev)
- if (!shost->can_queue)
- shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX;
-
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
- if (!shost->transportt->eh_timed_out)
- shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
-+#endif
- return scsi_add_host(shost, pdev);
- }
- EXPORT_SYMBOL_GPL(iscsi_host_add);
-@@ -2295,7 +2291,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
- INIT_LIST_HEAD(&conn->mgmtqueue);
- INIT_LIST_HEAD(&conn->xmitqueue);
- INIT_LIST_HEAD(&conn->requeue);
-- INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
-+ INIT_WORK(&conn->xmitwork, iscsi_xmitworker, conn);
-
- /* allocate login_task used for the login/text sequences */
- spin_lock_bh(&session->lock);
-diff --git a/libiscsi.h b/libiscsi.h
-index a261e2c..1274bc9 100644
---- a/libiscsi.h
-+++ b/libiscsi.h
-@@ -25,13 +25,16 @@
-
- #include <linux/types.h>
- #include <linux/wait.h>
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
- #include <linux/mutex.h>
--#include <linux/timer.h>
--#include <linux/workqueue.h>
-+#endif
-+
- #include "iscsi_proto.h"
- #include "iscsi_if.h"
- #include "scsi_transport_iscsi.h"
-
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct scsi_host_template;
- struct scsi_device;
-diff --git a/libiscsi_tcp.c b/libiscsi_tcp.c
-index 92cb13d..ea7dd8d 100644
---- a/libiscsi_tcp.c
-+++ b/libiscsi_tcp.c
-@@ -357,6 +357,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment,
-
- debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
- offset, size);
-+
-+ /*
-+ * older kernels could send use_sg=0 for commands like sgio
-+ * or scsi-ml commands.
-+ */
-+ if (!sg_count) {
-+ iscsi_segment_init_linear(segment, (void *)sg_list + offset,
-+ size, done, hash);
-+ return 0;
-+ }
-+
- __iscsi_segment_init(segment, size, done, hash);
- for_each_sg(sg_list, sg, sg_count, i) {
- debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
-@@ -469,7 +480,7 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
- int datasn = be32_to_cpu(rhdr->datasn);
-- unsigned total_in_length = scsi_in(task->sc)->length;
-+ unsigned total_in_length = scsi_bufflen(task->sc);
-
- iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
- if (tcp_conn->in.datalen == 0)
-@@ -557,11 +568,11 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- r2t->data_length, session->max_burst);
-
- r2t->data_offset = be32_to_cpu(rhdr->data_offset);
-- if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
-+ if (r2t->data_offset + r2t->data_length > scsi_bufflen(task->sc)) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with data len %u at offset %u "
- "and total length %d\n", r2t->data_length,
-- r2t->data_offset, scsi_out(task->sc)->length);
-+ r2t->data_offset, scsi_bufflen(task->sc));
- __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
-@@ -660,7 +671,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- if (tcp_conn->in.datalen) {
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct hash_desc *rx_hash = NULL;
-- struct scsi_data_buffer *sdb = scsi_in(task->sc);
-
- /*
- * Setup copy of Data-In into the Scsi_Cmnd
-@@ -679,8 +689,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- tcp_task->data_offset,
- tcp_conn->in.datalen);
- rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
-- sdb->table.sgl,
-- sdb->table.nents,
-+ scsi_sglist(task->sc),
-+ scsi_sg_count(task->sc),
- tcp_task->data_offset,
- tcp_conn->in.datalen,
- iscsi_tcp_process_data_in,
-diff --git a/libiscsi_tcp.h b/libiscsi_tcp.h
-index 3bacef5..5ea284d 100644
---- a/libiscsi_tcp.h
-+++ b/libiscsi_tcp.h
-@@ -21,6 +21,7 @@
- #ifndef LIBISCSI_TCP_H
- #define LIBISCSI_TCP_H
-
-+#include "open_iscsi_compat.h"
- #include "libiscsi.h"
-
- struct iscsi_tcp_conn;
-diff --git a/open_iscsi_compat.h b/open_iscsi_compat.h
-new file mode 100644
-index 0000000..2dbe4ce
---- /dev/null
-+++ b/open_iscsi_compat.h
-@@ -0,0 +1,303 @@
-+#ifndef OPEN_ISCSI_COMPAT
-+#define OPEN_ISCSI_COMPAT
-+
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <scsi/scsi.h>
-+#include <scsi/scsi_cmnd.h>
-+
-+#ifndef SCAN_WILD_CARD
-+#define SCAN_WILD_CARD ~0
-+#endif
-+
-+#ifndef NIPQUAD_FMT
-+#define NIPQUAD_FMT "%u.%u.%u.%u"
-+#endif
-+
-+#ifndef NIP6_FMT
-+#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-+#endif
-+
-+#ifndef DEFINE_MUTEX
-+
-+/* mutex changes from 2.6.16-rc1 and up */
-+#define DEFINE_MUTEX DECLARE_MUTEX
-+#define mutex_lock down
-+#define mutex_unlock up
-+#define mutex semaphore
-+#define mutex_init init_MUTEX
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12)
-+
-+void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun)
-+{
-+ int i;
-+
-+ memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
-+
-+ for (i = 0; i < sizeof(lun); i += 2) {
-+ scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
-+ scsilun->scsi_lun[i+1] = lun & 0xFF;
-+ lun = lun >> 16;
-+ }
-+}
-+
-+#define __nlmsg_put(skb, daemon_pid, seq, type, len, flags) \
-+ __nlmsg_put(skb, daemon_pid, 0, 0, len)
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define gfp_t unsigned
-+
-+void *kzalloc(size_t size, gfp_t flags)
-+{
-+ void *ret = kmalloc(size, flags);
-+ if (ret)
-+ memset(ret, 0, size);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+
-+#include "linux/crypto.h"
-+
-+#define CRYPTO_ALG_ASYNC 0x00000080
-+struct hash_desc
-+{
-+ struct crypto_tfm *tfm;
-+ u32 flags;
-+};
-+
-+static inline int crypto_hash_init(struct hash_desc *desc)
-+{
-+ crypto_digest_init(desc->tfm);
-+ return 0;
-+}
-+
-+static inline int crypto_hash_digest(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes, u8 *out)
-+{
-+ crypto_digest_digest(desc->tfm, sg, 1, out);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_update(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes)
-+{
-+ crypto_digest_update(desc->tfm, sg, 1);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
-+{
-+ crypto_digest_final(desc->tfm, out);
-+ return 0;
-+}
-+
-+static inline struct crypto_tfm *crypto_alloc_hash(const char *alg_name,
-+ u32 type, u32 mask)
-+{
-+ struct crypto_tfm *ret = crypto_alloc_tfm(alg_name ,type);
-+ return ret ? ret : ERR_PTR(-ENOMEM);
-+}
-+
-+static inline void crypto_free_hash(struct crypto_tfm *tfm)
-+{
-+ crypto_free_tfm(tfm);
-+}
-+
-+int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 0);
-+}
-+
-+int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 1);
-+}
-+
-+#endif
-+
-+#ifndef bool
-+#define bool int
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
-+#ifdef RHEL_RELEASE_VERSION
-+#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,2)
-+static inline int is_power_of_2(unsigned long n)
-+{
-+ return (n != 0 && ((n & (n - 1)) == 0));
-+}
-+#endif
-+#else
-+/* not a redhat kernel */
-+static inline int is_power_of_2(unsigned long n)
-+{
-+ return (n != 0 && ((n & (n - 1)) == 0));
-+}
-+#endif
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
-+{
-+ return (struct nlmsghdr *)skb->data;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+#ifdef RHEL_RELEASE_VERSION
-+#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,2)
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+ return (void *)shost->hostdata;
-+}
-+#endif
-+#else
-+/* not a redhat kernel */
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+ return (void *)shost->hostdata;
-+}
-+#endif
-+
-+/*
-+ * Note: We do not support bidi for the compat modules if the kernel
-+ * does not have support.
-+ */
-+#define scsi_sg_count(cmd) ((cmd)->use_sg)
-+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
-+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
-+
-+#ifdef RHEL_RELEASE_VERSION
-+#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,2)
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+ cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+ return cmd->resid;
-+}
-+#endif
-+#else
-+/* not a redhat kernel */
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+ cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+ return cmd->resid;
-+}
-+#endif
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+static inline unsigned long rounddown_pow_of_two(unsigned long n)
-+{
-+ return 1UL << (fls_long(n) - 1);
-+}
-+
-+
-+static inline struct scatterlist *sg_next(struct scatterlist *sg)
-+{
-+ if (!sg) {
-+ BUG();
-+ return NULL;
-+ }
-+ return sg + 1;
-+}
-+
-+#define for_each_sg(sglist, sg, nr, __i) \
-+ for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
-+
-+#define sg_page(_sg) _sg->page
-+
-+static inline void sg_set_page(struct scatterlist *sg, struct page *page,
-+ unsigned int len, unsigned int offset)
-+{
-+ sg->page = page;
-+ sg->offset = offset;
-+ sg->length = len;
-+}
-+
-+static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
-+{
-+ memset(sgl, 0, sizeof(*sgl) * nents);
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
-+
-+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
-+{
-+ return 0;
-+}
-+
-+#define netlink_kernel_release(_nls) \
-+ sock_release(_nls->sk_socket)
-+
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, input)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#endif
-+
-+#ifndef DID_TRANSPORT_DISRUPTED
-+#define DID_TRANSPORT_DISRUPTED DID_BUS_BUSY
-+#endif
-+
-+#ifndef DID_TRANSPORT_FAILFAST
-+#define DID_TRANSPORT_FAILFAST DID_NO_CONNECT
-+#endif
-+
-+#ifndef SCSI_MLQUEUE_TARGET_BUSY
-+#define SCSI_MLQUEUE_TARGET_BUSY SCSI_MLQUEUE_HOST_BUSY
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)
-+
-+#define BLK_EH_NOT_HANDLED EH_NOT_HANDLED
-+#define BLK_EH_RESET_TIMER EH_RESET_TIMER
-+
-+#define blk_eh_timer_return scsi_eh_timer_return
-+
-+#endif
-+
-+#endif
-diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c
-index 4781d81..98d1351 100644
---- a/scsi_transport_iscsi.c
-+++ b/scsi_transport_iscsi.c
-@@ -21,7 +21,10 @@
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include <linux/module.h>
-+#include <linux/version.h>
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
- #include <linux/mutex.h>
-+#endif
- #include <net/tcp.h>
- #include <scsi/scsi.h>
- #include <scsi/scsi_host.h>
-@@ -41,13 +44,13 @@ struct iscsi_internal {
- struct scsi_transport_template t;
- struct iscsi_transport *iscsi_transport;
- struct list_head list;
-- struct device dev;
-+ struct class_device cdev;
-
-- struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
-+ struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
- struct transport_container conn_cont;
-- struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
-+ struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
- struct transport_container session_cont;
-- struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
-+ struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
- };
-
- static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
-@@ -64,12 +67,12 @@ static DEFINE_SPINLOCK(iscsi_transport_lock);
- #define to_iscsi_internal(tmpl) \
- container_of(tmpl, struct iscsi_internal, t)
-
--#define dev_to_iscsi_internal(_dev) \
-- container_of(_dev, struct iscsi_internal, dev)
-+#define cdev_to_iscsi_internal(_cdev) \
-+ container_of(_cdev, struct iscsi_internal, cdev)
-
--static void iscsi_transport_release(struct device *dev)
-+static void iscsi_transport_release(struct class_device *cdev)
- {
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- kfree(priv);
- }
-
-@@ -79,33 +82,31 @@ static void iscsi_transport_release(struct device *dev)
- */
- static struct class iscsi_transport_class = {
- .name = "iscsi_transport",
-- .dev_release = iscsi_transport_release,
-+ .release = iscsi_transport_release,
- };
-
- static ssize_t
--show_transport_handle(struct device *dev, struct device_attribute *attr,
-- char *buf)
-+show_transport_handle(struct class_device *cdev, char *buf)
- {
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
- }
--static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-+static CLASS_DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-
- #define show_transport_attr(name, format) \
- static ssize_t \
--show_transport_##name(struct device *dev, \
-- struct device_attribute *attr,char *buf) \
-+show_transport_##name(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev); \
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev); \
- return sprintf(buf, format"\n", priv->iscsi_transport->name); \
- } \
--static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-
- show_transport_attr(caps, "0x%x");
-
- static struct attribute *iscsi_transport_attrs[] = {
-- &dev_attr_handle.attr,
-- &dev_attr_caps.attr,
-+ &class_device_attr_handle.attr,
-+ &class_device_attr_caps.attr,
- NULL,
- };
-
-@@ -113,6 +114,7 @@ static struct attribute_group iscsi_transport_group = {
- .attrs = iscsi_transport_attrs,
- };
-
-+#if 0
- /*
- * iSCSI endpoint attrs
- */
-@@ -236,9 +238,10 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
- return ep;
- }
- EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
-+#endif
-
- static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
-- struct device *cdev)
-+ struct class_device *cdev)
- {
- struct Scsi_Host *shost = dev_to_shost(dev);
- struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -257,7 +260,7 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
- }
-
- static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
-- struct device *cdev)
-+ struct class_device *cdev)
- {
- struct Scsi_Host *shost = dev_to_shost(dev);
- struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -497,10 +500,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
- iscsi_user_scan_session);
- }
-
--static void iscsi_scan_session(struct work_struct *work)
-+static void iscsi_scan_session(void *data)
- {
-- struct iscsi_cls_session *session =
-- container_of(work, struct iscsi_cls_session, scan_work);
-+ struct iscsi_cls_session *session = data;
- struct Scsi_Host *shost = iscsi_session_to_shost(session);
- struct iscsi_cls_host *ihost = shost->shost_data;
- struct iscsi_scan_data scan_data;
-@@ -513,11 +515,9 @@ static void iscsi_scan_session(struct work_struct *work)
- atomic_dec(&ihost->nr_scans);
- }
-
--static void session_recovery_timedout(struct work_struct *work)
-+static void session_recovery_timedout(void *data)
- {
-- struct iscsi_cls_session *session =
-- container_of(work, struct iscsi_cls_session,
-- recovery_work.work);
-+ struct iscsi_cls_session *session = data;
- unsigned long flags;
-
- iscsi_cls_session_printk(KERN_INFO, session,
-@@ -543,11 +543,9 @@ static void session_recovery_timedout(struct work_struct *work)
- scsi_target_unblock(&session->dev);
- }
-
--static void __iscsi_unblock_session(struct work_struct *work)
-+static void __iscsi_unblock_session(void *data)
- {
-- struct iscsi_cls_session *session =
-- container_of(work, struct iscsi_cls_session,
-- unblock_work);
-+ struct iscsi_cls_session *session = data;
- struct Scsi_Host *shost = iscsi_session_to_shost(session);
- struct iscsi_cls_host *ihost = shost->shost_data;
- unsigned long flags;
-@@ -567,10 +565,12 @@ static void __iscsi_unblock_session(struct work_struct *work)
- * the async scanning code (drivers like iscsi_tcp do login and
- * scanning from userspace).
- */
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
- if (shost->hostt->scan_finished) {
- if (queue_work(ihost->scan_workq, &session->scan_work))
- atomic_inc(&ihost->nr_scans);
- }
-+#endif
- }
-
- /**
-@@ -590,11 +590,9 @@ void iscsi_unblock_session(struct iscsi_cls_session *session)
- }
- EXPORT_SYMBOL_GPL(iscsi_unblock_session);
-
--static void __iscsi_block_session(struct work_struct *work)
-+static void __iscsi_block_session(void *data)
- {
-- struct iscsi_cls_session *session =
-- container_of(work, struct iscsi_cls_session,
-- block_work);
-+ struct iscsi_cls_session *session = data;
- unsigned long flags;
-
- spin_lock_irqsave(&session->lock, flags);
-@@ -611,11 +609,9 @@ void iscsi_block_session(struct iscsi_cls_session *session)
- }
- EXPORT_SYMBOL_GPL(iscsi_block_session);
-
--static void __iscsi_unbind_session(struct work_struct *work)
-+static void __iscsi_unbind_session(void *data)
- {
-- struct iscsi_cls_session *session =
-- container_of(work, struct iscsi_cls_session,
-- unbind_work);
-+ struct iscsi_cls_session *session = data;
- struct Scsi_Host *shost = iscsi_session_to_shost(session);
- struct iscsi_cls_host *ihost = shost->shost_data;
- unsigned long flags;
-@@ -658,12 +654,12 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
- session->transport = transport;
- session->recovery_tmo = 120;
- session->state = ISCSI_SESSION_FREE;
-- INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
-+ INIT_WORK(&session->recovery_work, session_recovery_timedout, session);
- INIT_LIST_HEAD(&session->sess_list);
-- INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
-- INIT_WORK(&session->block_work, __iscsi_block_session);
-- INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
-- INIT_WORK(&session->scan_work, iscsi_scan_session);
-+ INIT_WORK(&session->unblock_work, __iscsi_unblock_session, session);
-+ INIT_WORK(&session->block_work, __iscsi_block_session, session);
-+ INIT_WORK(&session->unbind_work, __iscsi_unbind_session, session);
-+ INIT_WORK(&session->scan_work, iscsi_scan_session, session);
- spin_lock_init(&session->lock);
-
- /* this is released in the dev's release function */
-@@ -723,7 +719,8 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
- }
- session->target_id = id;
-
-- dev_set_name(&session->dev, "session%u", session->sid);
-+ snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
-+ session->sid);
- err = device_add(&session->dev);
- if (err) {
- iscsi_cls_session_printk(KERN_ERR, session,
-@@ -822,7 +819,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session)
- scsi_target_unblock(&session->dev);
- /* flush running scans then delete devices */
- flush_workqueue(ihost->scan_workq);
-- __iscsi_unbind_session(&session->unbind_work);
-+ __iscsi_unbind_session(session);
-
- /* hw iscsi may not have removed all connections from session */
- err = device_for_each_child(&session->dev, NULL,
-@@ -896,7 +893,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
- if (!get_device(&session->dev))
- goto free_conn;
-
-- dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid);
-+ snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
-+ session->sid, cid);
- conn->dev.parent = &session->dev;
- conn->dev.release = iscsi_conn_release;
- err = device_register(&conn->dev);
-@@ -1305,6 +1303,8 @@ static int
- iscsi_if_transport_ep(struct iscsi_transport *transport,
- struct iscsi_uevent *ev, int msg_type)
- {
-+ return -ENOSYS;
-+#if 0
- struct iscsi_endpoint *ep;
- struct sockaddr *dst_addr;
- int rc = 0;
-@@ -1345,6 +1345,8 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
- break;
- }
- return rc;
-+
-+#endif
- }
-
- static int
-@@ -1426,6 +1428,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- ev->u.c_session.queue_depth);
- break;
- case ISCSI_UEVENT_CREATE_BOUND_SESSION:
-+ err = -ENOSYS;
-+ break;
-+#if 0
- ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
- if (!ep) {
- err = -EINVAL;
-@@ -1437,6 +1442,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- ev->u.c_bound_session.cmds_max,
- ev->u.c_bound_session.queue_depth);
- break;
-+#endif
- case ISCSI_UEVENT_DESTROY_SESSION:
- session = iscsi_session_lookup(ev->u.d_session.sid);
- if (session)
-@@ -1519,55 +1525,70 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- }
-
- /*
-- * Get message from skb. Each message is processed by iscsi_if_recv_msg.
-- * Malformed skbs with wrong lengths or invalid creds are not processed.
-+ * Get message from skb (based on rtnetlink_rcv_skb). Each message is
-+ * processed by iscsi_if_recv_msg. Malformed skbs with wrong lengths or
-+ * invalid creds are discarded silently.
- */
- static void
--iscsi_if_rx(struct sk_buff *skb)
-+iscsi_if_rx(struct sock *sk, int len)
- {
-+ struct sk_buff *skb;
-+
- mutex_lock(&rx_queue_mutex);
-- while (skb->len >= NLMSG_SPACE(0)) {
-- int err;
-- uint32_t rlen;
-- struct nlmsghdr *nlh;
-- struct iscsi_uevent *ev;
--
-- nlh = nlmsg_hdr(skb);
-- if (nlh->nlmsg_len < sizeof(*nlh) ||
-- skb->len < nlh->nlmsg_len) {
-- break;
-+ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
-+ if (NETLINK_CREDS(skb)->uid) {
-+ skb_pull(skb, skb->len);
-+ goto free_skb;
- }
-
-- ev = NLMSG_DATA(nlh);
-- rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-- if (rlen > skb->len)
-- rlen = skb->len;
-+ while (skb->len >= NLMSG_SPACE(0)) {
-+ int err;
-+ uint32_t rlen;
-+ struct nlmsghdr *nlh;
-+ struct iscsi_uevent *ev;
-
-- err = iscsi_if_recv_msg(skb, nlh);
-- if (err) {
-- ev->type = ISCSI_KEVENT_IF_ERROR;
-- ev->iferror = err;
-- }
-- do {
-- /*
-- * special case for GET_STATS:
-- * on success - sending reply and stats from
-- * inside of if_recv_msg(),
-- * on error - fall through.
-- */
-- if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
-+ nlh = nlmsg_hdr(skb);
-+ if (nlh->nlmsg_len < sizeof(*nlh) ||
-+ skb->len < nlh->nlmsg_len) {
- break;
-- err = iscsi_if_send_reply(
-- NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
-- nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-- } while (err < 0 && err != -ECONNREFUSED);
-- skb_pull(skb, rlen);
-+ }
-+
-+ ev = NLMSG_DATA(nlh);
-+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-+ if (rlen > skb->len)
-+ rlen = skb->len;
-+
-+ err = iscsi_if_recv_msg(skb, nlh);
-+ if (err) {
-+ ev->type = ISCSI_KEVENT_IF_ERROR;
-+ ev->iferror = err;
-+ }
-+ do {
-+ /*
-+ * special case for GET_STATS:
-+ * on success - sending reply and stats from
-+ * inside of if_recv_msg(),
-+ * on error - fall through.
-+ */
-+ if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
-+ break;
-+ err = iscsi_if_send_reply(
-+ NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
-+ nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-+ } while (err < 0 && err != -ECONNREFUSED);
-+ skb_pull(skb, rlen);
-+ }
-+free_skb:
-+ kfree_skb(skb);
- }
- mutex_unlock(&rx_queue_mutex);
- }
-
-+#define iscsi_cdev_to_conn(_cdev) \
-+ iscsi_dev_to_conn(_cdev->dev)
-+
- #define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \
--struct device_attribute dev_attr_##_prefix##_##_name = \
-+struct class_device_attribute class_device_attr_##_prefix##_##_name = \
- __ATTR(_name,_mode,_show,_store)
-
- /*
-@@ -1575,10 +1596,9 @@ struct device_attribute dev_attr_##_prefix##_##_name = \
- */
- #define iscsi_conn_attr_show(param) \
- static ssize_t \
--show_conn_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_conn_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
-+ struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
- struct iscsi_transport *t = conn->transport; \
- return t->get_conn_param(conn, param, buf); \
- }
-@@ -1602,16 +1622,17 @@ iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
- iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
- iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
-
-+#define iscsi_cdev_to_session(_cdev) \
-+ iscsi_dev_to_session(_cdev->dev)
-+
- /*
- * iSCSI session attrs
- */
- #define iscsi_session_attr_show(param, perm) \
- static ssize_t \
--show_session_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_session_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_session *session = \
-- iscsi_dev_to_session(dev->parent); \
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
- struct iscsi_transport *t = session->transport; \
- \
- if (perm && !capable(CAP_SYS_ADMIN)) \
-@@ -1645,10 +1666,9 @@ iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
- iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
-
- static ssize_t
--show_priv_session_state(struct device *dev, struct device_attribute *attr,
-- char *buf)
-+show_priv_session_state(struct class_device *cdev, char *buf)
- {
-- struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);
- return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
- }
- static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-@@ -1656,11 +1676,9 @@ static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-
- #define iscsi_priv_session_attr_show(field, format) \
- static ssize_t \
--show_priv_session_##field(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_priv_session_##field(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_session *session = \
-- iscsi_dev_to_session(dev->parent); \
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\
- return sprintf(buf, format"\n", session->field); \
- }
-
-@@ -1675,10 +1693,9 @@ iscsi_priv_session_attr(recovery_tmo, "%d");
- */
- #define iscsi_host_attr_show(param) \
- static ssize_t \
--show_host_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_host_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct Scsi_Host *shost = transport_class_to_shost(dev); \
-+ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
- struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
- return priv->iscsi_transport->get_host_param(shost, param, buf); \
- }
-@@ -1695,7 +1712,7 @@ iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
-
- #define SETUP_PRIV_SESSION_RD_ATTR(field) \
- do { \
-- priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
-+ priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
- count++; \
- } while (0)
-
-@@ -1703,7 +1720,7 @@ do { \
- #define SETUP_SESSION_RD_ATTR(field, param_flag) \
- do { \
- if (tt->param_mask & param_flag) { \
-- priv->session_attrs[count] = &dev_attr_sess_##field; \
-+ priv->session_attrs[count] = &class_device_attr_sess_##field; \
- count++; \
- } \
- } while (0)
-@@ -1711,7 +1728,7 @@ do { \
- #define SETUP_CONN_RD_ATTR(field, param_flag) \
- do { \
- if (tt->param_mask & param_flag) { \
-- priv->conn_attrs[count] = &dev_attr_conn_##field; \
-+ priv->conn_attrs[count] = &class_device_attr_conn_##field; \
- count++; \
- } \
- } while (0)
-@@ -1719,7 +1736,7 @@ do { \
- #define SETUP_HOST_RD_ATTR(field, param_flag) \
- do { \
- if (tt->host_param_mask & param_flag) { \
-- priv->host_attrs[count] = &dev_attr_host_##field; \
-+ priv->host_attrs[count] = &class_device_attr_host_##field; \
- count++; \
- } \
- } while (0)
-@@ -1808,19 +1825,21 @@ iscsi_register_transport(struct iscsi_transport *tt)
- INIT_LIST_HEAD(&priv->list);
- priv->daemon_pid = -1;
- priv->iscsi_transport = tt;
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
- priv->t.user_scan = iscsi_user_scan;
-+#endif
- if (!(tt->caps & CAP_DATA_PATH_OFFLOAD))
- priv->t.create_work_queue = 1;
-
-- priv->dev.class = &iscsi_transport_class;
-- dev_set_name(&priv->dev, "%s", tt->name);
-- err = device_register(&priv->dev);
-+ priv->cdev.class = &iscsi_transport_class;
-+ snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
-+ err = class_device_register(&priv->cdev);
- if (err)
- goto free_priv;
-
-- err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
-+ err = sysfs_create_group(&priv->cdev.kobj, &iscsi_transport_group);
- if (err)
-- goto unregister_dev;
-+ goto unregister_cdev;
-
- /* host parameters */
- priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
-@@ -1899,9 +1918,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
- printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
- return &priv->t;
-
--unregister_dev:
-- device_unregister(&priv->dev);
-- return NULL;
-+unregister_cdev:
-+ class_device_unregister(&priv->cdev);
- free_priv:
- kfree(priv);
- return NULL;
-@@ -1928,8 +1946,8 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
- transport_container_unregister(&priv->session_cont);
- transport_container_unregister(&priv->t.host_attrs);
-
-- sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
-- device_unregister(&priv->dev);
-+ sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
-+ class_device_unregister(&priv->cdev);
- mutex_unlock(&rx_queue_mutex);
-
- return 0;
-@@ -1949,13 +1967,14 @@ static __init int iscsi_transport_init(void)
- if (err)
- return err;
-
-+#if 0
- err = class_register(&iscsi_endpoint_class);
- if (err)
- goto unregister_transport_class;
--
-+#endif
- err = transport_class_register(&iscsi_host_class);
- if (err)
-- goto unregister_endpoint_class;
-+ goto unregister_transport_class;
-
- err = transport_class_register(&iscsi_connection_class);
- if (err)
-@@ -1986,8 +2005,10 @@ unregister_conn_class:
- transport_class_unregister(&iscsi_connection_class);
- unregister_host_class:
- transport_class_unregister(&iscsi_host_class);
-+#if 0
- unregister_endpoint_class:
- class_unregister(&iscsi_endpoint_class);
-+#endif
- unregister_transport_class:
- class_unregister(&iscsi_transport_class);
- return err;
-@@ -2000,7 +2021,9 @@ static void __exit iscsi_transport_exit(void)
- transport_class_unregister(&iscsi_connection_class);
- transport_class_unregister(&iscsi_session_class);
- transport_class_unregister(&iscsi_host_class);
-+#if 0
- class_unregister(&iscsi_endpoint_class);
-+#endif
- class_unregister(&iscsi_transport_class);
- }
-
-diff --git a/scsi_transport_iscsi.h b/scsi_transport_iscsi.h
-index 27d067a..6fa17f6 100644
---- a/scsi_transport_iscsi.h
-+++ b/scsi_transport_iscsi.h
-@@ -25,9 +25,14 @@
-
- #include <linux/device.h>
- #include <linux/list.h>
-+#include <linux/version.h>
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
- #include <linux/mutex.h>
-+#endif
- #include "iscsi_if.h"
-
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct iscsi_transport;
- struct iscsi_endpoint;
-@@ -184,7 +189,7 @@ struct iscsi_cls_session {
-
- /* recovery fields */
- int recovery_tmo;
-- struct delayed_work recovery_work;
-+ struct work_struct recovery_work;
-
- unsigned int target_id;
-
---
-1.5.6.6
-
diff --git a/kernel/2.6.14-23_compat.patch b/kernel/2.6.14-23_compat.patch
deleted file mode 100644
index 8936615..0000000
--- a/kernel/2.6.14-23_compat.patch
+++ /dev/null
@@ -1,1468 +0,0 @@
-diff --git a/iscsi_tcp.c b/iscsi_tcp.c
-index 2a401b9..13636d4 100644
---- a/iscsi_tcp.c
-+++ b/iscsi_tcp.c
-@@ -43,6 +43,7 @@
- #include <scsi/scsi.h>
- #include "scsi_transport_iscsi.h"
-
-+#include "open_iscsi_compat.h"
- #include "iscsi_tcp.h"
-
- MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
-@@ -480,10 +481,9 @@ static int iscsi_sw_tcp_pdu_init(struct iscsi_task *task,
- if (!task->sc)
- iscsi_sw_tcp_send_linear_data_prep(conn, task->data, count);
- else {
-- struct scsi_data_buffer *sdb = scsi_out(task->sc);
-
-- err = iscsi_sw_tcp_send_data_prep(conn, sdb->table.sgl,
-- sdb->table.nents, offset,
-+ err = iscsi_sw_tcp_send_data_prep(conn, scsi_sglist(task->sc),
-+ scsi_sg_count(task->sc), offset,
- count);
- }
-
-@@ -860,12 +860,6 @@ static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
- iscsi_host_free(shost);
- }
-
--static int iscsi_sw_tcp_slave_alloc(struct scsi_device *sdev)
--{
-- set_bit(QUEUE_FLAG_BIDI, &sdev->request_queue->queue_flags);
-- return 0;
--}
--
- static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev)
- {
- blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_ANY);
-@@ -883,10 +877,9 @@ static struct scsi_host_template iscsi_sw_tcp_sht = {
- .max_sectors = 0xFFFF,
- .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
- .eh_abort_handler = iscsi_eh_abort,
-+ .eh_host_reset_handler = iscsi_eh_recover_target,
- .eh_device_reset_handler= iscsi_eh_device_reset,
-- .eh_target_reset_handler = iscsi_eh_recover_target,
- .use_clustering = DISABLE_CLUSTERING,
-- .slave_alloc = iscsi_sw_tcp_slave_alloc,
- .slave_configure = iscsi_sw_tcp_slave_configure,
- .target_alloc = iscsi_target_alloc,
- .proc_name = "iscsi_tcp",
-diff --git a/libiscsi.c b/libiscsi.c
-index 59e3a5f..ee9716e 100644
---- a/libiscsi.c
-+++ b/libiscsi.c
-@@ -24,7 +24,10 @@
- #include <linux/types.h>
- #include <linux/kfifo.h>
- #include <linux/delay.h>
-+#include <linux/version.h>
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
- #include <linux/log2.h>
-+#endif
- #include <linux/slab.h>
- #include <asm/unaligned.h>
- #include <net/tcp.h>
-@@ -39,6 +42,8 @@
- #include "scsi_transport_iscsi.h"
- #include "libiscsi.h"
-
-+#include "open_iscsi_compat.h"
-+
- static int iscsi_dbg_lib_conn;
- module_param_named(debug_libiscsi_conn, iscsi_dbg_lib_conn, int,
- S_IRUGO | S_IWUSR);
-@@ -256,7 +261,7 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
- sizeof(rlen_ahdr->reserved));
- rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
- rlen_ahdr->reserved = 0;
-- rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
-+ rlen_ahdr->read_length = cpu_to_be32(scsi_bufflen(sc));
-
- ISCSI_DBG_SESSION(task->conn->session,
- "bidi-in rlen_ahdr->read_length(%d) "
-@@ -411,7 +416,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- return rc;
- }
- if (sc->sc_data_direction == DMA_TO_DEVICE) {
-- unsigned out_len = scsi_out(sc)->length;
-+ unsigned out_len = scsi_bufflen(sc);
- struct iscsi_r2t_info *r2t = &task->unsol_r2t;
-
- hdr->data_length = cpu_to_be32(out_len);
-@@ -457,7 +462,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- } else {
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- zero_data(hdr->dlength);
-- hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
-+ hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
-
- if (sc->sc_data_direction == DMA_FROM_DEVICE)
- hdr->flags |= ISCSI_FLAG_CMD_READ;
-@@ -486,7 +491,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- sc->sc_data_direction == DMA_TO_DEVICE ?
- "write" : "read", conn->id, sc, sc->cmnd[0],
- task->itt, scsi_bufflen(sc),
-- scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
-+ scsi_bidi_cmnd(sc) ? scsi_bufflen(sc) : 0,
- session->cmdsn,
- session->max_cmdsn - session->exp_cmdsn + 1);
- return 0;
-@@ -518,7 +523,7 @@ static void iscsi_free_task(struct iscsi_task *task)
- if (conn->login_task == task)
- return;
-
-- kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
-+ __kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
-
- if (sc) {
- task->sc = NULL;
-@@ -648,12 +653,7 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
- state = ISCSI_TASK_ABRT_TMF;
-
- sc->result = err << 16;
-- if (!scsi_bidi_cmnd(sc))
-- scsi_set_resid(sc, scsi_bufflen(sc));
-- else {
-- scsi_out(sc)->resid = scsi_out(sc)->length;
-- scsi_in(sc)->resid = scsi_in(sc)->length;
-- }
-+ scsi_set_resid(sc, scsi_bufflen(sc));
-
- iscsi_complete_task(task, state);
- }
-@@ -738,7 +738,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
- BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
-
-- if (!kfifo_out(&session->cmdpool.queue,
-+ if (!__kfifo_get(session->cmdpool.queue,
- (void*)&task, sizeof(void*)))
- return NULL;
- }
-@@ -853,7 +853,7 @@ invalid_datalen:
- goto out;
- }
-
-- senselen = get_unaligned_be16(data);
-+ senselen = be16_to_cpu(get_unaligned((__be16 *) data));
- if (datalen < senselen)
- goto invalid_datalen;
-
-@@ -870,8 +870,8 @@ invalid_datalen:
-
- if (scsi_bidi_cmnd(sc) && res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
-- res_count <= scsi_in(sc)->length))
-- scsi_in(sc)->resid = res_count;
-+ res_count <= scsi_bufflen(sc)))
-+ scsi_set_resid(sc, res_count);
- else
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- }
-@@ -920,8 +920,8 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
-
- if (res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
-- res_count <= scsi_in(sc)->length))
-- scsi_in(sc)->resid = res_count;
-+ res_count <= scsi_bufflen(sc)))
-+ scsi_set_resid(sc, res_count);
- else
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- }
-@@ -1568,7 +1568,7 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
- {
- struct iscsi_task *task;
-
-- if (!kfifo_out(&conn->session->cmdpool.queue,
-+ if (!__kfifo_get(conn->session->cmdpool.queue,
- (void *) &task, sizeof(void *)))
- return NULL;
-
-@@ -1717,7 +1717,11 @@ reject:
- ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
- sc->cmnd[0], reason);
- spin_lock(host->host_lock);
-+#if (defined RHELC1) || (defined SLEC1)
-+ return SCSI_MLQUEUE_DEVICE_BUSY;
-+#else
- return SCSI_MLQUEUE_TARGET_BUSY;
-+#endif
-
- prepd_fault:
- sc->scsi_done = NULL;
-@@ -1726,33 +1730,16 @@ fault:
- spin_unlock(&session->lock);
- ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
- sc->cmnd[0], reason);
-- if (!scsi_bidi_cmnd(sc))
-- scsi_set_resid(sc, scsi_bufflen(sc));
-- else {
-- scsi_out(sc)->resid = scsi_out(sc)->length;
-- scsi_in(sc)->resid = scsi_in(sc)->length;
-- }
-+ scsi_set_resid(sc, scsi_bufflen(sc));
- done(sc);
- spin_lock(host->host_lock);
- return 0;
- }
- EXPORT_SYMBOL_GPL(iscsi_queuecommand);
-
--int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
-+int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
- {
-- switch (reason) {
-- case SCSI_QDEPTH_DEFAULT:
-- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
-- break;
-- case SCSI_QDEPTH_QFULL:
-- scsi_track_queue_full(sdev, depth);
-- break;
-- case SCSI_QDEPTH_RAMP_UP:
-- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
-- break;
-- default:
-- return -EOPNOTSUPP;
-- }
-+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- return sdev->queue_depth;
- }
- EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
-@@ -2524,7 +2511,12 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
- if (q->pool == NULL)
- return -ENOMEM;
-
-- kfifo_init(&q->queue, (void*)q->pool, max * sizeof(void*));
-+ q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
-+ GFP_KERNEL, NULL);
-+ if (IS_ERR(q->queue)) {
-+ q->queue = NULL;
-+ goto enomem;
-+ }
-
- for (i = 0; i < max; i++) {
- q->pool[i] = kzalloc(item_size, GFP_KERNEL);
-@@ -2532,7 +2524,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
- q->max = i;
- goto enomem;
- }
-- kfifo_in(&q->queue, (void*)&q->pool[i], sizeof(void*));
-+ __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
- }
-
- if (items) {
-@@ -2555,6 +2547,7 @@ void iscsi_pool_free(struct iscsi_pool *q)
- for (i = 0; i < q->max; i++)
- kfree(q->pool[i]);
- kfree(q->pool);
-+ kfree(q->queue);
- }
- EXPORT_SYMBOL_GPL(iscsi_pool_free);
-
-@@ -2882,7 +2875,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
-
- /* allocate login_task used for the login/text sequences */
- spin_lock_bh(&session->lock);
-- if (!kfifo_out(&session->cmdpool.queue,
-+ if (!__kfifo_get(session->cmdpool.queue,
- (void*)&conn->login_task,
- sizeof(void*))) {
- spin_unlock_bh(&session->lock);
-@@ -2902,7 +2895,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
- return cls_conn;
-
- login_task_data_alloc_fail:
-- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
-+ __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
- sizeof(void*));
- login_task_alloc_fail:
- iscsi_destroy_conn(cls_conn);
-@@ -2965,7 +2958,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
- free_pages((unsigned long) conn->data,
- get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
- kfree(conn->persistent_address);
-- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
-+ __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
- sizeof(void*));
- if (session->leadconn == conn)
- session->leadconn = NULL;
-diff --git a/libiscsi.h b/libiscsi.h
-index 0563539..4be9333 100644
---- a/libiscsi.h
-+++ b/libiscsi.h
-@@ -231,7 +231,7 @@ struct iscsi_conn {
- };
-
- struct iscsi_pool {
-- struct kfifo queue; /* FIFO Queue */
-+ struct kfifo *queue; /* FIFO Queue */
- void **pool; /* Pool of elements */
- int max; /* Max number of elements */
- };
-@@ -334,8 +334,7 @@ struct iscsi_host {
- /*
- * scsi host template
- */
--extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth,
-- int reason);
-+extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth);
- extern int iscsi_eh_abort(struct scsi_cmnd *sc);
- extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
- extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
-diff --git a/libiscsi_tcp.c b/libiscsi_tcp.c
-index 1122de4..c590df2 100644
---- a/libiscsi_tcp.c
-+++ b/libiscsi_tcp.c
-@@ -361,6 +361,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment,
- struct scatterlist *sg;
- unsigned int i;
-
-+ /*
-+ * older kernels could send use_sg=0 for commands like sgio
-+ * or scsi-ml commands.
-+ */
-+
-+ if (!sg_count) {
-+ iscsi_segment_init_linear(segment, (void *)sg_list + offset,
-+ size, done, hash);
-+ return 0;
-+ }
-+
- __iscsi_segment_init(segment, size, done, hash);
- for_each_sg(sg_list, sg, sg_count, i) {
- if (offset < sg->length) {
-@@ -446,15 +457,15 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
- return;
-
- /* flush task's r2t queues */
-- while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ while (__kfifo_get(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- ISCSI_DBG_TCP(task->conn, "pending r2t dropped\n");
- }
-
- r2t = tcp_task->r2t;
- if (r2t != NULL) {
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- tcp_task->r2t = NULL;
- }
-@@ -472,7 +483,7 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
- int datasn = be32_to_cpu(rhdr->datasn);
-- unsigned total_in_length = scsi_in(task->sc)->length;
-+ unsigned total_in_length = scsi_bufflen(task->sc);
-
- /*
- * lib iscsi will update this in the completion handling if there
-@@ -542,7 +553,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- return 0;
- }
-
-- rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
-+ rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
- if (!rc) {
- iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
- "Target has sent more R2Ts than it "
-@@ -555,7 +566,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- if (r2t->data_length == 0) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with zero data len\n");
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
- }
-@@ -566,12 +577,12 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- r2t->data_length, session->max_burst);
-
- r2t->data_offset = be32_to_cpu(rhdr->data_offset);
-- if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
-+ if (r2t->data_offset + r2t->data_length > scsi_bufflen(task->sc)) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with data len %u at offset %u "
- "and total length %d\n", r2t->data_length,
-- r2t->data_offset, scsi_out(task->sc)->length);
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ r2t->data_offset, scsi_bufflen(task->sc));
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
- }
-@@ -581,7 +592,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- r2t->sent = 0;
-
- tcp_task->exp_datasn = r2tsn + 1;
-- kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
-+ __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
- conn->r2t_pdus_cnt++;
-
- iscsi_requeue_task(task);
-@@ -669,7 +680,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- if (tcp_conn->in.datalen) {
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct hash_desc *rx_hash = NULL;
-- struct scsi_data_buffer *sdb = scsi_in(task->sc);
-
- /*
- * Setup copy of Data-In into the Scsi_Cmnd
-@@ -689,8 +699,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- tcp_conn->in.datalen);
- task->last_xfer = jiffies;
- rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
-- sdb->table.sgl,
-- sdb->table.nents,
-+ scsi_sglist(task->sc),
-+ scsi_sg_count(task->sc),
- tcp_task->data_offset,
- tcp_conn->in.datalen,
- iscsi_tcp_process_data_in,
-@@ -952,7 +962,7 @@ int iscsi_tcp_task_init(struct iscsi_task *task)
- return conn->session->tt->init_pdu(task, 0, task->data_count);
- }
-
-- BUG_ON(kfifo_len(&tcp_task->r2tqueue));
-+ BUG_ON(__kfifo_len(tcp_task->r2tqueue));
- tcp_task->exp_datasn = 0;
-
- /* Prepare PDU, optionally w/ immediate data */
-@@ -983,7 +993,7 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
- if (r2t->data_length <= r2t->sent) {
- ISCSI_DBG_TCP(task->conn,
- " done with r2t %p\n", r2t);
-- kfifo_in(&tcp_task->r2tpool.queue,
-+ __kfifo_put(tcp_task->r2tpool.queue,
- (void *)&tcp_task->r2t,
- sizeof(void *));
- tcp_task->r2t = r2t = NULL;
-@@ -991,12 +1001,9 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
- }
-
- if (r2t == NULL) {
-- if (kfifo_out(&tcp_task->r2tqueue,
-- (void *)&tcp_task->r2t, sizeof(void *)) !=
-- sizeof(void *))
-- r2t = NULL;
-- else
-- r2t = tcp_task->r2t;
-+ __kfifo_get(tcp_task->r2tqueue,
-+ (void *)&tcp_task->r2t, sizeof(void *));
-+ r2t = tcp_task->r2t;
- }
- spin_unlock_bh(&session->lock);
- }
-@@ -1131,8 +1138,9 @@ int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
- }
-
- /* R2T xmit queue */
-- if (kfifo_alloc(&tcp_task->r2tqueue,
-- session->max_r2t * 4 * sizeof(void*), GFP_KERNEL)) {
-+ tcp_task->r2tqueue = kfifo_alloc(
-+ session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
-+ if (tcp_task->r2tqueue == ERR_PTR(-ENOMEM)) {
- iscsi_pool_free(&tcp_task->r2tpool);
- goto r2t_alloc_fail;
- }
-@@ -1145,7 +1153,7 @@ r2t_alloc_fail:
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
-- kfifo_free(&tcp_task->r2tqueue);
-+ kfifo_free(tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
- return -ENOMEM;
-@@ -1160,7 +1168,7 @@ void iscsi_tcp_r2tpool_free(struct iscsi_session *session)
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
-- kfifo_free(&tcp_task->r2tqueue);
-+ kfifo_free(tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
- }
-diff --git a/libiscsi_tcp.h b/libiscsi_tcp.h
-index c020eee..3bacef5 100644
---- a/libiscsi_tcp.h
-+++ b/libiscsi_tcp.h
-@@ -80,7 +80,7 @@ struct iscsi_tcp_task {
- int data_offset;
- struct iscsi_r2t_info *r2t; /* in progress solict R2T */
- struct iscsi_pool r2tpool;
-- struct kfifo r2tqueue;
-+ struct kfifo *r2tqueue;
- void *dd_data;
- };
-
-diff --git a/open_iscsi_compat.h b/open_iscsi_compat.h
-new file mode 100644
-index 0000000..e6511d3
---- /dev/null
-+++ b/open_iscsi_compat.h
-@@ -0,0 +1,399 @@
-+#ifndef OPEN_ISCSI_COMPAT
-+#define OPEN_ISCSI_COMPAT
-+
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <scsi/scsi.h>
-+#include <scsi/scsi_cmnd.h>
-+#include <scsi/scsi_host.h>
-+
-+#ifndef SCAN_WILD_CARD
-+#define SCAN_WILD_CARD ~0
-+#endif
-+
-+#ifndef NIPQUAD_FMT
-+#define NIPQUAD_FMT "%u.%u.%u.%u"
-+#endif
-+
-+#ifndef NIP6_FMT
-+#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-+#endif
-+
-+#ifndef DEFINE_MUTEX
-+
-+/* mutex changes from 2.6.16-rc1 and up */
-+#define DEFINE_MUTEX DECLARE_MUTEX
-+#define mutex_lock down
-+#define mutex_unlock up
-+#define mutex semaphore
-+#define mutex_init init_MUTEX
-+#endif
-+
-+#ifdef RHEL_RELEASE_CODE
-+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6, 0))
-+#define RHELC1 1
-+#endif
-+#endif
-+
-+#ifdef SLE_VERSION_CODE
-+#if (SLE_VERSION_CODE < SLE_VERSION(11, 0, 0))
-+#define SLEC1 1
-+#endif
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,19)
-+struct delayed_work {
-+ struct work_struct work;
-+};
-+
-+#define cancel_delayed_work(_dwork) cancel_delayed_work(&(_dwork)->work)
-+#define INIT_DELAYED_WORK(_work,_func) INIT_WORK(&(_work)->work, _func)
-+
-+static inline void INIT_WORK_compat(struct work_struct *work, void *func)
-+{
-+ INIT_WORK(work, func, work);
-+}
-+
-+#undef INIT_WORK
-+#define INIT_WORK(_work, _func) INIT_WORK_compat(_work, _func)
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12)
-+
-+void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun)
-+{
-+ int i;
-+
-+ memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
-+
-+ for (i = 0; i < sizeof(lun); i += 2) {
-+ scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
-+ scsilun->scsi_lun[i+1] = lun & 0xFF;
-+ lun = lun >> 16;
-+ }
-+}
-+
-+#define __nlmsg_put(skb, daemon_pid, seq, type, len, flags) \
-+ __nlmsg_put(skb, daemon_pid, 0, 0, len)
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+#ifdef RHEL_RELEASE_CODE && \
-+ RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(4,8)
-+
-+#define gfp_t unsigned
-+
-+void *kzalloc(size_t size, gfp_t flags)
-+{
-+ void *ret = kmalloc(size, flags);
-+ if (ret)
-+ memset(ret, 0, size);
-+}
-+
-+#endif
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+
-+#include "linux/crypto.h"
-+
-+#if !defined SLEC1
-+#define CRYPTO_ALG_ASYNC 0x00000080
-+struct hash_desc
-+{
-+ struct crypto_tfm *tfm;
-+ u32 flags;
-+};
-+
-+static inline int crypto_hash_init(struct hash_desc *desc)
-+{
-+ crypto_digest_init(desc->tfm);
-+ return 0;
-+}
-+
-+static inline int crypto_hash_digest(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes, u8 *out)
-+{
-+ crypto_digest_digest(desc->tfm, sg, 1, out);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_update(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes)
-+{
-+ crypto_digest_update(desc->tfm, sg, 1);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
-+{
-+ crypto_digest_final(desc->tfm, out);
-+ return 0;
-+}
-+
-+static inline struct crypto_tfm *crypto_alloc_hash(const char *alg_name,
-+ u32 type, u32 mask)
-+{
-+ struct crypto_tfm *ret = crypto_alloc_tfm(alg_name ,type);
-+ return ret ? ret : ERR_PTR(-ENOMEM);
-+}
-+
-+static inline void crypto_free_hash(struct crypto_tfm *tfm)
-+{
-+ crypto_free_tfm(tfm);
-+}
-+#endif
-+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) \
-+ && !(defined RHELC1)
-+static inline int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 0);
-+}
-+
-+static inline int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 1);
-+}
-+#endif
-+#endif
-+
-+#ifndef bool
-+#define bool int
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
-+#ifdef RHEL_RELEASE_VERSION
-+#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,2) && \
-+ RHEL_RELEASE_CODE != RHEL_RELEASE_VERSION(4,8)
-+static inline int is_power_of_2(unsigned long n)
-+{
-+ return (n != 0 && ((n & (n - 1)) == 0));
-+}
-+#endif
-+#else
-+/* not a redhat kernel */
-+static inline int is_power_of_2(unsigned long n)
-+{
-+ return (n != 0 && ((n & (n - 1)) == 0));
-+}
-+#endif
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
-+{
-+ return (struct nlmsghdr *)skb->data;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+#ifdef RHEL_RELEASE_VERSION
-+#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,2)
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+ return (void *)shost->hostdata;
-+}
-+#endif
-+#else
-+/* not a redhat kernel */
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+ return (void *)shost->hostdata;
-+}
-+#endif
-+
-+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)) && \
-+ !defined(SLEC1)
-+/**
-+ * scsilun_to_int: convert a scsi_lun to an int
-+ * @scsilun: struct scsi_lun to be converted.
-+ *
-+ * Description:
-+ * Convert @scsilun from a struct scsi_lun to a four byte host byte-ordered
-+ * integer, and return the result. The caller must check for
-+ * truncation before using this function.
-+ *
-+ * Notes:
-+ * The struct scsi_lun is assumed to be four levels, with each level
-+ * effectively containing a SCSI byte-ordered (big endian) short; the
-+ * addressing bits of each level are ignored (the highest two bits).
-+ * For a description of the LUN format, post SCSI-3 see the SCSI
-+ * Architecture Model, for SCSI-3 see the SCSI Controller Commands.
-+ *
-+ * Given a struct scsi_lun of: 0a 04 0b 03 00 00 00 00, this function returns
-+ * the integer: 0x0b030a04
-+ **/
-+static inline int scsilun_to_int(struct scsi_lun *scsilun)
-+{
-+ int i;
-+ unsigned int lun;
-+
-+ lun = 0;
-+ for (i = 0; i < sizeof(lun); i += 2)
-+ lun = lun | (((scsilun->scsi_lun[i] << 8) |
-+ scsilun->scsi_lun[i + 1]) << (i * 8));
-+ return lun;
-+}
-+#endif
-+
-+/*
-+ * Note: We do not support bidi for the compat modules if the kernel
-+ * does not have support.
-+ */
-+#define scsi_sg_count(cmd) ((cmd)->use_sg)
-+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
-+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
-+
-+#ifdef RHEL_RELEASE_VERSION
-+#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,2)
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+ cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+ return cmd->resid;
-+}
-+#endif
-+#else
-+/* not a redhat kernel */
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+ cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+ return cmd->resid;
-+}
-+#endif
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+#ifdef SLE_VERSION_CODE
-+#if SLE_VERSION_CODE == SLE_VERSION(10,2,0)
-+
-+static inline unsigned fls_long(unsigned long l)
-+{
-+ if (sizeof(l) == 4)
-+ return fls(l);
-+ return fls64(l);
-+}
-+
-+#endif
-+#endif
-+
-+static inline unsigned long rounddown_pow_of_two(unsigned long n)
-+{
-+ return 1UL << (fls_long(n) - 1);
-+}
-+
-+
-+static inline struct scatterlist *sg_next(struct scatterlist *sg)
-+{
-+ if (!sg) {
-+ BUG();
-+ return NULL;
-+ }
-+ return sg + 1;
-+}
-+
-+#define for_each_sg(sglist, sg, nr, __i) \
-+ for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
-+
-+#define sg_page(_sg) _sg->page
-+
-+static inline void sg_set_page(struct scatterlist *sg, struct page *page,
-+ unsigned int len, unsigned int offset)
-+{
-+ sg->page = page;
-+ sg->offset = offset;
-+ sg->length = len;
-+}
-+
-+static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
-+{
-+ memset(sgl, 0, sizeof(*sgl) * nents);
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
-+
-+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
-+{
-+ return 0;
-+}
-+
-+#define netlink_kernel_release(_nls) \
-+ sock_release(_nls->sk_socket)
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#endif
-+
-+#ifndef DID_TRANSPORT_DISRUPTED
-+#define DID_TRANSPORT_DISRUPTED DID_BUS_BUSY
-+#endif
-+
-+#ifndef DID_TRANSPORT_FAILFAST
-+#define DID_TRANSPORT_FAILFAST DID_NO_CONNECT
-+#endif
-+
-+#ifndef SCSI_MLQUEUE_TARGET_BUSY
-+#define SCSI_MLQUEUE_TARGET_BUSY SCSI_MLQUEUE_HOST_BUSY
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)
-+
-+#define BLK_EH_NOT_HANDLED EH_NOT_HANDLED
-+#define BLK_EH_RESET_TIMER EH_RESET_TIMER
-+
-+#define blk_eh_timer_return scsi_eh_timer_return
-+
-+#endif
-+
-+#ifndef SCSI_MAX_VARLEN_CDB_SIZE
-+#define SCSI_MAX_VARLEN_CDB_SIZE 16
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34)
-+
-+static inline wait_queue_head_t *sk_sleep(struct sock *sk)
-+{
-+ return sk->sk_sleep;
-+}
-+
-+#endif
-+
-+#endif
-diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c
-index fed8c9e..362bd4d 100644
---- a/scsi_transport_iscsi.c
-+++ b/scsi_transport_iscsi.c
-@@ -73,13 +73,13 @@ struct iscsi_internal {
- struct scsi_transport_template t;
- struct iscsi_transport *iscsi_transport;
- struct list_head list;
-- struct device dev;
-+ struct class_device cdev;
-
-- struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
-+ struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
- struct transport_container conn_cont;
-- struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
-+ struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
- struct transport_container session_cont;
-- struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
-+ struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
- };
-
- static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
-@@ -96,12 +96,12 @@ static DEFINE_SPINLOCK(iscsi_transport_lock);
- #define to_iscsi_internal(tmpl) \
- container_of(tmpl, struct iscsi_internal, t)
-
--#define dev_to_iscsi_internal(_dev) \
-- container_of(_dev, struct iscsi_internal, dev)
-+#define cdev_to_iscsi_internal(_cdev) \
-+ container_of(_cdev, struct iscsi_internal, cdev)
-
--static void iscsi_transport_release(struct device *dev)
-+static void iscsi_transport_release(struct class_device *cdev)
- {
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- kfree(priv);
- }
-
-@@ -111,33 +111,31 @@ static void iscsi_transport_release(struct device *dev)
- */
- static struct class iscsi_transport_class = {
- .name = "iscsi_transport",
-- .dev_release = iscsi_transport_release,
-+ .release = iscsi_transport_release,
- };
-
- static ssize_t
--show_transport_handle(struct device *dev, struct device_attribute *attr,
-- char *buf)
-+show_transport_handle(struct class_device *cdev, char *buf)
- {
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
- }
--static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-+static CLASS_DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-
- #define show_transport_attr(name, format) \
- static ssize_t \
--show_transport_##name(struct device *dev, \
-- struct device_attribute *attr,char *buf) \
-+show_transport_##name(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev); \
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev); \
- return sprintf(buf, format"\n", priv->iscsi_transport->name); \
- } \
--static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-
- show_transport_attr(caps, "0x%x");
-
- static struct attribute *iscsi_transport_attrs[] = {
-- &dev_attr_handle.attr,
-- &dev_attr_caps.attr,
-+ &class_device_attr_handle.attr,
-+ &class_device_attr_caps.attr,
- NULL,
- };
-
-@@ -155,27 +153,28 @@ static struct attribute_group iscsi_transport_group = {
- struct device_attribute dev_attr_##_prefix##_##_name = \
- __ATTR(_name,_mode,_show,_store)
-
--static void iscsi_endpoint_release(struct device *dev)
-+static void iscsi_endpoint_release(struct class_device *cdev)
- {
-- struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
-+ struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(cdev);
- kfree(ep);
- }
-
- static struct class iscsi_endpoint_class = {
- .name = "iscsi_endpoint",
-- .dev_release = iscsi_endpoint_release,
-+ .release = iscsi_endpoint_release,
- };
-
- static ssize_t
--show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf)
-+show_ep_handle(struct class_device *cdev, char *buf)
- {
-- struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
-+ struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(cdev);
- return sprintf(buf, "%llu\n", (unsigned long long) ep->id);
- }
--static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL);
-+static struct class_device_attribute class_device_attr_ep_handle =
-+ __ATTR(handle, S_IRUGO, show_ep_handle, NULL);
-
- static struct attribute *iscsi_endpoint_attrs[] = {
-- &dev_attr_ep_handle.attr,
-+ &class_device_attr_ep_handle.attr,
- NULL,
- };
-
-@@ -185,26 +184,15 @@ static struct attribute_group iscsi_endpoint_group = {
-
- #define ISCSI_MAX_EPID -1
-
--static int iscsi_match_epid(struct device *dev, void *data)
--{
-- struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
-- uint64_t *epid = (uint64_t *) data;
--
-- return *epid == ep->id;
--}
--
- struct iscsi_endpoint *
- iscsi_create_endpoint(int dd_size)
- {
-- struct device *dev;
- struct iscsi_endpoint *ep;
- uint64_t id;
- int err;
-
- for (id = 1; id < ISCSI_MAX_EPID; id++) {
-- dev = class_find_device(&iscsi_endpoint_class, NULL, &id,
-- iscsi_match_epid);
-- if (!dev)
-+ if (!iscsi_lookup_endpoint(id))
- break;
- }
- if (id == ISCSI_MAX_EPID) {
-@@ -219,8 +207,9 @@ iscsi_create_endpoint(int dd_size)
-
- ep->id = id;
- ep->dev.class = &iscsi_endpoint_class;
-- dev_set_name(&ep->dev, "ep-%llu", (unsigned long long) id);
-- err = device_register(&ep->dev);
-+ snprintf(ep->dev.class_id, BUS_ID_SIZE, "ep-%llu",
-+ (unsigned long long) id);
-+ err = class_device_register(&ep->dev);
- if (err)
- goto free_ep;
-
-@@ -233,7 +222,7 @@ iscsi_create_endpoint(int dd_size)
- return ep;
-
- unregister_dev:
-- device_unregister(&ep->dev);
-+ class_device_unregister(&ep->dev);
- return NULL;
-
- free_ep:
-@@ -245,32 +234,38 @@ EXPORT_SYMBOL_GPL(iscsi_create_endpoint);
- void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
- {
- sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group);
-- device_unregister(&ep->dev);
-+ class_device_unregister(&ep->dev);
- }
- EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint);
-
- struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
- {
-- struct iscsi_endpoint *ep;
-- struct device *dev;
--
-- dev = class_find_device(&iscsi_endpoint_class, NULL, &handle,
-- iscsi_match_epid);
-- if (!dev)
-- return NULL;
-+ struct iscsi_endpoint *ep = NULL;
-+ struct class_device *cdev;
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
-+ down_read(&iscsi_endpoint_class.subsys.rwsem);
-+#else
-+ spin_lock(&iscsi_endpoint_class.subsys.list_lock);
-+#endif
-+ list_for_each_entry(cdev, &iscsi_endpoint_class.children, node) {
-+ ep = iscsi_dev_to_endpoint(cdev);
-+ if (ep->id == handle)
-+ break;
-+ ep = NULL;
-+ }
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
-+ up_read(&iscsi_endpoint_class.subsys.rwsem);
-+#else
-+ spin_unlock(&iscsi_endpoint_class.subsys.list_lock);
-+#endif
-
-- ep = iscsi_dev_to_endpoint(dev);
-- /*
-- * we can drop this now because the interface will prevent
-- * removals and lookups from racing.
-- */
-- put_device(dev);
- return ep;
- }
- EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
-
- static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
-- struct device *cdev)
-+ struct class_device *cdev)
- {
- struct Scsi_Host *shost = dev_to_shost(dev);
- struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -571,8 +566,6 @@ static void __iscsi_unblock_session(struct work_struct *work)
- struct iscsi_cls_session *session =
- container_of(work, struct iscsi_cls_session,
- unblock_work);
-- struct Scsi_Host *shost = iscsi_session_to_shost(session);
-- struct iscsi_cls_host *ihost = shost->shost_data;
- unsigned long flags;
-
- ISCSI_DBG_TRANS_SESSION(session, "Unblocking session\n");
-@@ -586,15 +579,6 @@ static void __iscsi_unblock_session(struct work_struct *work)
- spin_unlock_irqrestore(&session->lock, flags);
- /* start IO */
- scsi_target_unblock(&session->dev);
-- /*
-- * Only do kernel scanning if the driver is properly hooked into
-- * the async scanning code (drivers like iscsi_tcp do login and
-- * scanning from userspace).
-- */
-- if (shost->hostt->scan_finished) {
-- if (scsi_queue_work(shost, &session->scan_work))
-- atomic_inc(&ihost->nr_scans);
-- }
- ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking session\n");
- }
-
-@@ -750,7 +734,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
- }
- session->target_id = id;
-
-- dev_set_name(&session->dev, "session%u", session->sid);
-+ snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", session->sid);
- err = device_add(&session->dev);
- if (err) {
- iscsi_cls_session_printk(KERN_ERR, session,
-@@ -930,7 +914,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
- if (!get_device(&session->dev))
- goto free_conn;
-
-- dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid);
-+ snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
-+ session->sid, cid);
- conn->dev.parent = &session->dev;
- conn->dev.release = iscsi_conn_release;
- err = device_register(&conn->dev);
-@@ -1003,7 +988,15 @@ iscsi_if_transport_lookup(struct iscsi_transport *tt)
- static int
- iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp)
- {
-- return nlmsg_multicast(nls, skb, 0, group, gfp);
-+ int err;
-+
-+ NETLINK_CB(skb).dst_group = group;
-+
-+ err = netlink_broadcast(nls, skb, 0, group, gfp);
-+ if (err > 0)
-+ err = 0;
-+
-+ return err;
- }
-
- int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
-@@ -1643,51 +1636,65 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
- * Malformed skbs with wrong lengths or invalid creds are not processed.
- */
- static void
--iscsi_if_rx(struct sk_buff *skb)
-+iscsi_if_rx(struct sock *sk, int len)
- {
-- mutex_lock(&rx_queue_mutex);
-- while (skb->len >= NLMSG_SPACE(0)) {
-- int err;
-- uint32_t rlen;
-- struct nlmsghdr *nlh;
-- struct iscsi_uevent *ev;
-- uint32_t group;
--
-- nlh = nlmsg_hdr(skb);
-- if (nlh->nlmsg_len < sizeof(*nlh) ||
-- skb->len < nlh->nlmsg_len) {
-- break;
-- }
--
-- ev = NLMSG_DATA(nlh);
-- rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-- if (rlen > skb->len)
-- rlen = skb->len;
-+ struct sk_buff *skb;
-
-- err = iscsi_if_recv_msg(skb, nlh, &group);
-- if (err) {
-- ev->type = ISCSI_KEVENT_IF_ERROR;
-- ev->iferror = err;
-+ mutex_lock(&rx_queue_mutex);
-+ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
-+ if (NETLINK_CREDS(skb)->uid) {
-+ skb_pull(skb, skb->len);
-+ goto free_skb;
- }
-- do {
-- /*
-- * special case for GET_STATS:
-- * on success - sending reply and stats from
-- * inside of if_recv_msg(),
-- * on error - fall through.
-- */
-- if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
-+
-+ while (skb->len >= NLMSG_SPACE(0)) {
-+ int err;
-+ uint32_t rlen;
-+ struct nlmsghdr *nlh;
-+ struct iscsi_uevent *ev;
-+ uint32_t group;
-+
-+ nlh = nlmsg_hdr(skb);
-+ if (nlh->nlmsg_len < sizeof(*nlh) ||
-+ skb->len < nlh->nlmsg_len) {
- break;
-- err = iscsi_if_send_reply(group, nlh->nlmsg_seq,
-- nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-- } while (err < 0 && err != -ECONNREFUSED);
-- skb_pull(skb, rlen);
-+ }
-+
-+ ev = NLMSG_DATA(nlh);
-+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-+ if (rlen > skb->len)
-+ rlen = skb->len;
-+
-+ err = iscsi_if_recv_msg(skb, nlh, &group);
-+ if (err) {
-+ ev->type = ISCSI_KEVENT_IF_ERROR;
-+ ev->iferror = err;
-+ }
-+ do {
-+ /*
-+ * special case for GET_STATS:
-+ * on success - sending reply and stats from
-+ * inside of if_recv_msg(),
-+ * on error - fall through.
-+ */
-+ if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
-+ break;
-+ err = iscsi_if_send_reply(group, nlh->nlmsg_seq,
-+ nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-+ } while (err < 0 && err != -ECONNREFUSED);
-+ skb_pull(skb, rlen);
-+ }
-+free_skb:
-+ kfree_skb(skb);
- }
- mutex_unlock(&rx_queue_mutex);
- }
-
-+#define iscsi_cdev_to_conn(_cdev) \
-+ iscsi_dev_to_conn(_cdev->dev)
-+
- #define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \
--struct device_attribute dev_attr_##_prefix##_##_name = \
-+struct class_device_attribute class_device_attr_##_prefix##_##_name = \
- __ATTR(_name,_mode,_show,_store)
-
- /*
-@@ -1695,10 +1702,9 @@ struct device_attribute dev_attr_##_prefix##_##_name = \
- */
- #define iscsi_conn_attr_show(param) \
- static ssize_t \
--show_conn_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_conn_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
-+ struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
- struct iscsi_transport *t = conn->transport; \
- return t->get_conn_param(conn, param, buf); \
- }
-@@ -1722,16 +1728,18 @@ iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
- iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
- iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
-
-+#define iscsi_cdev_to_session(_cdev) \
-+ iscsi_dev_to_session(_cdev->dev)
-+
- /*
- * iSCSI session attrs
- */
- #define iscsi_session_attr_show(param, perm) \
- static ssize_t \
--show_session_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_session_param_##param(struct class_device *cdev, char *buf) \
- { \
- struct iscsi_cls_session *session = \
-- iscsi_dev_to_session(dev->parent); \
-+ iscsi_cdev_to_session(cdev); \
- struct iscsi_transport *t = session->transport; \
- \
- if (perm && !capable(CAP_SYS_ADMIN)) \
-@@ -1766,10 +1774,9 @@ iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
- iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
-
- static ssize_t
--show_priv_session_state(struct device *dev, struct device_attribute *attr,
-- char *buf)
-+show_priv_session_state(struct class_device *cdev, char *buf)
- {
-- struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);
- return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
- }
- static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-@@ -1777,11 +1784,10 @@ static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-
- #define iscsi_priv_session_attr_show(field, format) \
- static ssize_t \
--show_priv_session_##field(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_priv_session_##field(struct class_device *cdev, char *buf) \
- { \
- struct iscsi_cls_session *session = \
-- iscsi_dev_to_session(dev->parent); \
-+ iscsi_cdev_to_session(cdev); \
- return sprintf(buf, format"\n", session->field); \
- }
-
-@@ -1796,10 +1802,9 @@ iscsi_priv_session_attr(recovery_tmo, "%d");
- */
- #define iscsi_host_attr_show(param) \
- static ssize_t \
--show_host_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_host_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct Scsi_Host *shost = transport_class_to_shost(dev); \
-+ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
- struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
- return priv->iscsi_transport->get_host_param(shost, param, buf); \
- }
-@@ -1816,7 +1821,7 @@ iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
-
- #define SETUP_PRIV_SESSION_RD_ATTR(field) \
- do { \
-- priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
-+ priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
- count++; \
- } while (0)
-
-@@ -1824,7 +1829,7 @@ do { \
- #define SETUP_SESSION_RD_ATTR(field, param_flag) \
- do { \
- if (tt->param_mask & param_flag) { \
-- priv->session_attrs[count] = &dev_attr_sess_##field; \
-+ priv->session_attrs[count] = &class_device_attr_sess_##field; \
- count++; \
- } \
- } while (0)
-@@ -1832,7 +1837,7 @@ do { \
- #define SETUP_CONN_RD_ATTR(field, param_flag) \
- do { \
- if (tt->param_mask & param_flag) { \
-- priv->conn_attrs[count] = &dev_attr_conn_##field; \
-+ priv->conn_attrs[count] = &class_device_attr_conn_##field; \
- count++; \
- } \
- } while (0)
-@@ -1840,7 +1845,7 @@ do { \
- #define SETUP_HOST_RD_ATTR(field, param_flag) \
- do { \
- if (tt->host_param_mask & param_flag) { \
-- priv->host_attrs[count] = &dev_attr_host_##field; \
-+ priv->host_attrs[count] = &class_device_attr_host_##field; \
- count++; \
- } \
- } while (0)
-@@ -1931,15 +1936,15 @@ iscsi_register_transport(struct iscsi_transport *tt)
- priv->t.user_scan = iscsi_user_scan;
- priv->t.create_work_queue = 1;
-
-- priv->dev.class = &iscsi_transport_class;
-- dev_set_name(&priv->dev, "%s", tt->name);
-- err = device_register(&priv->dev);
-+ priv->cdev.class = &iscsi_transport_class;
-+ snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
-+ err = class_device_register(&priv->cdev);
- if (err)
- goto free_priv;
-
-- err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
-+ err = sysfs_create_group(&priv->cdev.kobj, &iscsi_transport_group);
- if (err)
-- goto unregister_dev;
-+ goto unregister_cdev;
-
- /* host parameters */
- priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
-@@ -2019,8 +2024,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
- printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
- return &priv->t;
-
--unregister_dev:
-- device_unregister(&priv->dev);
-+unregister_cdev:
-+ class_device_unregister(&priv->cdev);
- return NULL;
- free_priv:
- kfree(priv);
-@@ -2048,8 +2053,8 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
- transport_container_unregister(&priv->session_cont);
- transport_container_unregister(&priv->t.host_attrs);
-
-- sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
-- device_unregister(&priv->dev);
-+ sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
-+ class_device_unregister(&priv->cdev);
- mutex_unlock(&rx_queue_mutex);
-
- return 0;
-diff --git a/scsi_transport_iscsi.h b/scsi_transport_iscsi.h
-index ef4b697..a633ee0 100644
---- a/scsi_transport_iscsi.h
-+++ b/scsi_transport_iscsi.h
-@@ -27,6 +27,7 @@
- #include <linux/list.h>
- #include <linux/mutex.h>
- #include "iscsi_if.h"
-+#include "open_iscsi_compat.h"
-
- struct scsi_transport_template;
- struct iscsi_transport;
-@@ -219,7 +220,7 @@ extern void iscsi_host_for_each_session(struct Scsi_Host *shost,
-
- struct iscsi_endpoint {
- void *dd_data; /* LLD private data */
-- struct device dev;
-+ struct class_device dev;
- uint64_t id;
- };
-
---
-1.6.6.1
-
diff --git a/kernel/2.6.16-suse.patch b/kernel/2.6.16-suse.patch
deleted file mode 100644
index f24babd..0000000
--- a/kernel/2.6.16-suse.patch
+++ /dev/null
@@ -1,864 +0,0 @@
-diff --git a/iscsi_tcp.c b/iscsi_tcp.c
-index 908b541..dfd8e31 100644
---- a/iscsi_tcp.c
-+++ b/iscsi_tcp.c
-@@ -426,6 +426,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment,
-
- debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
- offset, size);
-+
-+ /*
-+ * older kernels could send use_sg=0 for commands like sgio
-+ * or scsi-ml commands.
-+ */
-+ if (!sg_count) {
-+ iscsi_segment_init_linear(segment, (void *)sg_list + offset,
-+ size, done, hash);
-+ return 0;
-+ }
-+
- __iscsi_segment_init(segment, size, done, hash);
- for_each_sg(sg_list, sg, sg_count, i) {
- debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
-@@ -536,7 +547,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- struct iscsi_session *session = conn->session;
- struct scsi_cmnd *sc = task->sc;
- int datasn = be32_to_cpu(rhdr->datasn);
-- unsigned total_in_length = scsi_in(sc)->length;
-+ unsigned total_in_length = scsi_bufflen(sc);
-
- iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
- if (tcp_conn->in.datalen == 0)
-@@ -568,7 +579,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- if (res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
- res_count <= total_in_length))
-- scsi_in(sc)->resid = res_count;
-+ scsi_set_resid(sc, res_count);
- else
- sc->result = (DID_BAD_TARGET << 16) |
- rhdr->cmd_status;
-@@ -679,11 +690,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- r2t->data_length, session->max_burst);
-
- r2t->data_offset = be32_to_cpu(rhdr->data_offset);
-- if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
-+ if (r2t->data_offset + r2t->data_length > scsi_bufflen(task->sc)) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with data len %u at offset %u "
- "and total length %d\n", r2t->data_length,
-- r2t->data_offset, scsi_out(task->sc)->length);
-+ r2t->data_offset, scsi_bufflen(task->sc));
- __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
-@@ -783,7 +794,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- if (tcp_conn->in.datalen) {
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct hash_desc *rx_hash = NULL;
-- struct scsi_data_buffer *sdb = scsi_in(task->sc);
-
- /*
- * Setup copy of Data-In into the Scsi_Cmnd
-@@ -801,8 +811,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- tcp_task->data_offset,
- tcp_conn->in.datalen);
- rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
-- sdb->table.sgl,
-- sdb->table.nents,
-+ scsi_sglist(task->sc),
-+ scsi_sg_count(task->sc),
- tcp_task->data_offset,
- tcp_conn->in.datalen,
- iscsi_tcp_process_data_in,
-@@ -1369,8 +1379,8 @@ iscsi_tcp_task_init(struct iscsi_task *task)
- return 0;
-
- /* If we have immediate data, attach a payload */
-- err = iscsi_tcp_send_data_prep(conn, scsi_out(sc)->table.sgl,
-- scsi_out(sc)->table.nents,
-+ err = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+ scsi_sg_count(sc),
- 0, task->imm_count);
- if (err)
- return err;
-@@ -1393,7 +1403,6 @@ iscsi_tcp_task_xmit(struct iscsi_task *task)
- struct iscsi_conn *conn = task->conn;
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct scsi_cmnd *sc = task->sc;
-- struct scsi_data_buffer *sdb;
- int rc = 0;
-
- flush:
-@@ -1413,7 +1422,6 @@ flush:
- if (sc->sc_data_direction != DMA_TO_DEVICE)
- return 0;
-
-- sdb = scsi_out(sc);
- if (task->unsol_count != 0) {
- struct iscsi_data *hdr = &tcp_task->unsol_dtask.hdr;
-
-@@ -1428,8 +1436,8 @@ flush:
- task->itt, tcp_task->sent, task->data_count);
-
- iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
-- rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
-- sdb->table.nents, tcp_task->sent,
-+ rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+ scsi_sg_count(sc), tcp_task->sent,
- task->data_count);
- if (rc)
- goto fail;
-@@ -1475,8 +1483,8 @@ flush:
- iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr,
- sizeof(struct iscsi_hdr));
-
-- rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
-- sdb->table.nents,
-+ rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
-+ scsi_sg_count(sc),
- r2t->data_offset + r2t->sent,
- r2t->data_count);
- if (rc)
-@@ -1864,7 +1872,11 @@ iscsi_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
- shost->max_lun = iscsi_max_lun;
- shost->max_id = 0;
- shost->max_channel = 0;
-+#ifndef SCSI_MAX_VARLEN_CDB_SIZE
-+ shost->max_cmd_len = 16;
-+#else
- shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE;
-+#endif
-
- if (iscsi_host_add(shost, NULL))
- goto free_host;
-@@ -1917,6 +1929,9 @@ static int iscsi_tcp_slave_configure(struct scsi_device *sdev)
- }
-
- static struct scsi_host_template iscsi_sht = {
-+#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,24)
-+ .use_sg_chaining = ENABLE_SG_CHAINING,
-+#endif
- .module = THIS_MODULE,
- .name = "iSCSI Initiator over TCP/IP",
- .queuecommand = iscsi_queuecommand,
-diff --git a/iscsi_tcp.h b/iscsi_tcp.h
-index 68423e8..1796c96 100644
---- a/iscsi_tcp.h
-+++ b/iscsi_tcp.h
-@@ -24,6 +24,8 @@
-
- #include "libiscsi.h"
-
-+#include "open_iscsi_compat.h"
-+
- struct crypto_hash;
- struct socket;
- struct iscsi_tcp_conn;
-diff --git a/libiscsi.c b/libiscsi.c
-index dfeaed3..0fb0705 100644
---- a/libiscsi.c
-+++ b/libiscsi.c
-@@ -24,7 +24,10 @@
- #include <linux/types.h>
- #include <linux/kfifo.h>
- #include <linux/delay.h>
-+#include <linux/version.h>
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
- #include <linux/log2.h>
-+#endif
- #include <asm/unaligned.h>
- #include <net/tcp.h>
- #include <scsi/scsi_cmnd.h>
-@@ -187,7 +190,7 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
- sizeof(rlen_ahdr->reserved));
- rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
- rlen_ahdr->reserved = 0;
-- rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
-+ rlen_ahdr->read_length = cpu_to_be32(scsi_bufflen(sc));
-
- debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
- "rlen_ahdr->ahslength(%d)\n",
-@@ -242,7 +245,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- return rc;
- }
- if (sc->sc_data_direction == DMA_TO_DEVICE) {
-- unsigned out_len = scsi_out(sc)->length;
-+ unsigned out_len = scsi_bufflen(sc);
- hdr->data_length = cpu_to_be32(out_len);
- hdr->flags |= ISCSI_FLAG_CMD_WRITE;
- /*
-@@ -286,7 +289,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- } else {
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- zero_data(hdr->dlength);
-- hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
-+ hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
-
- if (sc->sc_data_direction == DMA_FROM_DEVICE)
- hdr->flags |= ISCSI_FLAG_CMD_READ;
-@@ -314,7 +317,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ?
- "write" : "read", conn->id, sc, sc->cmnd[0], task->itt,
- scsi_bufflen(sc),
-- scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
-+ scsi_bidi_cmnd(sc) ? scsi_bufflen(sc) : 0,
- session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
- return 0;
- }
-@@ -412,12 +415,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
- return;
-
- sc->result = err;
-- if (!scsi_bidi_cmnd(sc))
-- scsi_set_resid(sc, scsi_bufflen(sc));
-- else {
-- scsi_out(sc)->resid = scsi_out(sc)->length;
-- scsi_in(sc)->resid = scsi_in(sc)->length;
-- }
-+ scsi_set_resid(sc, scsi_bufflen(sc));
-
- if (conn->task == task)
- conn->task = NULL;
-@@ -592,7 +590,7 @@ invalid_datalen:
- goto out;
- }
-
-- senselen = get_unaligned_be16(data);
-+ senselen = be16_to_cpu(get_unaligned((__be16 *) data));
- if (datalen < senselen)
- goto invalid_datalen;
-
-@@ -608,8 +606,8 @@ invalid_datalen:
-
- if (scsi_bidi_cmnd(sc) && res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
-- res_count <= scsi_in(sc)->length))
-- scsi_in(sc)->resid = res_count;
-+ res_count <= scsi_bufflen(sc)))
-+ scsi_set_resid(sc, res_count);
- else
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- }
-@@ -1127,10 +1125,9 @@ again:
- return rc;
- }
-
--static void iscsi_xmitworker(struct work_struct *work)
-+static void iscsi_xmitworker(void *data)
- {
-- struct iscsi_conn *conn =
-- container_of(work, struct iscsi_conn, xmitwork);
-+ struct iscsi_conn *conn = data;
- int rc;
- /*
- * serialize Xmit worker on a per-connection basis.
-@@ -1273,12 +1270,7 @@ reject:
- fault:
- spin_unlock(&session->lock);
- debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
-- if (!scsi_bidi_cmnd(sc))
-- scsi_set_resid(sc, scsi_bufflen(sc));
-- else {
-- scsi_out(sc)->resid = scsi_out(sc)->length;
-- scsi_in(sc)->resid = scsi_in(sc)->length;
-- }
-+ scsi_set_resid(sc, scsi_bufflen(sc));
- done(sc);
- spin_lock(host->host_lock);
- return 0;
-@@ -2099,7 +2091,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
- INIT_LIST_HEAD(&conn->mgmtqueue);
- INIT_LIST_HEAD(&conn->xmitqueue);
- INIT_LIST_HEAD(&conn->requeue);
-- INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
-+ INIT_WORK(&conn->xmitwork, iscsi_xmitworker, conn);
-
- /* allocate login_task used for the login/text sequences */
- spin_lock_bh(&session->lock);
-diff --git a/libiscsi.h b/libiscsi.h
-index cfc5fa6..64508d8 100644
---- a/libiscsi.h
-+++ b/libiscsi.h
-@@ -32,6 +32,8 @@
- #include "iscsi_proto.h"
- #include "iscsi_if.h"
-
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct scsi_host_template;
- struct scsi_device;
-diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c
-index 535e461..1ae65fb 100644
---- a/scsi_transport_iscsi.c
-+++ b/scsi_transport_iscsi.c
-@@ -41,13 +41,13 @@ struct iscsi_internal {
- struct scsi_transport_template t;
- struct iscsi_transport *iscsi_transport;
- struct list_head list;
-- struct device dev;
-+ struct class_device cdev;
-
-- struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
-+ struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
- struct transport_container conn_cont;
-- struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
-+ struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
- struct transport_container session_cont;
-- struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
-+ struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
- };
-
- static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
-@@ -64,12 +64,12 @@ static DEFINE_SPINLOCK(iscsi_transport_lock);
- #define to_iscsi_internal(tmpl) \
- container_of(tmpl, struct iscsi_internal, t)
-
--#define dev_to_iscsi_internal(_dev) \
-- container_of(_dev, struct iscsi_internal, dev)
-+#define cdev_to_iscsi_internal(_cdev) \
-+ container_of(_cdev, struct iscsi_internal, cdev)
-
--static void iscsi_transport_release(struct device *dev)
-+static void iscsi_transport_release(struct class_device *cdev)
- {
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- kfree(priv);
- }
-
-@@ -79,33 +79,31 @@ static void iscsi_transport_release(struct device *dev)
- */
- static struct class iscsi_transport_class = {
- .name = "iscsi_transport",
-- .dev_release = iscsi_transport_release,
-+ .release = iscsi_transport_release,
- };
-
- static ssize_t
--show_transport_handle(struct device *dev, struct device_attribute *attr,
-- char *buf)
-+show_transport_handle(struct class_device *cdev, char *buf)
- {
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
- }
--static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-+static CLASS_DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-
- #define show_transport_attr(name, format) \
- static ssize_t \
--show_transport_##name(struct device *dev, \
-- struct device_attribute *attr,char *buf) \
-+show_transport_##name(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev); \
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev); \
- return sprintf(buf, format"\n", priv->iscsi_transport->name); \
- } \
--static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-
- show_transport_attr(caps, "0x%x");
-
- static struct attribute *iscsi_transport_attrs[] = {
-- &dev_attr_handle.attr,
-- &dev_attr_caps.attr,
-+ &class_device_attr_handle.attr,
-+ &class_device_attr_caps.attr,
- NULL,
- };
-
-@@ -113,6 +111,7 @@ static struct attribute_group iscsi_transport_group = {
- .attrs = iscsi_transport_attrs,
- };
-
-+#if 0
- /*
- * iSCSI endpoint attrs
- */
-@@ -229,9 +228,10 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
- return iscsi_dev_to_endpoint(dev);
- }
- EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
-+#endif
-
- static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
-- struct device *cdev)
-+ struct class_device *cdev)
- {
- struct Scsi_Host *shost = dev_to_shost(dev);
- struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -250,7 +250,7 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
- }
-
- static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
-- struct device *cdev)
-+ struct class_device *cdev)
- {
- struct Scsi_Host *shost = dev_to_shost(dev);
- struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -490,10 +490,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
- iscsi_user_scan_session);
- }
-
--static void iscsi_scan_session(struct work_struct *work)
-+static void iscsi_scan_session(void *data)
- {
-- struct iscsi_cls_session *session =
-- container_of(work, struct iscsi_cls_session, scan_work);
-+ struct iscsi_cls_session *session = data;
- struct Scsi_Host *shost = iscsi_session_to_shost(session);
- struct iscsi_cls_host *ihost = shost->shost_data;
- struct iscsi_scan_data scan_data;
-@@ -506,11 +505,9 @@ static void iscsi_scan_session(struct work_struct *work)
- atomic_dec(&ihost->nr_scans);
- }
-
--static void session_recovery_timedout(struct work_struct *work)
-+static void session_recovery_timedout(void *data)
- {
-- struct iscsi_cls_session *session =
-- container_of(work, struct iscsi_cls_session,
-- recovery_work.work);
-+ struct iscsi_cls_session *session = data;
- unsigned long flags;
-
- iscsi_cls_session_printk(KERN_INFO, session,
-@@ -536,13 +533,13 @@ static void session_recovery_timedout(struct work_struct *work)
- scsi_target_unblock(&session->dev);
- }
-
--static void __iscsi_unblock_session(struct work_struct *work)
-+static void __iscsi_unblock_session(void *data)
- {
-- struct iscsi_cls_session *session =
-- container_of(work, struct iscsi_cls_session,
-- unblock_work);
-+ struct iscsi_cls_session *session = data;
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
- struct Scsi_Host *shost = iscsi_session_to_shost(session);
- struct iscsi_cls_host *ihost = shost->shost_data;
-+#endif
- unsigned long flags;
-
- /*
-@@ -560,10 +557,12 @@ static void __iscsi_unblock_session(struct work_struct *work)
- * the async scanning code (drivers like iscsi_tcp do login and
- * scanning from userspace).
- */
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
- if (shost->hostt->scan_finished) {
- if (queue_work(ihost->scan_workq, &session->scan_work))
- atomic_inc(&ihost->nr_scans);
- }
-+#endif
- }
-
- /**
-@@ -583,11 +582,9 @@ void iscsi_unblock_session(struct iscsi_cls_session *session)
- }
- EXPORT_SYMBOL_GPL(iscsi_unblock_session);
-
--static void __iscsi_block_session(struct work_struct *work)
-+static void __iscsi_block_session(void *data)
- {
-- struct iscsi_cls_session *session =
-- container_of(work, struct iscsi_cls_session,
-- block_work);
-+ struct iscsi_cls_session *session = data;
- unsigned long flags;
-
- spin_lock_irqsave(&session->lock, flags);
-@@ -604,11 +601,9 @@ void iscsi_block_session(struct iscsi_cls_session *session)
- }
- EXPORT_SYMBOL_GPL(iscsi_block_session);
-
--static void __iscsi_unbind_session(struct work_struct *work)
-+static void __iscsi_unbind_session(void *data)
- {
-- struct iscsi_cls_session *session =
-- container_of(work, struct iscsi_cls_session,
-- unbind_work);
-+ struct iscsi_cls_session *session = data;
- struct Scsi_Host *shost = iscsi_session_to_shost(session);
- struct iscsi_cls_host *ihost = shost->shost_data;
- unsigned long flags;
-@@ -651,12 +646,12 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
- session->transport = transport;
- session->recovery_tmo = 120;
- session->state = ISCSI_SESSION_FREE;
-- INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
-+ INIT_WORK(&session->recovery_work, session_recovery_timedout, session);
- INIT_LIST_HEAD(&session->sess_list);
-- INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
-- INIT_WORK(&session->block_work, __iscsi_block_session);
-- INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
-- INIT_WORK(&session->scan_work, iscsi_scan_session);
-+ INIT_WORK(&session->unblock_work, __iscsi_unblock_session, session);
-+ INIT_WORK(&session->block_work, __iscsi_block_session, session);
-+ INIT_WORK(&session->unbind_work, __iscsi_unbind_session, session);
-+ INIT_WORK(&session->scan_work, iscsi_scan_session, session);
- spin_lock_init(&session->lock);
-
- /* this is released in the dev's release function */
-@@ -1300,6 +1295,8 @@ static int
- iscsi_if_transport_ep(struct iscsi_transport *transport,
- struct iscsi_uevent *ev, int msg_type)
- {
-+ return -ENOSYS;
-+#if 0
- struct iscsi_endpoint *ep;
- struct sockaddr *dst_addr;
- int rc = 0;
-@@ -1340,6 +1337,8 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
- break;
- }
- return rc;
-+
-+#endif
- }
-
- static int
-@@ -1421,6 +1420,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- ev->u.c_session.queue_depth);
- break;
- case ISCSI_UEVENT_CREATE_BOUND_SESSION:
-+ err = -ENOSYS;
-+ break;
-+#if 0
- ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
- if (!ep) {
- err = -EINVAL;
-@@ -1432,6 +1434,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- ev->u.c_bound_session.cmds_max,
- ev->u.c_bound_session.queue_depth);
- break;
-+#endif
- case ISCSI_UEVENT_DESTROY_SESSION:
- session = iscsi_session_lookup(ev->u.d_session.sid);
- if (session)
-@@ -1514,55 +1517,70 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- }
-
- /*
-- * Get message from skb. Each message is processed by iscsi_if_recv_msg.
-- * Malformed skbs with wrong lengths or invalid creds are not processed.
-+ * Get message from skb (based on rtnetlink_rcv_skb). Each message is
-+ * processed by iscsi_if_recv_msg. Malformed skbs with wrong lengths or
-+ * invalid creds are discarded silently.
- */
- static void
--iscsi_if_rx(struct sk_buff *skb)
-+iscsi_if_rx(struct sock *sk, int len)
- {
-+ struct sk_buff *skb;
-+
- mutex_lock(&rx_queue_mutex);
-- while (skb->len >= NLMSG_SPACE(0)) {
-- int err;
-- uint32_t rlen;
-- struct nlmsghdr *nlh;
-- struct iscsi_uevent *ev;
--
-- nlh = nlmsg_hdr(skb);
-- if (nlh->nlmsg_len < sizeof(*nlh) ||
-- skb->len < nlh->nlmsg_len) {
-- break;
-+ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
-+ if (NETLINK_CREDS(skb)->uid) {
-+ skb_pull(skb, skb->len);
-+ goto free_skb;
- }
-
-- ev = NLMSG_DATA(nlh);
-- rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-- if (rlen > skb->len)
-- rlen = skb->len;
-+ while (skb->len >= NLMSG_SPACE(0)) {
-+ int err;
-+ uint32_t rlen;
-+ struct nlmsghdr *nlh;
-+ struct iscsi_uevent *ev;
-
-- err = iscsi_if_recv_msg(skb, nlh);
-- if (err) {
-- ev->type = ISCSI_KEVENT_IF_ERROR;
-- ev->iferror = err;
-- }
-- do {
-- /*
-- * special case for GET_STATS:
-- * on success - sending reply and stats from
-- * inside of if_recv_msg(),
-- * on error - fall through.
-- */
-- if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
-+ nlh = nlmsg_hdr(skb);
-+ if (nlh->nlmsg_len < sizeof(*nlh) ||
-+ skb->len < nlh->nlmsg_len) {
- break;
-- err = iscsi_if_send_reply(
-- NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
-- nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-- } while (err < 0 && err != -ECONNREFUSED);
-- skb_pull(skb, rlen);
-+ }
-+
-+ ev = NLMSG_DATA(nlh);
-+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-+ if (rlen > skb->len)
-+ rlen = skb->len;
-+
-+ err = iscsi_if_recv_msg(skb, nlh);
-+ if (err) {
-+ ev->type = ISCSI_KEVENT_IF_ERROR;
-+ ev->iferror = err;
-+ }
-+ do {
-+ /*
-+ * special case for GET_STATS:
-+ * on success - sending reply and stats from
-+ * inside of if_recv_msg(),
-+ * on error - fall through.
-+ */
-+ if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
-+ break;
-+ err = iscsi_if_send_reply(
-+ NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
-+ nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-+ } while (err < 0 && err != -ECONNREFUSED);
-+ skb_pull(skb, rlen);
-+ }
-+free_skb:
-+ kfree_skb(skb);
- }
- mutex_unlock(&rx_queue_mutex);
- }
-
-+#define iscsi_cdev_to_conn(_cdev) \
-+ iscsi_dev_to_conn(_cdev->dev)
-+
- #define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \
--struct device_attribute dev_attr_##_prefix##_##_name = \
-+struct class_device_attribute class_device_attr_##_prefix##_##_name = \
- __ATTR(_name,_mode,_show,_store)
-
- /*
-@@ -1570,10 +1588,9 @@ struct device_attribute dev_attr_##_prefix##_##_name = \
- */
- #define iscsi_conn_attr_show(param) \
- static ssize_t \
--show_conn_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_conn_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
-+ struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
- struct iscsi_transport *t = conn->transport; \
- return t->get_conn_param(conn, param, buf); \
- }
-@@ -1597,16 +1614,17 @@ iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
- iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
- iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
-
-+#define iscsi_cdev_to_session(_cdev) \
-+ iscsi_dev_to_session(_cdev->dev)
-+
- /*
- * iSCSI session attrs
- */
- #define iscsi_session_attr_show(param, perm) \
- static ssize_t \
--show_session_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_session_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_session *session = \
-- iscsi_dev_to_session(dev->parent); \
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
- struct iscsi_transport *t = session->transport; \
- \
- if (perm && !capable(CAP_SYS_ADMIN)) \
-@@ -1640,10 +1658,9 @@ iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
- iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
-
- static ssize_t
--show_priv_session_state(struct device *dev, struct device_attribute *attr,
-- char *buf)
-+show_priv_session_state(struct class_device *cdev, char *buf)
- {
-- struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);
- return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
- }
- static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-@@ -1651,11 +1668,9 @@ static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-
- #define iscsi_priv_session_attr_show(field, format) \
- static ssize_t \
--show_priv_session_##field(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_priv_session_##field(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_session *session = \
-- iscsi_dev_to_session(dev->parent); \
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\
- return sprintf(buf, format"\n", session->field); \
- }
-
-@@ -1670,10 +1685,9 @@ iscsi_priv_session_attr(recovery_tmo, "%d");
- */
- #define iscsi_host_attr_show(param) \
- static ssize_t \
--show_host_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_host_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct Scsi_Host *shost = transport_class_to_shost(dev); \
-+ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
- struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
- return priv->iscsi_transport->get_host_param(shost, param, buf); \
- }
-@@ -1690,7 +1704,7 @@ iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
-
- #define SETUP_PRIV_SESSION_RD_ATTR(field) \
- do { \
-- priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
-+ priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
- count++; \
- } while (0)
-
-@@ -1698,7 +1712,7 @@ do { \
- #define SETUP_SESSION_RD_ATTR(field, param_flag) \
- do { \
- if (tt->param_mask & param_flag) { \
-- priv->session_attrs[count] = &dev_attr_sess_##field; \
-+ priv->session_attrs[count] = &class_device_attr_sess_##field; \
- count++; \
- } \
- } while (0)
-@@ -1706,7 +1720,7 @@ do { \
- #define SETUP_CONN_RD_ATTR(field, param_flag) \
- do { \
- if (tt->param_mask & param_flag) { \
-- priv->conn_attrs[count] = &dev_attr_conn_##field; \
-+ priv->conn_attrs[count] = &class_device_attr_conn_##field; \
- count++; \
- } \
- } while (0)
-@@ -1714,7 +1728,7 @@ do { \
- #define SETUP_HOST_RD_ATTR(field, param_flag) \
- do { \
- if (tt->host_param_mask & param_flag) { \
-- priv->host_attrs[count] = &dev_attr_host_##field; \
-+ priv->host_attrs[count] = &class_device_attr_host_##field; \
- count++; \
- } \
- } while (0)
-@@ -1807,15 +1821,15 @@ iscsi_register_transport(struct iscsi_transport *tt)
- if (!(tt->caps & CAP_DATA_PATH_OFFLOAD))
- priv->t.create_work_queue = 1;
-
-- priv->dev.class = &iscsi_transport_class;
-- snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name);
-- err = device_register(&priv->dev);
-+ priv->cdev.class = &iscsi_transport_class;
-+ snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
-+ err = class_device_register(&priv->cdev);
- if (err)
- goto free_priv;
-
-- err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
-+ err = sysfs_create_group(&priv->cdev.kobj, &iscsi_transport_group);
- if (err)
-- goto unregister_dev;
-+ goto unregister_cdev;
-
- /* host parameters */
- priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
-@@ -1894,9 +1908,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
- printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
- return &priv->t;
-
--unregister_dev:
-- device_unregister(&priv->dev);
-- return NULL;
-+unregister_cdev:
-+ class_device_unregister(&priv->cdev);
- free_priv:
- kfree(priv);
- return NULL;
-@@ -1923,8 +1936,8 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
- transport_container_unregister(&priv->session_cont);
- transport_container_unregister(&priv->t.host_attrs);
-
-- sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
-- device_unregister(&priv->dev);
-+ sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
-+ class_device_unregister(&priv->cdev);
- mutex_unlock(&rx_queue_mutex);
-
- return 0;
-@@ -1944,13 +1957,14 @@ static __init int iscsi_transport_init(void)
- if (err)
- return err;
-
-+#if 0
- err = class_register(&iscsi_endpoint_class);
- if (err)
- goto unregister_transport_class;
--
-+#endif
- err = transport_class_register(&iscsi_host_class);
- if (err)
-- goto unregister_endpoint_class;
-+ goto unregister_transport_class;
-
- err = transport_class_register(&iscsi_connection_class);
- if (err)
-@@ -1981,8 +1995,10 @@ unregister_conn_class:
- transport_class_unregister(&iscsi_connection_class);
- unregister_host_class:
- transport_class_unregister(&iscsi_host_class);
-+#if 0
- unregister_endpoint_class:
- class_unregister(&iscsi_endpoint_class);
-+#endif
- unregister_transport_class:
- class_unregister(&iscsi_transport_class);
- return err;
-@@ -1995,7 +2011,9 @@ static void __exit iscsi_transport_exit(void)
- transport_class_unregister(&iscsi_connection_class);
- transport_class_unregister(&iscsi_session_class);
- transport_class_unregister(&iscsi_host_class);
-+#if 0
- class_unregister(&iscsi_endpoint_class);
-+#endif
- class_unregister(&iscsi_transport_class);
- }
-
-diff --git a/scsi_transport_iscsi.h b/scsi_transport_iscsi.h
-index b7652e3..3978551 100644
---- a/scsi_transport_iscsi.h
-+++ b/scsi_transport_iscsi.h
-@@ -28,6 +28,8 @@
- #include <linux/mutex.h>
- #include "iscsi_if.h"
-
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct iscsi_transport;
- struct iscsi_endpoint;
-@@ -175,7 +177,7 @@ struct iscsi_cls_session {
-
- /* recovery fields */
- int recovery_tmo;
-- struct delayed_work recovery_work;
-+ struct work_struct recovery_work;
-
- unsigned int target_id;
-
diff --git a/kernel/2.6.20-21_compat.patch b/kernel/2.6.20-21_compat.patch
deleted file mode 100644
index b71247e..0000000
--- a/kernel/2.6.20-21_compat.patch
+++ /dev/null
@@ -1,1015 +0,0 @@
-diff --git a/iscsi_tcp.c b/iscsi_tcp.c
-index 6214055..8563545 100644
---- a/iscsi_tcp.c
-+++ b/iscsi_tcp.c
-@@ -444,11 +444,9 @@ static int iscsi_sw_tcp_pdu_init(struct iscsi_task *task,
- if (!task->sc)
- iscsi_sw_tcp_send_linear_data_prep(conn, task->data, count);
- else {
-- struct scsi_data_buffer *sdb = scsi_out(task->sc);
--
-- err = iscsi_sw_tcp_send_data_prep(conn, sdb->table.sgl,
-- sdb->table.nents, offset,
-- count);
-+ err = iscsi_sw_tcp_send_data_prep(conn, scsi_sglist(task->sc),
-+ scsi_sg_count(task->sc),
-+ offset, count);
- }
-
- if (err) {
-@@ -773,7 +771,11 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
- shost->max_lun = iscsi_max_lun;
- shost->max_id = 0;
- shost->max_channel = 0;
-+#ifndef SCSI_MAX_VARLEN_CDB_SIZE
-+ shost->max_cmd_len = 16;
-+#else
- shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE;
-+#endif
-
- if (iscsi_host_add(shost, NULL))
- goto free_host;
-@@ -821,6 +823,9 @@ static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev)
- }
-
- static struct scsi_host_template iscsi_sw_tcp_sht = {
-+#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,24)
-+ .use_sg_chaining = ENABLE_SG_CHAINING,
-+#endif
- .module = THIS_MODULE,
- .name = "iSCSI Initiator over TCP/IP",
- .queuecommand = iscsi_queuecommand,
-@@ -831,7 +836,7 @@ static struct scsi_host_template iscsi_sw_tcp_sht = {
- .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
- .eh_abort_handler = iscsi_eh_abort,
- .eh_device_reset_handler= iscsi_eh_device_reset,
-- .eh_target_reset_handler= iscsi_eh_target_reset,
-+ .eh_host_reset_handler = iscsi_eh_target_reset,
- .use_clustering = DISABLE_CLUSTERING,
- .slave_configure = iscsi_sw_tcp_slave_configure,
- .proc_name = "iscsi_tcp",
-diff --git a/iscsi_tcp.h b/iscsi_tcp.h
-index f9a4044..ab20530 100644
---- a/iscsi_tcp.h
-+++ b/iscsi_tcp.h
-@@ -22,6 +22,8 @@
- #ifndef ISCSI_SW_TCP_H
- #define ISCSI_SW_TCP_H
-
-+#include "open_iscsi_compat.h"
-+
- #include "libiscsi.h"
- #include "libiscsi_tcp.h"
-
-diff --git a/libiscsi.c b//libiscsi.c
-index 5ac73fb..0b22b75 100644
---- a/libiscsi.c
-+++ b/libiscsi.c
-@@ -38,6 +38,8 @@
- #include "scsi_transport_iscsi.h"
- #include "libiscsi.h"
-
-+#include "open_iscsi_compat.h"
-+
- /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
- #define SNA32_CHECK 2147483648UL
-
-@@ -199,7 +201,7 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
- sizeof(rlen_ahdr->reserved));
- rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
- rlen_ahdr->reserved = 0;
-- rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
-+ rlen_ahdr->read_length = cpu_to_be32(scsi_bufflen(sc));
-
- debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
- "rlen_ahdr->ahslength(%d)\n",
-@@ -267,7 +269,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- return rc;
- }
- if (sc->sc_data_direction == DMA_TO_DEVICE) {
-- unsigned out_len = scsi_out(sc)->length;
-+ unsigned out_len = scsi_bufflen(sc);
- struct iscsi_r2t_info *r2t = &task->unsol_r2t;
-
- hdr->data_length = cpu_to_be32(out_len);
-@@ -313,7 +315,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- } else {
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- zero_data(hdr->dlength);
-- hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
-+ hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
-
- if (sc->sc_data_direction == DMA_FROM_DEVICE)
- hdr->flags |= ISCSI_FLAG_CMD_READ;
-@@ -340,7 +342,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ?
- "write" : "read", conn->id, sc, sc->cmnd[0], task->itt,
- scsi_bufflen(sc),
-- scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
-+ scsi_bidi_cmnd(sc) ? scsi_bufflen(sc) : 0,
- session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
- return 0;
- }
-@@ -432,12 +434,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task,
- conn->session->queued_cmdsn--;
-
- sc->result = err;
-- if (!scsi_bidi_cmnd(sc))
-- scsi_set_resid(sc, scsi_bufflen(sc));
-- else {
-- scsi_out(sc)->resid = scsi_out(sc)->length;
-- scsi_in(sc)->resid = scsi_in(sc)->length;
-- }
-+ scsi_set_resid(sc, scsi_bufflen(sc));
-
- if (conn->task == task)
- conn->task = NULL;
-@@ -631,7 +628,7 @@ invalid_datalen:
- goto out;
- }
-
-- senselen = get_unaligned_be16(data);
-+ senselen = be16_to_cpu(get_unaligned((__be16 *) data));
- if (datalen < senselen)
- goto invalid_datalen;
-
-@@ -647,8 +644,8 @@ invalid_datalen:
-
- if (scsi_bidi_cmnd(sc) && res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
-- res_count <= scsi_in(sc)->length))
-- scsi_in(sc)->resid = res_count;
-+ res_count <= scsi_bufflen(sc)))
-+ scsi_set_resid(sc, res_count);
- else
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- }
-@@ -697,8 +694,8 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
-
- if (res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
-- res_count <= scsi_in(sc)->length))
-- scsi_in(sc)->resid = res_count;
-+ res_count <= scsi_bufflen(sc)))
-+ scsi_set_resid(sc, res_count);
- else
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- }
-@@ -1408,12 +1405,7 @@ prepd_fault:
- fault:
- spin_unlock(&session->lock);
- debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
-- if (!scsi_bidi_cmnd(sc))
-- scsi_set_resid(sc, scsi_bufflen(sc));
-- else {
-- scsi_out(sc)->resid = scsi_out(sc)->length;
-- scsi_in(sc)->resid = scsi_in(sc)->length;
-- }
-+ scsi_set_resid(sc, scsi_bufflen(sc));
- done(sc);
- spin_lock(host->host_lock);
- return 0;
-diff --git a/libiscsi.h b/libiscsi.h
-index a261e2c..96fd795 100644
---- a/libiscsi.h
-+++ b/libiscsi.h
-@@ -32,6 +32,8 @@
- #include "iscsi_if.h"
- #include "scsi_transport_iscsi.h"
-
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct scsi_host_template;
- struct scsi_device;
-diff --git a/libiscsi_tcp.c b/libiscsi_tcp.c
-index 92cb13d..ea7dd8d 100644
---- a/libiscsi_tcp.c
-+++ b/libiscsi_tcp.c
-@@ -357,6 +357,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment,
-
- debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
- offset, size);
-+
-+ /*
-+ * older kernels could send use_sg=0 for commands like sgio
-+ * or scsi-ml commands.
-+ */
-+ if (!sg_count) {
-+ iscsi_segment_init_linear(segment, (void *)sg_list + offset,
-+ size, done, hash);
-+ return 0;
-+ }
-+
- __iscsi_segment_init(segment, size, done, hash);
- for_each_sg(sg_list, sg, sg_count, i) {
- debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
-@@ -469,7 +480,7 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
- int datasn = be32_to_cpu(rhdr->datasn);
-- unsigned total_in_length = scsi_in(task->sc)->length;
-+ unsigned total_in_length = scsi_bufflen(task->sc);
-
- iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
- if (tcp_conn->in.datalen == 0)
-@@ -557,11 +568,11 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- r2t->data_length, session->max_burst);
-
- r2t->data_offset = be32_to_cpu(rhdr->data_offset);
-- if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
-+ if (r2t->data_offset + r2t->data_length > scsi_bufflen(task->sc)) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with data len %u at offset %u "
- "and total length %d\n", r2t->data_length,
-- r2t->data_offset, scsi_out(task->sc)->length);
-+ r2t->data_offset, scsi_bufflen(task->sc));
- __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
-@@ -660,7 +671,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- if (tcp_conn->in.datalen) {
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct hash_desc *rx_hash = NULL;
-- struct scsi_data_buffer *sdb = scsi_in(task->sc);
-
- /*
- * Setup copy of Data-In into the Scsi_Cmnd
-@@ -679,8 +689,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- tcp_task->data_offset,
- tcp_conn->in.datalen);
- rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
-- sdb->table.sgl,
-- sdb->table.nents,
-+ scsi_sglist(task->sc),
-+ scsi_sg_count(task->sc),
- tcp_task->data_offset,
- tcp_conn->in.datalen,
- iscsi_tcp_process_data_in,
-diff --git a/libiscsi_tcp.h b/libiscsi_tcp.h
-index 3bacef5..5ea284d 100644
---- a/libiscsi_tcp.h
-+++ b/libiscsi_tcp.h
-@@ -21,6 +21,7 @@
- #ifndef LIBISCSI_TCP_H
- #define LIBISCSI_TCP_H
-
-+#include "open_iscsi_compat.h"
- #include "libiscsi.h"
-
- struct iscsi_tcp_conn;
-diff --git a/open_iscsi_compat.h b/open_iscsi_compat.h
-new file mode 100644
-index 0000000..fd9ef7b
---- /dev/null
-+++ b/open_iscsi_compat.h
-@@ -0,0 +1,266 @@
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <scsi/scsi.h>
-+#include <scsi/scsi_cmnd.h>
-+
-+#ifndef OPEN_ISCSI_COMPAT
-+#define OPEN_ISCSI_COMPAT
-+
-+#ifndef SCAN_WILD_CARD
-+#define SCAN_WILD_CARD ~0
-+#endif
-+
-+#ifndef NIPQUAD_FMT
-+#define NIPQUAD_FMT "%u.%u.%u.%u"
-+#endif
-+
-+#ifndef NIP6_FMT
-+#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-+#endif
-+
-+#ifndef DEFINE_MUTEX
-+
-+/* mutex changes from 2.6.16-rc1 and up */
-+#define DEFINE_MUTEX DECLARE_MUTEX
-+#define mutex_lock down
-+#define mutex_unlock up
-+#define mutex semaphore
-+#define mutex_init init_MUTEX
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12)
-+
-+void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun)
-+{
-+ int i;
-+
-+ memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
-+
-+ for (i = 0; i < sizeof(lun); i += 2) {
-+ scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
-+ scsilun->scsi_lun[i+1] = lun & 0xFF;
-+ lun = lun >> 16;
-+ }
-+}
-+
-+#define __nlmsg_put(skb, daemon_pid, seq, type, len, flags) \
-+ __nlmsg_put(skb, daemon_pid, 0, 0, len)
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define gfp_t unsigned
-+
-+void *kzalloc(size_t size, gfp_t flags)
-+{
-+ void *ret = kmalloc(size, flags);
-+ if (ret)
-+ memset(ret, 0, size);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+
-+#include "linux/crypto.h"
-+
-+#define CRYPTO_ALG_ASYNC 0x00000080
-+struct hash_desc
-+{
-+ struct crypto_tfm *tfm;
-+ u32 flags;
-+};
-+
-+static inline int crypto_hash_init(struct hash_desc *desc)
-+{
-+ crypto_digest_init(desc->tfm);
-+ return 0;
-+}
-+
-+static inline int crypto_hash_digest(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes, u8 *out)
-+{
-+ crypto_digest_digest(desc->tfm, sg, 1, out);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_update(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes)
-+{
-+ crypto_digest_update(desc->tfm, sg, 1);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
-+{
-+ crypto_digest_final(desc->tfm, out);
-+ return 0;
-+}
-+
-+static inline struct crypto_tfm *crypto_alloc_hash(const char *alg_name,
-+ u32 type, u32 mask)
-+{
-+ struct crypto_tfm *ret = crypto_alloc_tfm(alg_name ,type);
-+ return ret ? ret : ERR_PTR(-ENOMEM);
-+}
-+
-+static inline void crypto_free_hash(struct crypto_tfm *tfm)
-+{
-+ crypto_free_tfm(tfm);
-+}
-+
-+int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 0);
-+}
-+
-+int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 1);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
-+
-+static inline int is_power_of_2(unsigned long n)
-+{
-+ return (n != 0 && ((n & (n - 1)) == 0));
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
-+{
-+ return (struct nlmsghdr *)skb->data;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+ return (void *)shost->hostdata;
-+}
-+
-+/*
-+ * Note: We do not support bidi for the compat modules if the kernel
-+ * does not have support.
-+ */
-+#define scsi_sg_count(cmd) ((cmd)->use_sg)
-+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
-+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
-+
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+ cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+ return cmd->resid;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+static inline unsigned long rounddown_pow_of_two(unsigned long n)
-+{
-+ return 1UL << (fls_long(n) - 1);
-+}
-+
-+
-+static inline struct scatterlist *sg_next(struct scatterlist *sg)
-+{
-+ if (!sg) {
-+ BUG();
-+ return NULL;
-+ }
-+ return sg + 1;
-+}
-+
-+#define for_each_sg(sglist, sg, nr, __i) \
-+ for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
-+
-+#define sg_page(_sg) _sg->page
-+
-+static inline void sg_set_page(struct scatterlist *sg, struct page *page,
-+ unsigned int len, unsigned int offset)
-+{
-+ sg->page = page;
-+ sg->offset = offset;
-+ sg->length = len;
-+}
-+
-+static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
-+{
-+ memset(sgl, 0, sizeof(*sgl) * nents);
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
-+
-+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
-+{
-+ return 0;
-+}
-+
-+#define netlink_kernel_release(_nls) \
-+ sock_release(_nls->sk_socket)
-+
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, input)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#endif
-+
-+#ifndef DID_TRANSPORT_DISRUPTED
-+#define DID_TRANSPORT_DISRUPTED DID_BUS_BUSY
-+#endif
-+
-+#ifndef DID_TRANSPORT_FAILFAST
-+#define DID_TRANSPORT_FAILFAST DID_NO_CONNECT
-+#endif
-+
-+#ifndef SCSI_MLQUEUE_TARGET_BUSY
-+#define SCSI_MLQUEUE_TARGET_BUSY SCSI_MLQUEUE_HOST_BUSY
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)
-+
-+#define BLK_EH_NOT_HANDLED EH_NOT_HANDLED
-+#define BLK_EH_RESET_TIMER EH_RESET_TIMER
-+
-+#define blk_eh_timer_return scsi_eh_timer_return
-+
-+#endif
-+
-+#endif
-diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c
-index 4781d81..023daf5 100644
---- a/scsi_transport_iscsi.c
-+++ b/scsi_transport_iscsi.c
-@@ -41,13 +41,13 @@ struct iscsi_internal {
- struct scsi_transport_template t;
- struct iscsi_transport *iscsi_transport;
- struct list_head list;
-- struct device dev;
-+ struct class_device cdev;
-
-- struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
-+ struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
- struct transport_container conn_cont;
-- struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
-+ struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
- struct transport_container session_cont;
-- struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
-+ struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
- };
-
- static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
-@@ -64,12 +64,12 @@ static DEFINE_SPINLOCK(iscsi_transport_lock);
- #define to_iscsi_internal(tmpl) \
- container_of(tmpl, struct iscsi_internal, t)
-
--#define dev_to_iscsi_internal(_dev) \
-- container_of(_dev, struct iscsi_internal, dev)
-+#define cdev_to_iscsi_internal(_cdev) \
-+ container_of(_cdev, struct iscsi_internal, cdev)
-
--static void iscsi_transport_release(struct device *dev)
-+static void iscsi_transport_release(struct class_device *cdev)
- {
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- kfree(priv);
- }
-
-@@ -79,33 +79,31 @@ static void iscsi_transport_release(struct device *dev)
- */
- static struct class iscsi_transport_class = {
- .name = "iscsi_transport",
-- .dev_release = iscsi_transport_release,
-+ .release = iscsi_transport_release,
- };
-
- static ssize_t
--show_transport_handle(struct device *dev, struct device_attribute *attr,
-- char *buf)
-+show_transport_handle(struct class_device *cdev, char *buf)
- {
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
- }
--static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-+static CLASS_DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-
- #define show_transport_attr(name, format) \
- static ssize_t \
--show_transport_##name(struct device *dev, \
-- struct device_attribute *attr,char *buf) \
-+show_transport_##name(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev); \
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev); \
- return sprintf(buf, format"\n", priv->iscsi_transport->name); \
- } \
--static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-
- show_transport_attr(caps, "0x%x");
-
- static struct attribute *iscsi_transport_attrs[] = {
-- &dev_attr_handle.attr,
-- &dev_attr_caps.attr,
-+ &class_device_attr_handle.attr,
-+ &class_device_attr_caps.attr,
- NULL,
- };
-
-@@ -113,6 +111,7 @@ static struct attribute_group iscsi_transport_group = {
- .attrs = iscsi_transport_attrs,
- };
-
-+#if 0
- /*
- * iSCSI endpoint attrs
- */
-@@ -236,9 +235,10 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
- return ep;
- }
- EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
-+#endif
-
- static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
-- struct device *cdev)
-+ struct class_device *cdev)
- {
- struct Scsi_Host *shost = dev_to_shost(dev);
- struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -257,7 +257,7 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
- }
-
- static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
-- struct device *cdev)
-+ struct class_device *cdev)
- {
- struct Scsi_Host *shost = dev_to_shost(dev);
- struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -723,7 +723,8 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
- }
- session->target_id = id;
-
-- dev_set_name(&session->dev, "session%u", session->sid);
-+ snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
-+ session->sid);
- err = device_add(&session->dev);
- if (err) {
- iscsi_cls_session_printk(KERN_ERR, session,
-@@ -896,7 +897,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
- if (!get_device(&session->dev))
- goto free_conn;
-
-- dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid);
-+ snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
-+ session->sid, cid);
- conn->dev.parent = &session->dev;
- conn->dev.release = iscsi_conn_release;
- err = device_register(&conn->dev);
-@@ -1305,6 +1307,8 @@ static int
- iscsi_if_transport_ep(struct iscsi_transport *transport,
- struct iscsi_uevent *ev, int msg_type)
- {
-+ return -ENOSYS;
-+#if 0
- struct iscsi_endpoint *ep;
- struct sockaddr *dst_addr;
- int rc = 0;
-@@ -1345,6 +1349,8 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
- break;
- }
- return rc;
-+
-+#endif
- }
-
- static int
-@@ -1426,6 +1432,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- ev->u.c_session.queue_depth);
- break;
- case ISCSI_UEVENT_CREATE_BOUND_SESSION:
-+ err = -ENOSYS;
-+ break;
-+#if 0
- ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
- if (!ep) {
- err = -EINVAL;
-@@ -1437,6 +1446,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- ev->u.c_bound_session.cmds_max,
- ev->u.c_bound_session.queue_depth);
- break;
-+#endif
- case ISCSI_UEVENT_DESTROY_SESSION:
- session = iscsi_session_lookup(ev->u.d_session.sid);
- if (session)
-@@ -1519,55 +1529,70 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
- }
-
- /*
-- * Get message from skb. Each message is processed by iscsi_if_recv_msg.
-- * Malformed skbs with wrong lengths or invalid creds are not processed.
-+ * Get message from skb (based on rtnetlink_rcv_skb). Each message is
-+ * processed by iscsi_if_recv_msg. Malformed skbs with wrong lengths or
-+ * invalid creds are discarded silently.
- */
- static void
--iscsi_if_rx(struct sk_buff *skb)
-+iscsi_if_rx(struct sock *sk, int len)
- {
-+ struct sk_buff *skb;
-+
- mutex_lock(&rx_queue_mutex);
-- while (skb->len >= NLMSG_SPACE(0)) {
-- int err;
-- uint32_t rlen;
-- struct nlmsghdr *nlh;
-- struct iscsi_uevent *ev;
--
-- nlh = nlmsg_hdr(skb);
-- if (nlh->nlmsg_len < sizeof(*nlh) ||
-- skb->len < nlh->nlmsg_len) {
-- break;
-+ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
-+ if (NETLINK_CREDS(skb)->uid) {
-+ skb_pull(skb, skb->len);
-+ goto free_skb;
- }
-
-- ev = NLMSG_DATA(nlh);
-- rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-- if (rlen > skb->len)
-- rlen = skb->len;
-+ while (skb->len >= NLMSG_SPACE(0)) {
-+ int err;
-+ uint32_t rlen;
-+ struct nlmsghdr *nlh;
-+ struct iscsi_uevent *ev;
-
-- err = iscsi_if_recv_msg(skb, nlh);
-- if (err) {
-- ev->type = ISCSI_KEVENT_IF_ERROR;
-- ev->iferror = err;
-- }
-- do {
-- /*
-- * special case for GET_STATS:
-- * on success - sending reply and stats from
-- * inside of if_recv_msg(),
-- * on error - fall through.
-- */
-- if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
-+ nlh = nlmsg_hdr(skb);
-+ if (nlh->nlmsg_len < sizeof(*nlh) ||
-+ skb->len < nlh->nlmsg_len) {
- break;
-- err = iscsi_if_send_reply(
-- NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
-- nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-- } while (err < 0 && err != -ECONNREFUSED);
-- skb_pull(skb, rlen);
-+ }
-+
-+ ev = NLMSG_DATA(nlh);
-+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-+ if (rlen > skb->len)
-+ rlen = skb->len;
-+
-+ err = iscsi_if_recv_msg(skb, nlh);
-+ if (err) {
-+ ev->type = ISCSI_KEVENT_IF_ERROR;
-+ ev->iferror = err;
-+ }
-+ do {
-+ /*
-+ * special case for GET_STATS:
-+ * on success - sending reply and stats from
-+ * inside of if_recv_msg(),
-+ * on error - fall through.
-+ */
-+ if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
-+ break;
-+ err = iscsi_if_send_reply(
-+ NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
-+ nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-+ } while (err < 0 && err != -ECONNREFUSED);
-+ skb_pull(skb, rlen);
-+ }
-+free_skb:
-+ kfree_skb(skb);
- }
- mutex_unlock(&rx_queue_mutex);
- }
-
-+#define iscsi_cdev_to_conn(_cdev) \
-+ iscsi_dev_to_conn(_cdev->dev)
-+
- #define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \
--struct device_attribute dev_attr_##_prefix##_##_name = \
-+struct class_device_attribute class_device_attr_##_prefix##_##_name = \
- __ATTR(_name,_mode,_show,_store)
-
- /*
-@@ -1575,10 +1600,9 @@ struct device_attribute dev_attr_##_prefix##_##_name = \
- */
- #define iscsi_conn_attr_show(param) \
- static ssize_t \
--show_conn_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_conn_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
-+ struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
- struct iscsi_transport *t = conn->transport; \
- return t->get_conn_param(conn, param, buf); \
- }
-@@ -1602,16 +1626,17 @@ iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
- iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
- iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
-
-+#define iscsi_cdev_to_session(_cdev) \
-+ iscsi_dev_to_session(_cdev->dev)
-+
- /*
- * iSCSI session attrs
- */
- #define iscsi_session_attr_show(param, perm) \
- static ssize_t \
--show_session_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_session_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_session *session = \
-- iscsi_dev_to_session(dev->parent); \
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
- struct iscsi_transport *t = session->transport; \
- \
- if (perm && !capable(CAP_SYS_ADMIN)) \
-@@ -1645,10 +1670,9 @@ iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
- iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
-
- static ssize_t
--show_priv_session_state(struct device *dev, struct device_attribute *attr,
-- char *buf)
-+show_priv_session_state(struct class_device *cdev, char *buf)
- {
-- struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);
- return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
- }
- static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-@@ -1656,11 +1680,9 @@ static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-
- #define iscsi_priv_session_attr_show(field, format) \
- static ssize_t \
--show_priv_session_##field(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_priv_session_##field(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_session *session = \
-- iscsi_dev_to_session(dev->parent); \
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\
- return sprintf(buf, format"\n", session->field); \
- }
-
-@@ -1675,10 +1697,9 @@ iscsi_priv_session_attr(recovery_tmo, "%d");
- */
- #define iscsi_host_attr_show(param) \
- static ssize_t \
--show_host_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_host_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct Scsi_Host *shost = transport_class_to_shost(dev); \
-+ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
- struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
- return priv->iscsi_transport->get_host_param(shost, param, buf); \
- }
-@@ -1695,7 +1716,7 @@ iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
-
- #define SETUP_PRIV_SESSION_RD_ATTR(field) \
- do { \
-- priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
-+ priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
- count++; \
- } while (0)
-
-@@ -1703,7 +1724,7 @@ do { \
- #define SETUP_SESSION_RD_ATTR(field, param_flag) \
- do { \
- if (tt->param_mask & param_flag) { \
-- priv->session_attrs[count] = &dev_attr_sess_##field; \
-+ priv->session_attrs[count] = &class_device_attr_sess_##field; \
- count++; \
- } \
- } while (0)
-@@ -1711,7 +1732,7 @@ do { \
- #define SETUP_CONN_RD_ATTR(field, param_flag) \
- do { \
- if (tt->param_mask & param_flag) { \
-- priv->conn_attrs[count] = &dev_attr_conn_##field; \
-+ priv->conn_attrs[count] = &class_device_attr_conn_##field; \
- count++; \
- } \
- } while (0)
-@@ -1719,7 +1740,7 @@ do { \
- #define SETUP_HOST_RD_ATTR(field, param_flag) \
- do { \
- if (tt->host_param_mask & param_flag) { \
-- priv->host_attrs[count] = &dev_attr_host_##field; \
-+ priv->host_attrs[count] = &class_device_attr_host_##field; \
- count++; \
- } \
- } while (0)
-@@ -1812,15 +1833,15 @@ iscsi_register_transport(struct iscsi_transport *tt)
- if (!(tt->caps & CAP_DATA_PATH_OFFLOAD))
- priv->t.create_work_queue = 1;
-
-- priv->dev.class = &iscsi_transport_class;
-- dev_set_name(&priv->dev, "%s", tt->name);
-- err = device_register(&priv->dev);
-+ priv->cdev.class = &iscsi_transport_class;
-+ snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
-+ err = class_device_register(&priv->cdev);
- if (err)
- goto free_priv;
-
-- err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
-+ err = sysfs_create_group(&priv->cdev.kobj, &iscsi_transport_group);
- if (err)
-- goto unregister_dev;
-+ goto unregister_cdev;
-
- /* host parameters */
- priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
-@@ -1899,9 +1920,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
- printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
- return &priv->t;
-
--unregister_dev:
-- device_unregister(&priv->dev);
-- return NULL;
-+unregister_cdev:
-+ class_device_unregister(&priv->cdev);
- free_priv:
- kfree(priv);
- return NULL;
-@@ -1928,8 +1948,8 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
- transport_container_unregister(&priv->session_cont);
- transport_container_unregister(&priv->t.host_attrs);
-
-- sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
-- device_unregister(&priv->dev);
-+ sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
-+ class_device_unregister(&priv->cdev);
- mutex_unlock(&rx_queue_mutex);
-
- return 0;
-@@ -1949,13 +1969,14 @@ static __init int iscsi_transport_init(void)
- if (err)
- return err;
-
-+#if 0
- err = class_register(&iscsi_endpoint_class);
- if (err)
- goto unregister_transport_class;
--
-+#endif
- err = transport_class_register(&iscsi_host_class);
- if (err)
-- goto unregister_endpoint_class;
-+ goto unregister_transport_class;
-
- err = transport_class_register(&iscsi_connection_class);
- if (err)
-@@ -1986,8 +2007,10 @@ unregister_conn_class:
- transport_class_unregister(&iscsi_connection_class);
- unregister_host_class:
- transport_class_unregister(&iscsi_host_class);
-+#if 0
- unregister_endpoint_class:
- class_unregister(&iscsi_endpoint_class);
-+#endif
- unregister_transport_class:
- class_unregister(&iscsi_transport_class);
- return err;
-@@ -2000,7 +2023,9 @@ static void __exit iscsi_transport_exit(void)
- transport_class_unregister(&iscsi_connection_class);
- transport_class_unregister(&iscsi_session_class);
- transport_class_unregister(&iscsi_host_class);
-+#if 0
- class_unregister(&iscsi_endpoint_class);
-+#endif
- class_unregister(&iscsi_transport_class);
- }
-
-diff --git a/scsi_transport_iscsi.h b/scsi_transport_iscsi.h
-index 27d067a..41a54c8 100644
---- a/scsi_transport_iscsi.h
-+++ b//scsi_transport_iscsi.h
-@@ -28,6 +28,8 @@
- #include <linux/mutex.h>
- #include "iscsi_if.h"
-
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct iscsi_transport;
- struct iscsi_endpoint;
---
-1.6.0.4
-
diff --git a/kernel/2.6.24_compat.patch b/kernel/2.6.24_compat.patch
deleted file mode 100644
index 494605c..0000000
--- a/kernel/2.6.24_compat.patch
+++ /dev/null
@@ -1,1177 +0,0 @@
-diff --git a/iscsi_tcp.c b/iscsi_tcp.c
-index 2a401b9..bb027e4 100644
---- a/iscsi_tcp.c
-+++ b/iscsi_tcp.c
-@@ -43,6 +43,7 @@
- #include <scsi/scsi.h>
- #include "scsi_transport_iscsi.h"
-
-+#include "open_iscsi_compat.h"
- #include "iscsi_tcp.h"
-
- MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
-@@ -480,11 +481,9 @@ static int iscsi_sw_tcp_pdu_init(struct iscsi_task *task,
- if (!task->sc)
- iscsi_sw_tcp_send_linear_data_prep(conn, task->data, count);
- else {
-- struct scsi_data_buffer *sdb = scsi_out(task->sc);
--
-- err = iscsi_sw_tcp_send_data_prep(conn, sdb->table.sgl,
-- sdb->table.nents, offset,
-- count);
-+ err = iscsi_sw_tcp_send_data_prep(conn, scsi_sglist(task->sc),
-+ scsi_sg_count(task->sc),
-+ offset, count);
- }
-
- if (err) {
-@@ -821,7 +820,11 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
- shost->max_lun = iscsi_max_lun;
- shost->max_id = 0;
- shost->max_channel = 0;
-+#ifndef SCSI_MAX_VARLEN_CDB_SIZE
-+ shost->max_cmd_len = 16;
-+#else
- shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE;
-+#endif
-
- if (iscsi_host_add(shost, NULL))
- goto free_host;
-@@ -874,6 +877,9 @@ static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev)
- }
-
- static struct scsi_host_template iscsi_sw_tcp_sht = {
-+#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,24)
-+ .use_sg_chaining = ENABLE_SG_CHAINING,
-+#endif
- .module = THIS_MODULE,
- .name = "iSCSI Initiator over TCP/IP",
- .queuecommand = iscsi_queuecommand,
-@@ -884,7 +890,7 @@ static struct scsi_host_template iscsi_sw_tcp_sht = {
- .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
- .eh_abort_handler = iscsi_eh_abort,
- .eh_device_reset_handler= iscsi_eh_device_reset,
-- .eh_target_reset_handler = iscsi_eh_recover_target,
-+ .eh_host_reset_handler = iscsi_eh_recover_target,
- .use_clustering = DISABLE_CLUSTERING,
- .slave_alloc = iscsi_sw_tcp_slave_alloc,
- .slave_configure = iscsi_sw_tcp_slave_configure,
-diff --git a/iscsi_tcp.h b/iscsi_tcp.h
-index 2a1cf23..32d7edd 100644
---- a/iscsi_tcp.h
-+++ b/iscsi_tcp.h
-@@ -22,6 +22,8 @@
- #ifndef ISCSI_SW_TCP_H
- #define ISCSI_SW_TCP_H
-
-+#include "open_iscsi_compat.h"
-+
- #include "libiscsi.h"
- #include "libiscsi_tcp.h"
-
-diff --git a/libiscsi.c b/libiscsi.c
-index 59e3a5f..1c8d00d 100644
---- a/libiscsi.c
-+++ b/libiscsi.c
-@@ -84,6 +84,8 @@ MODULE_PARM_DESC(debug_libiscsi_eh,
- __func__, ##arg); \
- } while (0);
-
-+#include "open_iscsi_compat.h"
-+
- /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
- #define SNA32_CHECK 2147483648UL
-
-@@ -256,7 +258,7 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
- sizeof(rlen_ahdr->reserved));
- rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
- rlen_ahdr->reserved = 0;
-- rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
-+ rlen_ahdr->read_length = cpu_to_be32(scsi_bufflen(sc));
-
- ISCSI_DBG_SESSION(task->conn->session,
- "bidi-in rlen_ahdr->read_length(%d) "
-@@ -411,7 +413,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- return rc;
- }
- if (sc->sc_data_direction == DMA_TO_DEVICE) {
-- unsigned out_len = scsi_out(sc)->length;
-+ unsigned out_len = scsi_bufflen(sc);
- struct iscsi_r2t_info *r2t = &task->unsol_r2t;
-
- hdr->data_length = cpu_to_be32(out_len);
-@@ -457,7 +459,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- } else {
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- zero_data(hdr->dlength);
-- hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
-+ hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
-
- if (sc->sc_data_direction == DMA_FROM_DEVICE)
- hdr->flags |= ISCSI_FLAG_CMD_READ;
-@@ -486,7 +488,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
- sc->sc_data_direction == DMA_TO_DEVICE ?
- "write" : "read", conn->id, sc, sc->cmnd[0],
- task->itt, scsi_bufflen(sc),
-- scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
-+ scsi_bidi_cmnd(sc) ? scsi_bufflen(sc) : 0,
- session->cmdsn,
- session->max_cmdsn - session->exp_cmdsn + 1);
- return 0;
-@@ -518,7 +520,7 @@ static void iscsi_free_task(struct iscsi_task *task)
- if (conn->login_task == task)
- return;
-
-- kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
-+ __kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
-
- if (sc) {
- task->sc = NULL;
-@@ -648,12 +650,7 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
- state = ISCSI_TASK_ABRT_TMF;
-
- sc->result = err << 16;
-- if (!scsi_bidi_cmnd(sc))
-- scsi_set_resid(sc, scsi_bufflen(sc));
-- else {
-- scsi_out(sc)->resid = scsi_out(sc)->length;
-- scsi_in(sc)->resid = scsi_in(sc)->length;
-- }
-+ scsi_set_resid(sc, scsi_bufflen(sc));
-
- iscsi_complete_task(task, state);
- }
-@@ -738,7 +735,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
- BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
-
-- if (!kfifo_out(&session->cmdpool.queue,
-+ if (!__kfifo_get(session->cmdpool.queue,
- (void*)&task, sizeof(void*)))
- return NULL;
- }
-@@ -853,7 +850,7 @@ invalid_datalen:
- goto out;
- }
-
-- senselen = get_unaligned_be16(data);
-+ senselen = be16_to_cpu(get_unaligned((__be16 *) data));
- if (datalen < senselen)
- goto invalid_datalen;
-
-@@ -870,8 +867,8 @@ invalid_datalen:
-
- if (scsi_bidi_cmnd(sc) && res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
-- res_count <= scsi_in(sc)->length))
-- scsi_in(sc)->resid = res_count;
-+ res_count <= scsi_bufflen(sc)))
-+ scsi_set_resid(sc, res_count);
- else
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- }
-@@ -920,8 +917,8 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
-
- if (res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
-- res_count <= scsi_in(sc)->length))
-- scsi_in(sc)->resid = res_count;
-+ res_count <= scsi_bufflen(sc)))
-+ scsi_set_resid(sc, res_count);
- else
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- }
-@@ -1568,7 +1565,7 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
- {
- struct iscsi_task *task;
-
-- if (!kfifo_out(&conn->session->cmdpool.queue,
-+ if (!__kfifo_get(conn->session->cmdpool.queue,
- (void *) &task, sizeof(void *)))
- return NULL;
-
-@@ -1726,33 +1723,16 @@ fault:
- spin_unlock(&session->lock);
- ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
- sc->cmnd[0], reason);
-- if (!scsi_bidi_cmnd(sc))
-- scsi_set_resid(sc, scsi_bufflen(sc));
-- else {
-- scsi_out(sc)->resid = scsi_out(sc)->length;
-- scsi_in(sc)->resid = scsi_in(sc)->length;
-- }
-+ scsi_set_resid(sc, scsi_bufflen(sc));
- done(sc);
- spin_lock(host->host_lock);
- return 0;
- }
- EXPORT_SYMBOL_GPL(iscsi_queuecommand);
-
--int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
-+int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
- {
-- switch (reason) {
-- case SCSI_QDEPTH_DEFAULT:
-- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
-- break;
-- case SCSI_QDEPTH_QFULL:
-- scsi_track_queue_full(sdev, depth);
-- break;
-- case SCSI_QDEPTH_RAMP_UP:
-- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
-- break;
-- default:
-- return -EOPNOTSUPP;
-- }
-+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- return sdev->queue_depth;
- }
- EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
-@@ -2524,7 +2504,12 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
- if (q->pool == NULL)
- return -ENOMEM;
-
-- kfifo_init(&q->queue, (void*)q->pool, max * sizeof(void*));
-+ q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
-+ GFP_KERNEL, NULL);
-+ if (IS_ERR(q->queue)) {
-+ q->queue = NULL;
-+ goto enomem;
-+ }
-
- for (i = 0; i < max; i++) {
- q->pool[i] = kzalloc(item_size, GFP_KERNEL);
-@@ -2532,7 +2517,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
- q->max = i;
- goto enomem;
- }
-- kfifo_in(&q->queue, (void*)&q->pool[i], sizeof(void*));
-+ __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
- }
-
- if (items) {
-@@ -2555,6 +2540,7 @@ void iscsi_pool_free(struct iscsi_pool *q)
- for (i = 0; i < q->max; i++)
- kfree(q->pool[i]);
- kfree(q->pool);
-+ kfree(q->queue);
- }
- EXPORT_SYMBOL_GPL(iscsi_pool_free);
-
-@@ -2882,7 +2868,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
-
- /* allocate login_task used for the login/text sequences */
- spin_lock_bh(&session->lock);
-- if (!kfifo_out(&session->cmdpool.queue,
-+ if (!__kfifo_get(session->cmdpool.queue,
- (void*)&conn->login_task,
- sizeof(void*))) {
- spin_unlock_bh(&session->lock);
-@@ -2902,7 +2888,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
- return cls_conn;
-
- login_task_data_alloc_fail:
-- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
-+ __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
- sizeof(void*));
- login_task_alloc_fail:
- iscsi_destroy_conn(cls_conn);
-@@ -2965,7 +2951,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
- free_pages((unsigned long) conn->data,
- get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
- kfree(conn->persistent_address);
-- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
-+ __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
- sizeof(void*));
- if (session->leadconn == conn)
- session->leadconn = NULL;
-diff --git a/libiscsi.h b/libiscsi.h
-index 0563539..d74385c 100644
---- a/libiscsi.h
-+++ b/libiscsi.h
-@@ -32,6 +32,8 @@
- #include "iscsi_if.h"
- #include "scsi_transport_iscsi.h"
-
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct scsi_host_template;
- struct scsi_device;
-@@ -231,7 +233,7 @@ struct iscsi_conn {
- };
-
- struct iscsi_pool {
-- struct kfifo queue; /* FIFO Queue */
-+ struct kfifo *queue; /* FIFO Queue */
- void **pool; /* Pool of elements */
- int max; /* Max number of elements */
- };
-@@ -334,8 +336,7 @@ struct iscsi_host {
- /*
- * scsi host template
- */
--extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth,
-- int reason);
-+extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth);
- extern int iscsi_eh_abort(struct scsi_cmnd *sc);
- extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
- extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
-diff --git a/libiscsi_tcp.c b/libiscsi_tcp.c
-index 1122de4..a0307e1 100644
---- a/libiscsi_tcp.c
-+++ b/libiscsi_tcp.c
-@@ -361,6 +361,16 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment,
- struct scatterlist *sg;
- unsigned int i;
-
-+ /*
-+ * older kernels could send use_sg=0 for commands like sgio
-+ * or scsi-ml commands.
-+ */
-+ if (!sg_count) {
-+ iscsi_segment_init_linear(segment, (void *)sg_list + offset,
-+ size, done, hash);
-+ return 0;
-+ }
-+
- __iscsi_segment_init(segment, size, done, hash);
- for_each_sg(sg_list, sg, sg_count, i) {
- if (offset < sg->length) {
-@@ -446,15 +456,15 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
- return;
-
- /* flush task's r2t queues */
-- while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ while (__kfifo_get(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- ISCSI_DBG_TCP(task->conn, "pending r2t dropped\n");
- }
-
- r2t = tcp_task->r2t;
- if (r2t != NULL) {
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- tcp_task->r2t = NULL;
- }
-@@ -472,7 +482,7 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
- int datasn = be32_to_cpu(rhdr->datasn);
-- unsigned total_in_length = scsi_in(task->sc)->length;
-+ unsigned total_in_length = scsi_bufflen(task->sc);
-
- /*
- * lib iscsi will update this in the completion handling if there
-@@ -542,7 +552,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- return 0;
- }
-
-- rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
-+ rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
- if (!rc) {
- iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
- "Target has sent more R2Ts than it "
-@@ -555,7 +565,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- if (r2t->data_length == 0) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with zero data len\n");
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
- }
-@@ -566,12 +576,12 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- r2t->data_length, session->max_burst);
-
- r2t->data_offset = be32_to_cpu(rhdr->data_offset);
-- if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
-+ if (r2t->data_offset + r2t->data_length > scsi_bufflen(task->sc)) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with data len %u at offset %u "
- "and total length %d\n", r2t->data_length,
-- r2t->data_offset, scsi_out(task->sc)->length);
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ r2t->data_offset, scsi_bufflen(task->sc));
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
- }
-@@ -581,7 +591,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- r2t->sent = 0;
-
- tcp_task->exp_datasn = r2tsn + 1;
-- kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
-+ __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
- conn->r2t_pdus_cnt++;
-
- iscsi_requeue_task(task);
-@@ -669,7 +679,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- if (tcp_conn->in.datalen) {
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct hash_desc *rx_hash = NULL;
-- struct scsi_data_buffer *sdb = scsi_in(task->sc);
-
- /*
- * Setup copy of Data-In into the Scsi_Cmnd
-@@ -689,8 +698,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
- tcp_conn->in.datalen);
- task->last_xfer = jiffies;
- rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
-- sdb->table.sgl,
-- sdb->table.nents,
-+ scsi_sglist(task->sc),
-+ scsi_sg_count(task->sc),
- tcp_task->data_offset,
- tcp_conn->in.datalen,
- iscsi_tcp_process_data_in,
-@@ -952,7 +961,7 @@ int iscsi_tcp_task_init(struct iscsi_task *task)
- return conn->session->tt->init_pdu(task, 0, task->data_count);
- }
-
-- BUG_ON(kfifo_len(&tcp_task->r2tqueue));
-+ BUG_ON(__kfifo_len(tcp_task->r2tqueue));
- tcp_task->exp_datasn = 0;
-
- /* Prepare PDU, optionally w/ immediate data */
-@@ -983,7 +992,7 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
- if (r2t->data_length <= r2t->sent) {
- ISCSI_DBG_TCP(task->conn,
- " done with r2t %p\n", r2t);
-- kfifo_in(&tcp_task->r2tpool.queue,
-+ __kfifo_put(tcp_task->r2tpool.queue,
- (void *)&tcp_task->r2t,
- sizeof(void *));
- tcp_task->r2t = r2t = NULL;
-@@ -991,12 +1000,9 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
- }
-
- if (r2t == NULL) {
-- if (kfifo_out(&tcp_task->r2tqueue,
-- (void *)&tcp_task->r2t, sizeof(void *)) !=
-- sizeof(void *))
-- r2t = NULL;
-- else
-- r2t = tcp_task->r2t;
-+ __kfifo_get(tcp_task->r2tqueue,
-+ (void *)&tcp_task->r2t, sizeof(void *));
-+ r2t = tcp_task->r2t;
- }
- spin_unlock_bh(&session->lock);
- }
-@@ -1131,8 +1137,9 @@ int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
- }
-
- /* R2T xmit queue */
-- if (kfifo_alloc(&tcp_task->r2tqueue,
-- session->max_r2t * 4 * sizeof(void*), GFP_KERNEL)) {
-+ tcp_task->r2tqueue = kfifo_alloc(
-+ session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
-+ if (tcp_task->r2tqueue == ERR_PTR(-ENOMEM)) {
- iscsi_pool_free(&tcp_task->r2tpool);
- goto r2t_alloc_fail;
- }
-@@ -1145,7 +1152,7 @@ r2t_alloc_fail:
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
-- kfifo_free(&tcp_task->r2tqueue);
-+ kfifo_free(tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
- return -ENOMEM;
-@@ -1160,7 +1167,7 @@ void iscsi_tcp_r2tpool_free(struct iscsi_session *session)
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
-- kfifo_free(&tcp_task->r2tqueue);
-+ kfifo_free(tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
- }
-diff --git a/libiscsi_tcp.h b/libiscsi_tcp.h
-index c020eee..5ea284d 100644
---- a/libiscsi_tcp.h
-+++ b/libiscsi_tcp.h
-@@ -21,6 +21,7 @@
- #ifndef LIBISCSI_TCP_H
- #define LIBISCSI_TCP_H
-
-+#include "open_iscsi_compat.h"
- #include "libiscsi.h"
-
- struct iscsi_tcp_conn;
-@@ -80,7 +81,7 @@ struct iscsi_tcp_task {
- int data_offset;
- struct iscsi_r2t_info *r2t; /* in progress solict R2T */
- struct iscsi_pool r2tpool;
-- struct kfifo r2tqueue;
-+ struct kfifo *r2tqueue;
- void *dd_data;
- };
-
-diff --git a/open_iscsi_compat.h b/open_iscsi_compat.h
-new file mode 100644
-index 0000000..50ab84d
---- /dev/null
-+++ b/open_iscsi_compat.h
-@@ -0,0 +1,276 @@
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <scsi/scsi.h>
-+#include <scsi/scsi_cmnd.h>
-+
-+#ifndef OPEN_ISCSI_COMPAT
-+#define OPEN_ISCSI_COMPAT
-+
-+#ifndef SCAN_WILD_CARD
-+#define SCAN_WILD_CARD ~0
-+#endif
-+
-+#ifndef NIPQUAD_FMT
-+#define NIPQUAD_FMT "%u.%u.%u.%u"
-+#endif
-+
-+#ifndef NIP6_FMT
-+#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-+#endif
-+
-+#ifndef DEFINE_MUTEX
-+
-+/* mutex changes from 2.6.16-rc1 and up */
-+#define DEFINE_MUTEX DECLARE_MUTEX
-+#define mutex_lock down
-+#define mutex_unlock up
-+#define mutex semaphore
-+#define mutex_init init_MUTEX
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12)
-+
-+void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun)
-+{
-+ int i;
-+
-+ memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
-+
-+ for (i = 0; i < sizeof(lun); i += 2) {
-+ scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
-+ scsilun->scsi_lun[i+1] = lun & 0xFF;
-+ lun = lun >> 16;
-+ }
-+}
-+
-+#define __nlmsg_put(skb, daemon_pid, seq, type, len, flags) \
-+ __nlmsg_put(skb, daemon_pid, 0, 0, len)
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define gfp_t unsigned
-+
-+void *kzalloc(size_t size, gfp_t flags)
-+{
-+ void *ret = kmalloc(size, flags);
-+ if (ret)
-+ memset(ret, 0, size);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+
-+#include "linux/crypto.h"
-+
-+#define CRYPTO_ALG_ASYNC 0x00000080
-+struct hash_desc
-+{
-+ struct crypto_tfm *tfm;
-+ u32 flags;
-+};
-+
-+static inline int crypto_hash_init(struct hash_desc *desc)
-+{
-+ crypto_digest_init(desc->tfm);
-+ return 0;
-+}
-+
-+static inline int crypto_hash_digest(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes, u8 *out)
-+{
-+ crypto_digest_digest(desc->tfm, sg, 1, out);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_update(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes)
-+{
-+ crypto_digest_update(desc->tfm, sg, 1);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
-+{
-+ crypto_digest_final(desc->tfm, out);
-+ return 0;
-+}
-+
-+static inline struct crypto_tfm *crypto_alloc_hash(const char *alg_name,
-+ u32 type, u32 mask)
-+{
-+ struct crypto_tfm *ret = crypto_alloc_tfm(alg_name ,type);
-+ return ret ? ret : ERR_PTR(-ENOMEM);
-+}
-+
-+static inline void crypto_free_hash(struct crypto_tfm *tfm)
-+{
-+ crypto_free_tfm(tfm);
-+}
-+
-+int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 0);
-+}
-+
-+int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 1);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
-+
-+static inline int is_power_of_2(unsigned long n)
-+{
-+ return (n != 0 && ((n & (n - 1)) == 0));
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
-+{
-+ return (struct nlmsghdr *)skb->data;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+ return (void *)shost->hostdata;
-+}
-+
-+/*
-+ * Note: We do not support bidi for the compat modules if the kernel
-+ * does not have support.
-+ */
-+#define scsi_sg_count(cmd) ((cmd)->use_sg)
-+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
-+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
-+
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+ cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+ return cmd->resid;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+static inline unsigned long rounddown_pow_of_two(unsigned long n)
-+{
-+ return 1UL << (fls_long(n) - 1);
-+}
-+
-+
-+static inline struct scatterlist *sg_next(struct scatterlist *sg)
-+{
-+ if (!sg) {
-+ BUG();
-+ return NULL;
-+ }
-+ return sg + 1;
-+}
-+
-+#define for_each_sg(sglist, sg, nr, __i) \
-+ for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
-+
-+#define sg_page(_sg) _sg->page
-+
-+static inline void sg_set_page(struct scatterlist *sg, struct page *page,
-+ unsigned int len, unsigned int offset)
-+{
-+ sg->page = page;
-+ sg->offset = offset;
-+ sg->length = len;
-+}
-+
-+static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
-+{
-+ memset(sgl, 0, sizeof(*sgl) * nents);
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
-+
-+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
-+{
-+ return 0;
-+}
-+
-+#define netlink_kernel_release(_nls) \
-+ sock_release(_nls->sk_socket)
-+
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, input)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#endif
-+
-+#ifndef DID_TRANSPORT_DISRUPTED
-+#define DID_TRANSPORT_DISRUPTED DID_BUS_BUSY
-+#endif
-+
-+#ifndef DID_TRANSPORT_FAILFAST
-+#define DID_TRANSPORT_FAILFAST DID_NO_CONNECT
-+#endif
-+
-+#ifndef SCSI_MLQUEUE_TARGET_BUSY
-+#define SCSI_MLQUEUE_TARGET_BUSY SCSI_MLQUEUE_HOST_BUSY
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)
-+
-+#define BLK_EH_NOT_HANDLED EH_NOT_HANDLED
-+#define BLK_EH_RESET_TIMER EH_RESET_TIMER
-+
-+#define blk_eh_timer_return scsi_eh_timer_return
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34)
-+
-+static inline wait_queue_head_t *sk_sleep(struct sock *sk)
-+{
-+ return sk->sk_sleep;
-+}
-+
-+#endif
-+
-+#endif
-diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c
-index fed8c9e..01bf46c 100644
---- a/scsi_transport_iscsi.c
-+++ b/scsi_transport_iscsi.c
-@@ -73,13 +73,13 @@ struct iscsi_internal {
- struct scsi_transport_template t;
- struct iscsi_transport *iscsi_transport;
- struct list_head list;
-- struct device dev;
-+ struct class_device cdev;
-
-- struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
-+ struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
- struct transport_container conn_cont;
-- struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
-+ struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
- struct transport_container session_cont;
-- struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
-+ struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
- };
-
- static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
-@@ -96,12 +96,12 @@ static DEFINE_SPINLOCK(iscsi_transport_lock);
- #define to_iscsi_internal(tmpl) \
- container_of(tmpl, struct iscsi_internal, t)
-
--#define dev_to_iscsi_internal(_dev) \
-- container_of(_dev, struct iscsi_internal, dev)
-+#define cdev_to_iscsi_internal(_cdev) \
-+ container_of(_cdev, struct iscsi_internal, cdev)
-
--static void iscsi_transport_release(struct device *dev)
-+static void iscsi_transport_release(struct class_device *cdev)
- {
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- kfree(priv);
- }
-
-@@ -111,33 +111,31 @@ static void iscsi_transport_release(struct device *dev)
- */
- static struct class iscsi_transport_class = {
- .name = "iscsi_transport",
-- .dev_release = iscsi_transport_release,
-+ .release = iscsi_transport_release,
- };
-
- static ssize_t
--show_transport_handle(struct device *dev, struct device_attribute *attr,
-- char *buf)
-+show_transport_handle(struct class_device *cdev, char *buf)
- {
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
- return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
- }
--static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-+static CLASS_DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-
- #define show_transport_attr(name, format) \
- static ssize_t \
--show_transport_##name(struct device *dev, \
-- struct device_attribute *attr,char *buf) \
-+show_transport_##name(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_internal *priv = dev_to_iscsi_internal(dev); \
-+ struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev); \
- return sprintf(buf, format"\n", priv->iscsi_transport->name); \
- } \
--static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-
- show_transport_attr(caps, "0x%x");
-
- static struct attribute *iscsi_transport_attrs[] = {
-- &dev_attr_handle.attr,
-- &dev_attr_caps.attr,
-+ &class_device_attr_handle.attr,
-+ &class_device_attr_caps.attr,
- NULL,
- };
-
-@@ -145,6 +143,7 @@ static struct attribute_group iscsi_transport_group = {
- .attrs = iscsi_transport_attrs,
- };
-
-+#if 0
- /*
- * iSCSI endpoint attrs
- */
-@@ -268,9 +267,10 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
- return ep;
- }
- EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
-+#endif
-
- static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
-- struct device *cdev)
-+ struct class_device *cdev)
- {
- struct Scsi_Host *shost = dev_to_shost(dev);
- struct iscsi_cls_host *ihost = shost->shost_data;
-@@ -750,7 +750,8 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
- }
- session->target_id = id;
-
-- dev_set_name(&session->dev, "session%u", session->sid);
-+ snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
-+ session->sid);
- err = device_add(&session->dev);
- if (err) {
- iscsi_cls_session_printk(KERN_ERR, session,
-@@ -930,7 +931,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
- if (!get_device(&session->dev))
- goto free_conn;
-
-- dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid);
-+ snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
-+ session->sid, cid);
- conn->dev.parent = &session->dev;
- conn->dev.release = iscsi_conn_release;
- err = device_register(&conn->dev);
-@@ -1402,6 +1404,8 @@ static int
- iscsi_if_transport_ep(struct iscsi_transport *transport,
- struct iscsi_uevent *ev, int msg_type)
- {
-+ return -ENOSYS;
-+#if 0
- struct iscsi_endpoint *ep;
- int rc = 0;
-
-@@ -1433,6 +1437,8 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
- break;
- }
- return rc;
-+
-+#endif
- }
-
- static int
-@@ -1541,6 +1547,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
- ev->u.c_session.queue_depth);
- break;
- case ISCSI_UEVENT_CREATE_BOUND_SESSION:
-+ err = -ENOSYS;
-+ break;
-+#if 0
- ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
- if (!ep) {
- err = -EINVAL;
-@@ -1552,6 +1561,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
- ev->u.c_bound_session.cmds_max,
- ev->u.c_bound_session.queue_depth);
- break;
-+#endif
- case ISCSI_UEVENT_DESTROY_SESSION:
- session = iscsi_session_lookup(ev->u.d_session.sid);
- if (session)
-@@ -1686,8 +1696,11 @@ iscsi_if_rx(struct sk_buff *skb)
- mutex_unlock(&rx_queue_mutex);
- }
-
-+#define iscsi_cdev_to_conn(_cdev) \
-+ iscsi_dev_to_conn(_cdev->dev)
-+
- #define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \
--struct device_attribute dev_attr_##_prefix##_##_name = \
-+struct class_device_attribute class_device_attr_##_prefix##_##_name = \
- __ATTR(_name,_mode,_show,_store)
-
- /*
-@@ -1695,10 +1708,9 @@ struct device_attribute dev_attr_##_prefix##_##_name = \
- */
- #define iscsi_conn_attr_show(param) \
- static ssize_t \
--show_conn_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_conn_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
-+ struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
- struct iscsi_transport *t = conn->transport; \
- return t->get_conn_param(conn, param, buf); \
- }
-@@ -1722,16 +1734,17 @@ iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
- iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
- iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
-
-+#define iscsi_cdev_to_session(_cdev) \
-+ iscsi_dev_to_session(_cdev->dev)
-+
- /*
- * iSCSI session attrs
- */
- #define iscsi_session_attr_show(param, perm) \
- static ssize_t \
--show_session_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_session_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_session *session = \
-- iscsi_dev_to_session(dev->parent); \
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
- struct iscsi_transport *t = session->transport; \
- \
- if (perm && !capable(CAP_SYS_ADMIN)) \
-@@ -1766,10 +1779,9 @@ iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
- iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
-
- static ssize_t
--show_priv_session_state(struct device *dev, struct device_attribute *attr,
-- char *buf)
-+show_priv_session_state(struct class_device *cdev, char *buf)
- {
-- struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);
- return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
- }
- static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-@@ -1777,11 +1789,9 @@ static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
-
- #define iscsi_priv_session_attr_show(field, format) \
- static ssize_t \
--show_priv_session_##field(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_priv_session_##field(struct class_device *cdev, char *buf) \
- { \
-- struct iscsi_cls_session *session = \
-- iscsi_dev_to_session(dev->parent); \
-+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\
- return sprintf(buf, format"\n", session->field); \
- }
-
-@@ -1796,10 +1806,9 @@ iscsi_priv_session_attr(recovery_tmo, "%d");
- */
- #define iscsi_host_attr_show(param) \
- static ssize_t \
--show_host_param_##param(struct device *dev, \
-- struct device_attribute *attr, char *buf) \
-+show_host_param_##param(struct class_device *cdev, char *buf) \
- { \
-- struct Scsi_Host *shost = transport_class_to_shost(dev); \
-+ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
- struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
- return priv->iscsi_transport->get_host_param(shost, param, buf); \
- }
-@@ -1816,7 +1825,7 @@ iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
-
- #define SETUP_PRIV_SESSION_RD_ATTR(field) \
- do { \
-- priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
-+ priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
- count++; \
- } while (0)
-
-@@ -1824,7 +1833,7 @@ do { \
- #define SETUP_SESSION_RD_ATTR(field, param_flag) \
- do { \
- if (tt->param_mask & param_flag) { \
-- priv->session_attrs[count] = &dev_attr_sess_##field; \
-+ priv->session_attrs[count] = &class_device_attr_sess_##field; \
- count++; \
- } \
- } while (0)
-@@ -1832,7 +1841,7 @@ do { \
- #define SETUP_CONN_RD_ATTR(field, param_flag) \
- do { \
- if (tt->param_mask & param_flag) { \
-- priv->conn_attrs[count] = &dev_attr_conn_##field; \
-+ priv->conn_attrs[count] = &class_device_attr_conn_##field; \
- count++; \
- } \
- } while (0)
-@@ -1840,7 +1849,7 @@ do { \
- #define SETUP_HOST_RD_ATTR(field, param_flag) \
- do { \
- if (tt->host_param_mask & param_flag) { \
-- priv->host_attrs[count] = &dev_attr_host_##field; \
-+ priv->host_attrs[count] = &class_device_attr_host_##field; \
- count++; \
- } \
- } while (0)
-@@ -1931,15 +1940,15 @@ iscsi_register_transport(struct iscsi_transport *tt)
- priv->t.user_scan = iscsi_user_scan;
- priv->t.create_work_queue = 1;
-
-- priv->dev.class = &iscsi_transport_class;
-- dev_set_name(&priv->dev, "%s", tt->name);
-- err = device_register(&priv->dev);
-+ priv->cdev.class = &iscsi_transport_class;
-+ snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
-+ err = class_device_register(&priv->cdev);
- if (err)
- goto free_priv;
-
-- err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
-+ err = sysfs_create_group(&priv->cdev.kobj, &iscsi_transport_group);
- if (err)
-- goto unregister_dev;
-+ goto unregister_cdev;
-
- /* host parameters */
- priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
-@@ -2019,9 +2028,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
- printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
- return &priv->t;
-
--unregister_dev:
-- device_unregister(&priv->dev);
-- return NULL;
-+unregister_cdev:
-+ class_device_unregister(&priv->cdev);
- free_priv:
- kfree(priv);
- return NULL;
-@@ -2048,8 +2056,8 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
- transport_container_unregister(&priv->session_cont);
- transport_container_unregister(&priv->t.host_attrs);
-
-- sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
-- device_unregister(&priv->dev);
-+ sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
-+ class_device_unregister(&priv->cdev);
- mutex_unlock(&rx_queue_mutex);
-
- return 0;
-@@ -2069,13 +2077,14 @@ static __init int iscsi_transport_init(void)
- if (err)
- return err;
-
-+#if 0
- err = class_register(&iscsi_endpoint_class);
- if (err)
- goto unregister_transport_class;
--
-+#endif
- err = transport_class_register(&iscsi_host_class);
- if (err)
-- goto unregister_endpoint_class;
-+ goto unregister_transport_class;
-
- err = transport_class_register(&iscsi_connection_class);
- if (err)
-@@ -2106,8 +2115,10 @@ unregister_conn_class:
- transport_class_unregister(&iscsi_connection_class);
- unregister_host_class:
- transport_class_unregister(&iscsi_host_class);
-+#if 0
- unregister_endpoint_class:
- class_unregister(&iscsi_endpoint_class);
-+#endif
- unregister_transport_class:
- class_unregister(&iscsi_transport_class);
- return err;
-@@ -2120,7 +2131,9 @@ static void __exit iscsi_transport_exit(void)
- transport_class_unregister(&iscsi_connection_class);
- transport_class_unregister(&iscsi_session_class);
- transport_class_unregister(&iscsi_host_class);
-+#if 0
- class_unregister(&iscsi_endpoint_class);
-+#endif
- class_unregister(&iscsi_transport_class);
- }
-
-diff --git a/scsi_transport_iscsi.h b/scsi_transport_iscsi.h
-index ef4b697..d62fd13 100644
---- a/scsi_transport_iscsi.h
-+++ b/scsi_transport_iscsi.h
-@@ -28,6 +28,8 @@
- #include <linux/mutex.h>
- #include "iscsi_if.h"
-
-+#include "open_iscsi_compat.h"
-+
- struct scsi_transport_template;
- struct iscsi_transport;
- struct iscsi_endpoint;
---
-1.6.6.1
-
diff --git a/kernel/2.6.26_compat.patch b/kernel/2.6.26_compat.patch
deleted file mode 100644
index abd7d5a..0000000
--- a/kernel/2.6.26_compat.patch
+++ /dev/null
@@ -1,681 +0,0 @@
-diff --git a/iscsi_tcp.c b/iscsi_tcp.c
-index 2a401b9..197d314 100644
---- a/iscsi_tcp.c
-+++ b/iscsi_tcp.c
-@@ -43,6 +43,7 @@
- #include <scsi/scsi.h>
- #include "scsi_transport_iscsi.h"
-
-+#include "open_iscsi_compat.h"
- #include "iscsi_tcp.h"
-
- MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
-diff --git a/libiscsi.c b/libiscsi.c
-index 59e3a5f..d0e41d9 100644
---- a/libiscsi.c
-+++ b/libiscsi.c
-@@ -39,6 +39,8 @@
- #include "scsi_transport_iscsi.h"
- #include "libiscsi.h"
-
-+#include "open_iscsi_compat.h"
-+
- static int iscsi_dbg_lib_conn;
- module_param_named(debug_libiscsi_conn, iscsi_dbg_lib_conn, int,
- S_IRUGO | S_IWUSR);
-@@ -518,7 +520,7 @@ static void iscsi_free_task(struct iscsi_task *task)
- if (conn->login_task == task)
- return;
-
-- kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
-+ __kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
-
- if (sc) {
- task->sc = NULL;
-@@ -738,7 +740,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
- BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
-
-- if (!kfifo_out(&session->cmdpool.queue,
-+ if (!__kfifo_get(session->cmdpool.queue,
- (void*)&task, sizeof(void*)))
- return NULL;
- }
-@@ -1568,7 +1570,7 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
- {
- struct iscsi_task *task;
-
-- if (!kfifo_out(&conn->session->cmdpool.queue,
-+ if (!__kfifo_get(conn->session->cmdpool.queue,
- (void *) &task, sizeof(void *)))
- return NULL;
-
-@@ -1738,21 +1740,9 @@ fault:
- }
- EXPORT_SYMBOL_GPL(iscsi_queuecommand);
-
--int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
-+int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
- {
-- switch (reason) {
-- case SCSI_QDEPTH_DEFAULT:
-- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
-- break;
-- case SCSI_QDEPTH_QFULL:
-- scsi_track_queue_full(sdev, depth);
-- break;
-- case SCSI_QDEPTH_RAMP_UP:
-- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
-- break;
-- default:
-- return -EOPNOTSUPP;
-- }
-+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- return sdev->queue_depth;
- }
- EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
-@@ -2524,7 +2514,12 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
- if (q->pool == NULL)
- return -ENOMEM;
-
-- kfifo_init(&q->queue, (void*)q->pool, max * sizeof(void*));
-+ q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
-+ GFP_KERNEL, NULL);
-+ if (IS_ERR(q->queue)) {
-+ q->queue = NULL;
-+ goto enomem;
-+ }
-
- for (i = 0; i < max; i++) {
- q->pool[i] = kzalloc(item_size, GFP_KERNEL);
-@@ -2532,7 +2527,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
- q->max = i;
- goto enomem;
- }
-- kfifo_in(&q->queue, (void*)&q->pool[i], sizeof(void*));
-+ __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
- }
-
- if (items) {
-@@ -2555,6 +2550,7 @@ void iscsi_pool_free(struct iscsi_pool *q)
- for (i = 0; i < q->max; i++)
- kfree(q->pool[i]);
- kfree(q->pool);
-+ kfree(q->queue);
- }
- EXPORT_SYMBOL_GPL(iscsi_pool_free);
-
-@@ -2882,7 +2878,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
-
- /* allocate login_task used for the login/text sequences */
- spin_lock_bh(&session->lock);
-- if (!kfifo_out(&session->cmdpool.queue,
-+ if (!__kfifo_get(session->cmdpool.queue,
- (void*)&conn->login_task,
- sizeof(void*))) {
- spin_unlock_bh(&session->lock);
-@@ -2902,7 +2898,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
- return cls_conn;
-
- login_task_data_alloc_fail:
-- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
-+ __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
- sizeof(void*));
- login_task_alloc_fail:
- iscsi_destroy_conn(cls_conn);
-@@ -2965,7 +2961,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
- free_pages((unsigned long) conn->data,
- get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
- kfree(conn->persistent_address);
-- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
-+ __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
- sizeof(void*));
- if (session->leadconn == conn)
- session->leadconn = NULL;
-diff --git a/libiscsi.h b/libiscsi.h
-index 0563539..4be9333 100644
---- a/libiscsi.h
-+++ b/libiscsi.h
-@@ -231,7 +231,7 @@ struct iscsi_conn {
- };
-
- struct iscsi_pool {
-- struct kfifo queue; /* FIFO Queue */
-+ struct kfifo *queue; /* FIFO Queue */
- void **pool; /* Pool of elements */
- int max; /* Max number of elements */
- };
-@@ -334,8 +334,7 @@ struct iscsi_host {
- /*
- * scsi host template
- */
--extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth,
-- int reason);
-+extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth);
- extern int iscsi_eh_abort(struct scsi_cmnd *sc);
- extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
- extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
-diff --git a/libiscsi_tcp.c b/libiscsi_tcp.c
-index 1122de4..c3ff728 100644
---- a/libiscsi_tcp.c
-+++ b/libiscsi_tcp.c
-@@ -446,15 +446,15 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
- return;
-
- /* flush task's r2t queues */
-- while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ while (__kfifo_get(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- ISCSI_DBG_TCP(task->conn, "pending r2t dropped\n");
- }
-
- r2t = tcp_task->r2t;
- if (r2t != NULL) {
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- tcp_task->r2t = NULL;
- }
-@@ -542,7 +542,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- return 0;
- }
-
-- rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
-+ rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
- if (!rc) {
- iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
- "Target has sent more R2Ts than it "
-@@ -555,7 +555,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- if (r2t->data_length == 0) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with zero data len\n");
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
- }
-@@ -571,7 +571,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- "invalid R2T with data len %u at offset %u "
- "and total length %d\n", r2t->data_length,
- r2t->data_offset, scsi_out(task->sc)->length);
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
- }
-@@ -581,7 +581,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- r2t->sent = 0;
-
- tcp_task->exp_datasn = r2tsn + 1;
-- kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
-+ __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
- conn->r2t_pdus_cnt++;
-
- iscsi_requeue_task(task);
-@@ -952,7 +952,7 @@ int iscsi_tcp_task_init(struct iscsi_task *task)
- return conn->session->tt->init_pdu(task, 0, task->data_count);
- }
-
-- BUG_ON(kfifo_len(&tcp_task->r2tqueue));
-+ BUG_ON(__kfifo_len(tcp_task->r2tqueue));
- tcp_task->exp_datasn = 0;
-
- /* Prepare PDU, optionally w/ immediate data */
-@@ -983,7 +983,7 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
- if (r2t->data_length <= r2t->sent) {
- ISCSI_DBG_TCP(task->conn,
- " done with r2t %p\n", r2t);
-- kfifo_in(&tcp_task->r2tpool.queue,
-+ __kfifo_put(tcp_task->r2tpool.queue,
- (void *)&tcp_task->r2t,
- sizeof(void *));
- tcp_task->r2t = r2t = NULL;
-@@ -991,12 +991,9 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
- }
-
- if (r2t == NULL) {
-- if (kfifo_out(&tcp_task->r2tqueue,
-- (void *)&tcp_task->r2t, sizeof(void *)) !=
-- sizeof(void *))
-- r2t = NULL;
-- else
-- r2t = tcp_task->r2t;
-+ __kfifo_get(tcp_task->r2tqueue,
-+ (void *)&tcp_task->r2t, sizeof(void *));
-+ r2t = tcp_task->r2t;
- }
- spin_unlock_bh(&session->lock);
- }
-@@ -1131,8 +1128,9 @@ int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
- }
-
- /* R2T xmit queue */
-- if (kfifo_alloc(&tcp_task->r2tqueue,
-- session->max_r2t * 4 * sizeof(void*), GFP_KERNEL)) {
-+ tcp_task->r2tqueue = kfifo_alloc(
-+ session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
-+ if (tcp_task->r2tqueue == ERR_PTR(-ENOMEM)) {
- iscsi_pool_free(&tcp_task->r2tpool);
- goto r2t_alloc_fail;
- }
-@@ -1145,7 +1143,7 @@ r2t_alloc_fail:
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
-- kfifo_free(&tcp_task->r2tqueue);
-+ kfifo_free(tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
- return -ENOMEM;
-@@ -1160,7 +1158,7 @@ void iscsi_tcp_r2tpool_free(struct iscsi_session *session)
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
-- kfifo_free(&tcp_task->r2tqueue);
-+ kfifo_free(tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
- }
-diff --git a/libiscsi_tcp.h b/libiscsi_tcp.h
-index c020eee..3bacef5 100644
---- a/libiscsi_tcp.h
-+++ b/libiscsi_tcp.h
-@@ -80,7 +80,7 @@ struct iscsi_tcp_task {
- int data_offset;
- struct iscsi_r2t_info *r2t; /* in progress solict R2T */
- struct iscsi_pool r2tpool;
-- struct kfifo r2tqueue;
-+ struct kfifo *r2tqueue;
- void *dd_data;
- };
-
-diff --git a/open_iscsi_compat.h b/open_iscsi_compat.h
-new file mode 100644
-index 0000000..50ab84d
---- /dev/null
-+++ b/open_iscsi_compat.h
-@@ -0,0 +1,276 @@
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <scsi/scsi.h>
-+#include <scsi/scsi_cmnd.h>
-+
-+#ifndef OPEN_ISCSI_COMPAT
-+#define OPEN_ISCSI_COMPAT
-+
-+#ifndef SCAN_WILD_CARD
-+#define SCAN_WILD_CARD ~0
-+#endif
-+
-+#ifndef NIPQUAD_FMT
-+#define NIPQUAD_FMT "%u.%u.%u.%u"
-+#endif
-+
-+#ifndef NIP6_FMT
-+#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-+#endif
-+
-+#ifndef DEFINE_MUTEX
-+
-+/* mutex changes from 2.6.16-rc1 and up */
-+#define DEFINE_MUTEX DECLARE_MUTEX
-+#define mutex_lock down
-+#define mutex_unlock up
-+#define mutex semaphore
-+#define mutex_init init_MUTEX
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12)
-+
-+void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun)
-+{
-+ int i;
-+
-+ memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
-+
-+ for (i = 0; i < sizeof(lun); i += 2) {
-+ scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
-+ scsilun->scsi_lun[i+1] = lun & 0xFF;
-+ lun = lun >> 16;
-+ }
-+}
-+
-+#define __nlmsg_put(skb, daemon_pid, seq, type, len, flags) \
-+ __nlmsg_put(skb, daemon_pid, 0, 0, len)
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define gfp_t unsigned
-+
-+void *kzalloc(size_t size, gfp_t flags)
-+{
-+ void *ret = kmalloc(size, flags);
-+ if (ret)
-+ memset(ret, 0, size);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+
-+#include "linux/crypto.h"
-+
-+#define CRYPTO_ALG_ASYNC 0x00000080
-+struct hash_desc
-+{
-+ struct crypto_tfm *tfm;
-+ u32 flags;
-+};
-+
-+static inline int crypto_hash_init(struct hash_desc *desc)
-+{
-+ crypto_digest_init(desc->tfm);
-+ return 0;
-+}
-+
-+static inline int crypto_hash_digest(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes, u8 *out)
-+{
-+ crypto_digest_digest(desc->tfm, sg, 1, out);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_update(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes)
-+{
-+ crypto_digest_update(desc->tfm, sg, 1);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
-+{
-+ crypto_digest_final(desc->tfm, out);
-+ return 0;
-+}
-+
-+static inline struct crypto_tfm *crypto_alloc_hash(const char *alg_name,
-+ u32 type, u32 mask)
-+{
-+ struct crypto_tfm *ret = crypto_alloc_tfm(alg_name ,type);
-+ return ret ? ret : ERR_PTR(-ENOMEM);
-+}
-+
-+static inline void crypto_free_hash(struct crypto_tfm *tfm)
-+{
-+ crypto_free_tfm(tfm);
-+}
-+
-+int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 0);
-+}
-+
-+int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 1);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
-+
-+static inline int is_power_of_2(unsigned long n)
-+{
-+ return (n != 0 && ((n & (n - 1)) == 0));
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
-+{
-+ return (struct nlmsghdr *)skb->data;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+ return (void *)shost->hostdata;
-+}
-+
-+/*
-+ * Note: We do not support bidi for the compat modules if the kernel
-+ * does not have support.
-+ */
-+#define scsi_sg_count(cmd) ((cmd)->use_sg)
-+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
-+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
-+
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+ cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+ return cmd->resid;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+static inline unsigned long rounddown_pow_of_two(unsigned long n)
-+{
-+ return 1UL << (fls_long(n) - 1);
-+}
-+
-+
-+static inline struct scatterlist *sg_next(struct scatterlist *sg)
-+{
-+ if (!sg) {
-+ BUG();
-+ return NULL;
-+ }
-+ return sg + 1;
-+}
-+
-+#define for_each_sg(sglist, sg, nr, __i) \
-+ for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
-+
-+#define sg_page(_sg) _sg->page
-+
-+static inline void sg_set_page(struct scatterlist *sg, struct page *page,
-+ unsigned int len, unsigned int offset)
-+{
-+ sg->page = page;
-+ sg->offset = offset;
-+ sg->length = len;
-+}
-+
-+static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
-+{
-+ memset(sgl, 0, sizeof(*sgl) * nents);
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
-+
-+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
-+{
-+ return 0;
-+}
-+
-+#define netlink_kernel_release(_nls) \
-+ sock_release(_nls->sk_socket)
-+
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, input)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#endif
-+
-+#ifndef DID_TRANSPORT_DISRUPTED
-+#define DID_TRANSPORT_DISRUPTED DID_BUS_BUSY
-+#endif
-+
-+#ifndef DID_TRANSPORT_FAILFAST
-+#define DID_TRANSPORT_FAILFAST DID_NO_CONNECT
-+#endif
-+
-+#ifndef SCSI_MLQUEUE_TARGET_BUSY
-+#define SCSI_MLQUEUE_TARGET_BUSY SCSI_MLQUEUE_HOST_BUSY
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)
-+
-+#define BLK_EH_NOT_HANDLED EH_NOT_HANDLED
-+#define BLK_EH_RESET_TIMER EH_RESET_TIMER
-+
-+#define blk_eh_timer_return scsi_eh_timer_return
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34)
-+
-+static inline wait_queue_head_t *sk_sleep(struct sock *sk)
-+{
-+ return sk->sk_sleep;
-+}
-+
-+#endif
-+
-+#endif
-diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c
-index fed8c9e..c187e5d 100644
---- a/scsi_transport_iscsi.c
-+++ b/scsi_transport_iscsi.c
-@@ -31,6 +31,8 @@
- #include "scsi_transport_iscsi.h"
- #include "iscsi_if.h"
-
-+#include "open_iscsi_compat.h"
-+
- #define ISCSI_SESSION_ATTRS 22
- #define ISCSI_CONN_ATTRS 13
- #define ISCSI_HOST_ATTRS 4
-@@ -145,6 +147,7 @@ static struct attribute_group iscsi_transport_group = {
- .attrs = iscsi_transport_attrs,
- };
-
-+#if 0
- /*
- * iSCSI endpoint attrs
- */
-@@ -268,6 +271,7 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
- return ep;
- }
- EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
-+#endif
-
- static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
- struct device *cdev)
-@@ -1402,6 +1406,8 @@ static int
- iscsi_if_transport_ep(struct iscsi_transport *transport,
- struct iscsi_uevent *ev, int msg_type)
- {
-+ return -ENOSYS;
-+#if 0
- struct iscsi_endpoint *ep;
- int rc = 0;
-
-@@ -1433,6 +1439,8 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
- break;
- }
- return rc;
-+
-+#endif
- }
-
- static int
-@@ -1541,6 +1549,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
- ev->u.c_session.queue_depth);
- break;
- case ISCSI_UEVENT_CREATE_BOUND_SESSION:
-+ err = -ENOSYS;
-+ break;
-+#if 0
- ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
- if (!ep) {
- err = -EINVAL;
-@@ -1552,6 +1563,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
- ev->u.c_bound_session.cmds_max,
- ev->u.c_bound_session.queue_depth);
- break;
-+#endif
- case ISCSI_UEVENT_DESTROY_SESSION:
- session = iscsi_session_lookup(ev->u.d_session.sid);
- if (session)
-@@ -2069,13 +2081,14 @@ static __init int iscsi_transport_init(void)
- if (err)
- return err;
-
-+#if 0
- err = class_register(&iscsi_endpoint_class);
- if (err)
- goto unregister_transport_class;
--
-+#endif
- err = transport_class_register(&iscsi_host_class);
- if (err)
-- goto unregister_endpoint_class;
-+ goto unregister_transport_class;
-
- err = transport_class_register(&iscsi_connection_class);
- if (err)
-@@ -2106,8 +2119,10 @@ unregister_conn_class:
- transport_class_unregister(&iscsi_connection_class);
- unregister_host_class:
- transport_class_unregister(&iscsi_host_class);
-+#if 0
- unregister_endpoint_class:
- class_unregister(&iscsi_endpoint_class);
-+#endif
- unregister_transport_class:
- class_unregister(&iscsi_transport_class);
- return err;
-@@ -2120,7 +2135,9 @@ static void __exit iscsi_transport_exit(void)
- transport_class_unregister(&iscsi_connection_class);
- transport_class_unregister(&iscsi_session_class);
- transport_class_unregister(&iscsi_host_class);
-+#if 0
- class_unregister(&iscsi_endpoint_class);
-+#endif
- class_unregister(&iscsi_transport_class);
- }
-
---
-1.6.6.1
-
diff --git a/kernel/2.6.27_compat.patch b/kernel/2.6.27_compat.patch
deleted file mode 100644
index 2406511..0000000
--- a/kernel/2.6.27_compat.patch
+++ /dev/null
@@ -1,591 +0,0 @@
-diff --git a/iscsi_tcp.c b/iscsi_tcp.c
-index 2a401b9..197d314 100644
---- a/iscsi_tcp.c
-+++ b/iscsi_tcp.c
-@@ -43,6 +43,7 @@
- #include <scsi/scsi.h>
- #include "scsi_transport_iscsi.h"
-
-+#include "open_iscsi_compat.h"
- #include "iscsi_tcp.h"
-
- MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
-diff --git a/libiscsi.c b/libiscsi.c
-index 59e3a5f..d0e41d9 100644
---- a/libiscsi.c
-+++ b/libiscsi.c
-@@ -39,6 +39,8 @@
- #include "scsi_transport_iscsi.h"
- #include "libiscsi.h"
-
-+#include "open_iscsi_compat.h"
-+
- static int iscsi_dbg_lib_conn;
- module_param_named(debug_libiscsi_conn, iscsi_dbg_lib_conn, int,
- S_IRUGO | S_IWUSR);
-@@ -518,7 +520,7 @@ static void iscsi_free_task(struct iscsi_task *task)
- if (conn->login_task == task)
- return;
-
-- kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
-+ __kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
-
- if (sc) {
- task->sc = NULL;
-@@ -738,7 +740,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
- BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
-
-- if (!kfifo_out(&session->cmdpool.queue,
-+ if (!__kfifo_get(session->cmdpool.queue,
- (void*)&task, sizeof(void*)))
- return NULL;
- }
-@@ -1568,7 +1570,7 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
- {
- struct iscsi_task *task;
-
-- if (!kfifo_out(&conn->session->cmdpool.queue,
-+ if (!__kfifo_get(conn->session->cmdpool.queue,
- (void *) &task, sizeof(void *)))
- return NULL;
-
-@@ -1738,21 +1740,9 @@ fault:
- }
- EXPORT_SYMBOL_GPL(iscsi_queuecommand);
-
--int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
-+int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
- {
-- switch (reason) {
-- case SCSI_QDEPTH_DEFAULT:
-- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
-- break;
-- case SCSI_QDEPTH_QFULL:
-- scsi_track_queue_full(sdev, depth);
-- break;
-- case SCSI_QDEPTH_RAMP_UP:
-- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
-- break;
-- default:
-- return -EOPNOTSUPP;
-- }
-+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- return sdev->queue_depth;
- }
- EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
-@@ -2524,7 +2514,12 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
- if (q->pool == NULL)
- return -ENOMEM;
-
-- kfifo_init(&q->queue, (void*)q->pool, max * sizeof(void*));
-+ q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
-+ GFP_KERNEL, NULL);
-+ if (IS_ERR(q->queue)) {
-+ q->queue = NULL;
-+ goto enomem;
-+ }
-
- for (i = 0; i < max; i++) {
- q->pool[i] = kzalloc(item_size, GFP_KERNEL);
-@@ -2532,7 +2527,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
- q->max = i;
- goto enomem;
- }
-- kfifo_in(&q->queue, (void*)&q->pool[i], sizeof(void*));
-+ __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
- }
-
- if (items) {
-@@ -2555,6 +2550,7 @@ void iscsi_pool_free(struct iscsi_pool *q)
- for (i = 0; i < q->max; i++)
- kfree(q->pool[i]);
- kfree(q->pool);
-+ kfree(q->queue);
- }
- EXPORT_SYMBOL_GPL(iscsi_pool_free);
-
-@@ -2882,7 +2878,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
-
- /* allocate login_task used for the login/text sequences */
- spin_lock_bh(&session->lock);
-- if (!kfifo_out(&session->cmdpool.queue,
-+ if (!__kfifo_get(session->cmdpool.queue,
- (void*)&conn->login_task,
- sizeof(void*))) {
- spin_unlock_bh(&session->lock);
-@@ -2902,7 +2898,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
- return cls_conn;
-
- login_task_data_alloc_fail:
-- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
-+ __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
- sizeof(void*));
- login_task_alloc_fail:
- iscsi_destroy_conn(cls_conn);
-@@ -2965,7 +2961,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
- free_pages((unsigned long) conn->data,
- get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
- kfree(conn->persistent_address);
-- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
-+ __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
- sizeof(void*));
- if (session->leadconn == conn)
- session->leadconn = NULL;
-diff --git a/libiscsi.h b/libiscsi.h
-index 0563539..4be9333 100644
---- a/libiscsi.h
-+++ b/libiscsi.h
-@@ -231,7 +231,7 @@ struct iscsi_conn {
- };
-
- struct iscsi_pool {
-- struct kfifo queue; /* FIFO Queue */
-+ struct kfifo *queue; /* FIFO Queue */
- void **pool; /* Pool of elements */
- int max; /* Max number of elements */
- };
-@@ -334,8 +334,7 @@ struct iscsi_host {
- /*
- * scsi host template
- */
--extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth,
-- int reason);
-+extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth);
- extern int iscsi_eh_abort(struct scsi_cmnd *sc);
- extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
- extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
-diff --git a/libiscsi_tcp.c b/libiscsi_tcp.c
-index 1122de4..c3ff728 100644
---- a/libiscsi_tcp.c
-+++ b/libiscsi_tcp.c
-@@ -446,15 +446,15 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
- return;
-
- /* flush task's r2t queues */
-- while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ while (__kfifo_get(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- ISCSI_DBG_TCP(task->conn, "pending r2t dropped\n");
- }
-
- r2t = tcp_task->r2t;
- if (r2t != NULL) {
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- tcp_task->r2t = NULL;
- }
-@@ -542,7 +542,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- return 0;
- }
-
-- rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
-+ rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
- if (!rc) {
- iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
- "Target has sent more R2Ts than it "
-@@ -555,7 +555,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- if (r2t->data_length == 0) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with zero data len\n");
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
- }
-@@ -571,7 +571,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- "invalid R2T with data len %u at offset %u "
- "and total length %d\n", r2t->data_length,
- r2t->data_offset, scsi_out(task->sc)->length);
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
- }
-@@ -581,7 +581,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- r2t->sent = 0;
-
- tcp_task->exp_datasn = r2tsn + 1;
-- kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
-+ __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
- conn->r2t_pdus_cnt++;
-
- iscsi_requeue_task(task);
-@@ -952,7 +952,7 @@ int iscsi_tcp_task_init(struct iscsi_task *task)
- return conn->session->tt->init_pdu(task, 0, task->data_count);
- }
-
-- BUG_ON(kfifo_len(&tcp_task->r2tqueue));
-+ BUG_ON(__kfifo_len(tcp_task->r2tqueue));
- tcp_task->exp_datasn = 0;
-
- /* Prepare PDU, optionally w/ immediate data */
-@@ -983,7 +983,7 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
- if (r2t->data_length <= r2t->sent) {
- ISCSI_DBG_TCP(task->conn,
- " done with r2t %p\n", r2t);
-- kfifo_in(&tcp_task->r2tpool.queue,
-+ __kfifo_put(tcp_task->r2tpool.queue,
- (void *)&tcp_task->r2t,
- sizeof(void *));
- tcp_task->r2t = r2t = NULL;
-@@ -991,12 +991,9 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
- }
-
- if (r2t == NULL) {
-- if (kfifo_out(&tcp_task->r2tqueue,
-- (void *)&tcp_task->r2t, sizeof(void *)) !=
-- sizeof(void *))
-- r2t = NULL;
-- else
-- r2t = tcp_task->r2t;
-+ __kfifo_get(tcp_task->r2tqueue,
-+ (void *)&tcp_task->r2t, sizeof(void *));
-+ r2t = tcp_task->r2t;
- }
- spin_unlock_bh(&session->lock);
- }
-@@ -1131,8 +1128,9 @@ int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
- }
-
- /* R2T xmit queue */
-- if (kfifo_alloc(&tcp_task->r2tqueue,
-- session->max_r2t * 4 * sizeof(void*), GFP_KERNEL)) {
-+ tcp_task->r2tqueue = kfifo_alloc(
-+ session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
-+ if (tcp_task->r2tqueue == ERR_PTR(-ENOMEM)) {
- iscsi_pool_free(&tcp_task->r2tpool);
- goto r2t_alloc_fail;
- }
-@@ -1145,7 +1143,7 @@ r2t_alloc_fail:
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
-- kfifo_free(&tcp_task->r2tqueue);
-+ kfifo_free(tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
- return -ENOMEM;
-@@ -1160,7 +1158,7 @@ void iscsi_tcp_r2tpool_free(struct iscsi_session *session)
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
-- kfifo_free(&tcp_task->r2tqueue);
-+ kfifo_free(tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
- }
-diff --git a/libiscsi_tcp.h b/libiscsi_tcp.h
-index c020eee..3bacef5 100644
---- a/libiscsi_tcp.h
-+++ b/libiscsi_tcp.h
-@@ -80,7 +80,7 @@ struct iscsi_tcp_task {
- int data_offset;
- struct iscsi_r2t_info *r2t; /* in progress solict R2T */
- struct iscsi_pool r2tpool;
-- struct kfifo r2tqueue;
-+ struct kfifo *r2tqueue;
- void *dd_data;
- };
-
-diff --git a/open_iscsi_compat.h b/open_iscsi_compat.h
-new file mode 100644
-index 0000000..50ab84d
---- /dev/null
-+++ b/open_iscsi_compat.h
-@@ -0,0 +1,276 @@
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <scsi/scsi.h>
-+#include <scsi/scsi_cmnd.h>
-+
-+#ifndef OPEN_ISCSI_COMPAT
-+#define OPEN_ISCSI_COMPAT
-+
-+#ifndef SCAN_WILD_CARD
-+#define SCAN_WILD_CARD ~0
-+#endif
-+
-+#ifndef NIPQUAD_FMT
-+#define NIPQUAD_FMT "%u.%u.%u.%u"
-+#endif
-+
-+#ifndef NIP6_FMT
-+#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-+#endif
-+
-+#ifndef DEFINE_MUTEX
-+
-+/* mutex changes from 2.6.16-rc1 and up */
-+#define DEFINE_MUTEX DECLARE_MUTEX
-+#define mutex_lock down
-+#define mutex_unlock up
-+#define mutex semaphore
-+#define mutex_init init_MUTEX
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12)
-+
-+void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun)
-+{
-+ int i;
-+
-+ memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
-+
-+ for (i = 0; i < sizeof(lun); i += 2) {
-+ scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
-+ scsilun->scsi_lun[i+1] = lun & 0xFF;
-+ lun = lun >> 16;
-+ }
-+}
-+
-+#define __nlmsg_put(skb, daemon_pid, seq, type, len, flags) \
-+ __nlmsg_put(skb, daemon_pid, 0, 0, len)
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define gfp_t unsigned
-+
-+void *kzalloc(size_t size, gfp_t flags)
-+{
-+ void *ret = kmalloc(size, flags);
-+ if (ret)
-+ memset(ret, 0, size);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+
-+#include "linux/crypto.h"
-+
-+#define CRYPTO_ALG_ASYNC 0x00000080
-+struct hash_desc
-+{
-+ struct crypto_tfm *tfm;
-+ u32 flags;
-+};
-+
-+static inline int crypto_hash_init(struct hash_desc *desc)
-+{
-+ crypto_digest_init(desc->tfm);
-+ return 0;
-+}
-+
-+static inline int crypto_hash_digest(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes, u8 *out)
-+{
-+ crypto_digest_digest(desc->tfm, sg, 1, out);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_update(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes)
-+{
-+ crypto_digest_update(desc->tfm, sg, 1);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
-+{
-+ crypto_digest_final(desc->tfm, out);
-+ return 0;
-+}
-+
-+static inline struct crypto_tfm *crypto_alloc_hash(const char *alg_name,
-+ u32 type, u32 mask)
-+{
-+ struct crypto_tfm *ret = crypto_alloc_tfm(alg_name ,type);
-+ return ret ? ret : ERR_PTR(-ENOMEM);
-+}
-+
-+static inline void crypto_free_hash(struct crypto_tfm *tfm)
-+{
-+ crypto_free_tfm(tfm);
-+}
-+
-+int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 0);
-+}
-+
-+int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 1);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
-+
-+static inline int is_power_of_2(unsigned long n)
-+{
-+ return (n != 0 && ((n & (n - 1)) == 0));
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
-+{
-+ return (struct nlmsghdr *)skb->data;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+ return (void *)shost->hostdata;
-+}
-+
-+/*
-+ * Note: We do not support bidi for the compat modules if the kernel
-+ * does not have support.
-+ */
-+#define scsi_sg_count(cmd) ((cmd)->use_sg)
-+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
-+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
-+
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+ cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+ return cmd->resid;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+static inline unsigned long rounddown_pow_of_two(unsigned long n)
-+{
-+ return 1UL << (fls_long(n) - 1);
-+}
-+
-+
-+static inline struct scatterlist *sg_next(struct scatterlist *sg)
-+{
-+ if (!sg) {
-+ BUG();
-+ return NULL;
-+ }
-+ return sg + 1;
-+}
-+
-+#define for_each_sg(sglist, sg, nr, __i) \
-+ for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
-+
-+#define sg_page(_sg) _sg->page
-+
-+static inline void sg_set_page(struct scatterlist *sg, struct page *page,
-+ unsigned int len, unsigned int offset)
-+{
-+ sg->page = page;
-+ sg->offset = offset;
-+ sg->length = len;
-+}
-+
-+static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
-+{
-+ memset(sgl, 0, sizeof(*sgl) * nents);
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
-+
-+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
-+{
-+ return 0;
-+}
-+
-+#define netlink_kernel_release(_nls) \
-+ sock_release(_nls->sk_socket)
-+
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, input)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#endif
-+
-+#ifndef DID_TRANSPORT_DISRUPTED
-+#define DID_TRANSPORT_DISRUPTED DID_BUS_BUSY
-+#endif
-+
-+#ifndef DID_TRANSPORT_FAILFAST
-+#define DID_TRANSPORT_FAILFAST DID_NO_CONNECT
-+#endif
-+
-+#ifndef SCSI_MLQUEUE_TARGET_BUSY
-+#define SCSI_MLQUEUE_TARGET_BUSY SCSI_MLQUEUE_HOST_BUSY
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)
-+
-+#define BLK_EH_NOT_HANDLED EH_NOT_HANDLED
-+#define BLK_EH_RESET_TIMER EH_RESET_TIMER
-+
-+#define blk_eh_timer_return scsi_eh_timer_return
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34)
-+
-+static inline wait_queue_head_t *sk_sleep(struct sock *sk)
-+{
-+ return sk->sk_sleep;
-+}
-+
-+#endif
-+
-+#endif
-diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c
-index fed8c9e..3b28918 100644
---- a/scsi_transport_iscsi.c
-+++ b/scsi_transport_iscsi.c
-@@ -31,6 +31,8 @@
- #include "scsi_transport_iscsi.h"
- #include "iscsi_if.h"
-
-+#include "open_iscsi_compat.h"
-+
- #define ISCSI_SESSION_ATTRS 22
- #define ISCSI_CONN_ATTRS 13
- #define ISCSI_HOST_ATTRS 4
---
-1.6.6.1
-
diff --git a/kernel/2.6.28-32_compat.patch b/kernel/2.6.28-32_compat.patch
deleted file mode 100644
index c3ec600..0000000
--- a/kernel/2.6.28-32_compat.patch
+++ /dev/null
@@ -1,569 +0,0 @@
-diff --git a/iscsi_tcp.c b/iscsi_tcp.c
-index 2a401b9..197d314 100644
---- a/iscsi_tcp.c
-+++ b/iscsi_tcp.c
-@@ -43,6 +43,7 @@
- #include <scsi/scsi.h>
- #include "scsi_transport_iscsi.h"
-
-+#include "open_iscsi_compat.h"
- #include "iscsi_tcp.h"
-
- MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
-diff --git a/libiscsi.c b/libiscsi.c
-index 59e3a5f..b79453a 100644
---- a/libiscsi.c
-+++ b/libiscsi.c
-@@ -518,7 +518,7 @@ static void iscsi_free_task(struct iscsi_task *task)
- if (conn->login_task == task)
- return;
-
-- kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
-+ __kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
-
- if (sc) {
- task->sc = NULL;
-@@ -738,7 +738,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
- BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
-
-- if (!kfifo_out(&session->cmdpool.queue,
-+ if (!__kfifo_get(session->cmdpool.queue,
- (void*)&task, sizeof(void*)))
- return NULL;
- }
-@@ -1568,7 +1568,7 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
- {
- struct iscsi_task *task;
-
-- if (!kfifo_out(&conn->session->cmdpool.queue,
-+ if (!__kfifo_get(conn->session->cmdpool.queue,
- (void *) &task, sizeof(void *)))
- return NULL;
-
-@@ -1738,21 +1738,9 @@ fault:
- }
- EXPORT_SYMBOL_GPL(iscsi_queuecommand);
-
--int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
-+int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
- {
-- switch (reason) {
-- case SCSI_QDEPTH_DEFAULT:
-- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
-- break;
-- case SCSI_QDEPTH_QFULL:
-- scsi_track_queue_full(sdev, depth);
-- break;
-- case SCSI_QDEPTH_RAMP_UP:
-- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
-- break;
-- default:
-- return -EOPNOTSUPP;
-- }
-+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- return sdev->queue_depth;
- }
- EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
-@@ -2524,7 +2512,12 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
- if (q->pool == NULL)
- return -ENOMEM;
-
-- kfifo_init(&q->queue, (void*)q->pool, max * sizeof(void*));
-+ q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
-+ GFP_KERNEL, NULL);
-+ if (IS_ERR(q->queue)) {
-+ q->queue = NULL;
-+ goto enomem;
-+ }
-
- for (i = 0; i < max; i++) {
- q->pool[i] = kzalloc(item_size, GFP_KERNEL);
-@@ -2532,7 +2525,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
- q->max = i;
- goto enomem;
- }
-- kfifo_in(&q->queue, (void*)&q->pool[i], sizeof(void*));
-+ __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
- }
-
- if (items) {
-@@ -2555,6 +2548,7 @@ void iscsi_pool_free(struct iscsi_pool *q)
- for (i = 0; i < q->max; i++)
- kfree(q->pool[i]);
- kfree(q->pool);
-+ kfree(q->queue);
- }
- EXPORT_SYMBOL_GPL(iscsi_pool_free);
-
-@@ -2882,7 +2876,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
-
- /* allocate login_task used for the login/text sequences */
- spin_lock_bh(&session->lock);
-- if (!kfifo_out(&session->cmdpool.queue,
-+ if (!__kfifo_get(session->cmdpool.queue,
- (void*)&conn->login_task,
- sizeof(void*))) {
- spin_unlock_bh(&session->lock);
-@@ -2902,7 +2896,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
- return cls_conn;
-
- login_task_data_alloc_fail:
-- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
-+ __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
- sizeof(void*));
- login_task_alloc_fail:
- iscsi_destroy_conn(cls_conn);
-@@ -2965,7 +2959,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
- free_pages((unsigned long) conn->data,
- get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
- kfree(conn->persistent_address);
-- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
-+ __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
- sizeof(void*));
- if (session->leadconn == conn)
- session->leadconn = NULL;
-diff --git a/libiscsi.h b/libiscsi.h
-index 0563539..4be9333 100644
---- a/libiscsi.h
-+++ b/libiscsi.h
-@@ -231,7 +231,7 @@ struct iscsi_conn {
- };
-
- struct iscsi_pool {
-- struct kfifo queue; /* FIFO Queue */
-+ struct kfifo *queue; /* FIFO Queue */
- void **pool; /* Pool of elements */
- int max; /* Max number of elements */
- };
-@@ -334,8 +334,7 @@ struct iscsi_host {
- /*
- * scsi host template
- */
--extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth,
-- int reason);
-+extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth);
- extern int iscsi_eh_abort(struct scsi_cmnd *sc);
- extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
- extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
-diff --git a/libiscsi_tcp.c b/libiscsi_tcp.c
-index 1122de4..c3ff728 100644
---- a/libiscsi_tcp.c
-+++ b/libiscsi_tcp.c
-@@ -446,15 +446,15 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
- return;
-
- /* flush task's r2t queues */
-- while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ while (__kfifo_get(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- ISCSI_DBG_TCP(task->conn, "pending r2t dropped\n");
- }
-
- r2t = tcp_task->r2t;
- if (r2t != NULL) {
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- tcp_task->r2t = NULL;
- }
-@@ -542,7 +542,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- return 0;
- }
-
-- rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
-+ rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
- if (!rc) {
- iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
- "Target has sent more R2Ts than it "
-@@ -555,7 +555,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- if (r2t->data_length == 0) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with zero data len\n");
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
- }
-@@ -571,7 +571,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- "invalid R2T with data len %u at offset %u "
- "and total length %d\n", r2t->data_length,
- r2t->data_offset, scsi_out(task->sc)->length);
-- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
-+ __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
- }
-@@ -581,7 +581,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
- r2t->sent = 0;
-
- tcp_task->exp_datasn = r2tsn + 1;
-- kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
-+ __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
- conn->r2t_pdus_cnt++;
-
- iscsi_requeue_task(task);
-@@ -952,7 +952,7 @@ int iscsi_tcp_task_init(struct iscsi_task *task)
- return conn->session->tt->init_pdu(task, 0, task->data_count);
- }
-
-- BUG_ON(kfifo_len(&tcp_task->r2tqueue));
-+ BUG_ON(__kfifo_len(tcp_task->r2tqueue));
- tcp_task->exp_datasn = 0;
-
- /* Prepare PDU, optionally w/ immediate data */
-@@ -983,7 +983,7 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
- if (r2t->data_length <= r2t->sent) {
- ISCSI_DBG_TCP(task->conn,
- " done with r2t %p\n", r2t);
-- kfifo_in(&tcp_task->r2tpool.queue,
-+ __kfifo_put(tcp_task->r2tpool.queue,
- (void *)&tcp_task->r2t,
- sizeof(void *));
- tcp_task->r2t = r2t = NULL;
-@@ -991,12 +991,9 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
- }
-
- if (r2t == NULL) {
-- if (kfifo_out(&tcp_task->r2tqueue,
-- (void *)&tcp_task->r2t, sizeof(void *)) !=
-- sizeof(void *))
-- r2t = NULL;
-- else
-- r2t = tcp_task->r2t;
-+ __kfifo_get(tcp_task->r2tqueue,
-+ (void *)&tcp_task->r2t, sizeof(void *));
-+ r2t = tcp_task->r2t;
- }
- spin_unlock_bh(&session->lock);
- }
-@@ -1131,8 +1128,9 @@ int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
- }
-
- /* R2T xmit queue */
-- if (kfifo_alloc(&tcp_task->r2tqueue,
-- session->max_r2t * 4 * sizeof(void*), GFP_KERNEL)) {
-+ tcp_task->r2tqueue = kfifo_alloc(
-+ session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
-+ if (tcp_task->r2tqueue == ERR_PTR(-ENOMEM)) {
- iscsi_pool_free(&tcp_task->r2tpool);
- goto r2t_alloc_fail;
- }
-@@ -1145,7 +1143,7 @@ r2t_alloc_fail:
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
-- kfifo_free(&tcp_task->r2tqueue);
-+ kfifo_free(tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
- return -ENOMEM;
-@@ -1160,7 +1158,7 @@ void iscsi_tcp_r2tpool_free(struct iscsi_session *session)
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
-- kfifo_free(&tcp_task->r2tqueue);
-+ kfifo_free(tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
- }
-diff --git a/libiscsi_tcp.h b/libiscsi_tcp.h
-index c020eee..3bacef5 100644
---- a/libiscsi_tcp.h
-+++ b/libiscsi_tcp.h
-@@ -80,7 +80,7 @@ struct iscsi_tcp_task {
- int data_offset;
- struct iscsi_r2t_info *r2t; /* in progress solict R2T */
- struct iscsi_pool r2tpool;
-- struct kfifo r2tqueue;
-+ struct kfifo *r2tqueue;
- void *dd_data;
- };
-
-diff --git a/open_iscsi_compat.h b/open_iscsi_compat.h
-new file mode 100644
-index 0000000..50ab84d
---- /dev/null
-+++ b/open_iscsi_compat.h
-@@ -0,0 +1,276 @@
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <scsi/scsi.h>
-+#include <scsi/scsi_cmnd.h>
-+
-+#ifndef OPEN_ISCSI_COMPAT
-+#define OPEN_ISCSI_COMPAT
-+
-+#ifndef SCAN_WILD_CARD
-+#define SCAN_WILD_CARD ~0
-+#endif
-+
-+#ifndef NIPQUAD_FMT
-+#define NIPQUAD_FMT "%u.%u.%u.%u"
-+#endif
-+
-+#ifndef NIP6_FMT
-+#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-+#endif
-+
-+#ifndef DEFINE_MUTEX
-+
-+/* mutex changes from 2.6.16-rc1 and up */
-+#define DEFINE_MUTEX DECLARE_MUTEX
-+#define mutex_lock down
-+#define mutex_unlock up
-+#define mutex semaphore
-+#define mutex_init init_MUTEX
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12)
-+
-+void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun)
-+{
-+ int i;
-+
-+ memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
-+
-+ for (i = 0; i < sizeof(lun); i += 2) {
-+ scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
-+ scsilun->scsi_lun[i+1] = lun & 0xFF;
-+ lun = lun >> 16;
-+ }
-+}
-+
-+#define __nlmsg_put(skb, daemon_pid, seq, type, len, flags) \
-+ __nlmsg_put(skb, daemon_pid, 0, 0, len)
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define gfp_t unsigned
-+
-+void *kzalloc(size_t size, gfp_t flags)
-+{
-+ void *ret = kmalloc(size, flags);
-+ if (ret)
-+ memset(ret, 0, size);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+
-+#include "linux/crypto.h"
-+
-+#define CRYPTO_ALG_ASYNC 0x00000080
-+struct hash_desc
-+{
-+ struct crypto_tfm *tfm;
-+ u32 flags;
-+};
-+
-+static inline int crypto_hash_init(struct hash_desc *desc)
-+{
-+ crypto_digest_init(desc->tfm);
-+ return 0;
-+}
-+
-+static inline int crypto_hash_digest(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes, u8 *out)
-+{
-+ crypto_digest_digest(desc->tfm, sg, 1, out);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_update(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes)
-+{
-+ crypto_digest_update(desc->tfm, sg, 1);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
-+{
-+ crypto_digest_final(desc->tfm, out);
-+ return 0;
-+}
-+
-+static inline struct crypto_tfm *crypto_alloc_hash(const char *alg_name,
-+ u32 type, u32 mask)
-+{
-+ struct crypto_tfm *ret = crypto_alloc_tfm(alg_name ,type);
-+ return ret ? ret : ERR_PTR(-ENOMEM);
-+}
-+
-+static inline void crypto_free_hash(struct crypto_tfm *tfm)
-+{
-+ crypto_free_tfm(tfm);
-+}
-+
-+int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 0);
-+}
-+
-+int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 1);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
-+
-+static inline int is_power_of_2(unsigned long n)
-+{
-+ return (n != 0 && ((n & (n - 1)) == 0));
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
-+{
-+ return (struct nlmsghdr *)skb->data;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+ return (void *)shost->hostdata;
-+}
-+
-+/*
-+ * Note: We do not support bidi for the compat modules if the kernel
-+ * does not have support.
-+ */
-+#define scsi_sg_count(cmd) ((cmd)->use_sg)
-+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
-+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
-+
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+ cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+ return cmd->resid;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+static inline unsigned long rounddown_pow_of_two(unsigned long n)
-+{
-+ return 1UL << (fls_long(n) - 1);
-+}
-+
-+
-+static inline struct scatterlist *sg_next(struct scatterlist *sg)
-+{
-+ if (!sg) {
-+ BUG();
-+ return NULL;
-+ }
-+ return sg + 1;
-+}
-+
-+#define for_each_sg(sglist, sg, nr, __i) \
-+ for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
-+
-+#define sg_page(_sg) _sg->page
-+
-+static inline void sg_set_page(struct scatterlist *sg, struct page *page,
-+ unsigned int len, unsigned int offset)
-+{
-+ sg->page = page;
-+ sg->offset = offset;
-+ sg->length = len;
-+}
-+
-+static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
-+{
-+ memset(sgl, 0, sizeof(*sgl) * nents);
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
-+
-+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
-+{
-+ return 0;
-+}
-+
-+#define netlink_kernel_release(_nls) \
-+ sock_release(_nls->sk_socket)
-+
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, input)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#endif
-+
-+#ifndef DID_TRANSPORT_DISRUPTED
-+#define DID_TRANSPORT_DISRUPTED DID_BUS_BUSY
-+#endif
-+
-+#ifndef DID_TRANSPORT_FAILFAST
-+#define DID_TRANSPORT_FAILFAST DID_NO_CONNECT
-+#endif
-+
-+#ifndef SCSI_MLQUEUE_TARGET_BUSY
-+#define SCSI_MLQUEUE_TARGET_BUSY SCSI_MLQUEUE_HOST_BUSY
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)
-+
-+#define BLK_EH_NOT_HANDLED EH_NOT_HANDLED
-+#define BLK_EH_RESET_TIMER EH_RESET_TIMER
-+
-+#define blk_eh_timer_return scsi_eh_timer_return
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34)
-+
-+static inline wait_queue_head_t *sk_sleep(struct sock *sk)
-+{
-+ return sk->sk_sleep;
-+}
-+
-+#endif
-+
-+#endif
---
-1.6.6.1
-
diff --git a/kernel/2.6.33-34_compat.patch b/kernel/2.6.33-34_compat.patch
deleted file mode 100644
index c43117d..0000000
--- a/kernel/2.6.33-34_compat.patch
+++ /dev/null
@@ -1,297 +0,0 @@
-diff --git a/iscsi_tcp.c b/iscsi_tcp.c
-index 2a401b9..197d314 100644
---- a/iscsi_tcp.c
-+++ b/iscsi_tcp.c
-@@ -43,6 +43,7 @@
- #include <scsi/scsi.h>
- #include "scsi_transport_iscsi.h"
-
-+#include "open_iscsi_compat.h"
- #include "iscsi_tcp.h"
-
- MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
-diff --git a/open_iscsi_compat.h b/open_iscsi_compat.h
-new file mode 100644
-index 0000000..50ab84d
---- /dev/null
-+++ b/open_iscsi_compat.h
-@@ -0,0 +1,276 @@
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <scsi/scsi.h>
-+#include <scsi/scsi_cmnd.h>
-+
-+#ifndef OPEN_ISCSI_COMPAT
-+#define OPEN_ISCSI_COMPAT
-+
-+#ifndef SCAN_WILD_CARD
-+#define SCAN_WILD_CARD ~0
-+#endif
-+
-+#ifndef NIPQUAD_FMT
-+#define NIPQUAD_FMT "%u.%u.%u.%u"
-+#endif
-+
-+#ifndef NIP6_FMT
-+#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-+#endif
-+
-+#ifndef DEFINE_MUTEX
-+
-+/* mutex changes from 2.6.16-rc1 and up */
-+#define DEFINE_MUTEX DECLARE_MUTEX
-+#define mutex_lock down
-+#define mutex_unlock up
-+#define mutex semaphore
-+#define mutex_init init_MUTEX
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12)
-+
-+void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun)
-+{
-+ int i;
-+
-+ memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
-+
-+ for (i = 0; i < sizeof(lun); i += 2) {
-+ scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
-+ scsilun->scsi_lun[i+1] = lun & 0xFF;
-+ lun = lun >> 16;
-+ }
-+}
-+
-+#define __nlmsg_put(skb, daemon_pid, seq, type, len, flags) \
-+ __nlmsg_put(skb, daemon_pid, 0, 0, len)
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define gfp_t unsigned
-+
-+void *kzalloc(size_t size, gfp_t flags)
-+{
-+ void *ret = kmalloc(size, flags);
-+ if (ret)
-+ memset(ret, 0, size);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+
-+#include "linux/crypto.h"
-+
-+#define CRYPTO_ALG_ASYNC 0x00000080
-+struct hash_desc
-+{
-+ struct crypto_tfm *tfm;
-+ u32 flags;
-+};
-+
-+static inline int crypto_hash_init(struct hash_desc *desc)
-+{
-+ crypto_digest_init(desc->tfm);
-+ return 0;
-+}
-+
-+static inline int crypto_hash_digest(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes, u8 *out)
-+{
-+ crypto_digest_digest(desc->tfm, sg, 1, out);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_update(struct hash_desc *desc,
-+ struct scatterlist *sg,
-+ unsigned int nbytes)
-+{
-+ crypto_digest_update(desc->tfm, sg, 1);
-+ return nbytes;
-+}
-+
-+static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
-+{
-+ crypto_digest_final(desc->tfm, out);
-+ return 0;
-+}
-+
-+static inline struct crypto_tfm *crypto_alloc_hash(const char *alg_name,
-+ u32 type, u32 mask)
-+{
-+ struct crypto_tfm *ret = crypto_alloc_tfm(alg_name ,type);
-+ return ret ? ret : ERR_PTR(-ENOMEM);
-+}
-+
-+static inline void crypto_free_hash(struct crypto_tfm *tfm)
-+{
-+ crypto_free_tfm(tfm);
-+}
-+
-+int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 0);
-+}
-+
-+int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
-+ int *addrlen)
-+{
-+ return sock->ops->getname(sock, addr, addrlen, 1);
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
-+
-+static inline int is_power_of_2(unsigned long n)
-+{
-+ return (n != 0 && ((n & (n - 1)) == 0));
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
-+{
-+ return (struct nlmsghdr *)skb->data;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+static inline void *shost_priv(struct Scsi_Host *shost)
-+{
-+ return (void *)shost->hostdata;
-+}
-+
-+/*
-+ * Note: We do not support bidi for the compat modules if the kernel
-+ * does not have support.
-+ */
-+#define scsi_sg_count(cmd) ((cmd)->use_sg)
-+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
-+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
-+
-+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
-+{
-+ cmd->resid = resid;
-+}
-+
-+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
-+{
-+ return cmd->resid;
-+}
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+static inline unsigned long rounddown_pow_of_two(unsigned long n)
-+{
-+ return 1UL << (fls_long(n) - 1);
-+}
-+
-+
-+static inline struct scatterlist *sg_next(struct scatterlist *sg)
-+{
-+ if (!sg) {
-+ BUG();
-+ return NULL;
-+ }
-+ return sg + 1;
-+}
-+
-+#define for_each_sg(sglist, sg, nr, __i) \
-+ for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
-+
-+#define sg_page(_sg) _sg->page
-+
-+static inline void sg_set_page(struct scatterlist *sg, struct page *page,
-+ unsigned int len, unsigned int offset)
-+{
-+ sg->page = page;
-+ sg->offset = offset;
-+ sg->length = len;
-+}
-+
-+static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
-+{
-+ memset(sgl, 0, sizeof(*sgl) * nents);
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
-+
-+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
-+{
-+ return 0;
-+}
-+
-+#define netlink_kernel_release(_nls) \
-+ sock_release(_nls->sk_socket)
-+
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, input)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
-+
-+#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \
-+ netlink_kernel_create(uint, groups, input, cb_mutex, mod)
-+
-+#endif
-+
-+#ifndef DID_TRANSPORT_DISRUPTED
-+#define DID_TRANSPORT_DISRUPTED DID_BUS_BUSY
-+#endif
-+
-+#ifndef DID_TRANSPORT_FAILFAST
-+#define DID_TRANSPORT_FAILFAST DID_NO_CONNECT
-+#endif
-+
-+#ifndef SCSI_MLQUEUE_TARGET_BUSY
-+#define SCSI_MLQUEUE_TARGET_BUSY SCSI_MLQUEUE_HOST_BUSY
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)
-+
-+#define BLK_EH_NOT_HANDLED EH_NOT_HANDLED
-+#define BLK_EH_RESET_TIMER EH_RESET_TIMER
-+
-+#define blk_eh_timer_return scsi_eh_timer_return
-+
-+#endif
-+
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34)
-+
-+static inline wait_queue_head_t *sk_sleep(struct sock *sk)
-+{
-+ return sk->sk_sleep;
-+}
-+
-+#endif
-+
-+#endif
---
-1.6.6.1
-
diff --git a/kernel/Makefile b/kernel/Makefile
deleted file mode 100644
index 395ba36..0000000
--- a/kernel/Makefile
+++ /dev/null
@@ -1,229 +0,0 @@
-#
-# Makefile for the Linux Kernel iSCSI Initiator
-#
-# This Makefile invokes KBuild from outside the kernel directory when
-# used from the main open-iscsi package. It also contains all of the
-# KBuild stuff needed to build the modules.
-#
-
-# Kbuild stuff, the following is the only part of this file that KBuild
-# actually uses itself.
-EXTRA_CFLAGS += -I$(obj) -I$(obj)/../include
-
-ifeq ($(DEBUG_SCSI), 1)
-EXTRA_CFLAGS += -DDEBUG_SCSI=1
-endif
-
-ifeq ($(DEBUG_TCP), 1)
-EXTRA_CFLAGS += -DDEBUG_TCP=1
-endif
-
-obj-m += scsi_transport_iscsi.o
-obj-m += libiscsi.o
-obj-m += libiscsi_tcp.o
-obj-m += iscsi_tcp.o
-
-# Everything beyond this point is used to call KBuild or handle support
-# for multiple kernel versions.
-
-# Kbuild verbosity
-V ?= 0
-
-# allow users to override these
-# eg to compile for a kernel that you aren't currently running
-KERNELRELEASE ?= $(shell uname -r)
-KSRC ?= /lib/modules/$(KERNELRELEASE)/build
-KBUILD_OUTPUT ?=
-# this is the basic Kbuild invocation, just append your make target
-KBUILD_BASE = +$(MAKE) -C $(KSRC) M=`pwd` KBUILD_OUTPUT=$(KBUILD_OUTPUT) $(KARCH) V=$(V)
-
-all: kernel_check
- $(KBUILD_BASE) modules
-
-# ============ BEGIN code for kernel_check and source patching ================
-# We calculate the Linux version for compilation. Than according to version,
-# if needed, we patch source-code to match the compiling kernel.
-# if you need a new kernel sub-version just add a target below.
-#
-# IMPORTANT: do "make clean" before submitting to SVN so source is in unpatched
-# form.
-
-#some constants
-14to23_patch=2.6.14-23_compat.patch
-24_patch=2.6.24_compat.patch
-26_patch=2.6.26_compat.patch
-27_patch=2.6.27_compat.patch
-28to32_patch=2.6.28-32_compat.patch
-33to34_patch=2.6.33-34_compat.patch
-all_patches=14to21_patch 20to21_patch 24_patch 26_patch 27_patch 28to32_patch 33to34_patch
-cur_patched=cur_patched
-
-## fun stuff for maintaining multiple versions
-
-# check to see if code is unpatched
-unpatch_code=$(shell test -e $(cur_patched) && echo do_unpatch_code )
-
-KSUBLEVEL = $(shell cat $(KSRC)/Makefile | awk -F= '/^SUBLEVEL =/ {print $$2}' | \
- sed 's/^[ \t]*//;s/[ \t]*$$//')
-
-
-KERNEL_TARGET=linux_2_6_$(KSUBLEVEL)
-kernel_check: $(KERNEL_TARGET)
-
-linux_2_6_14: has_14to23_patch
-
-linux_2_6_15: has_14to23_patch
-
-linux_2_6_16: has_14to23_patch
-
-linux_2_6_17: has_14to23_patch
-
-linux_2_6_18: has_14to23_patch
-
-linux_2_6_19: has_14to23_patch
-
-linux_2_6_20: has_14to23_patch
-
-linux_2_6_21: has_14to23_patch
-
-linux_2_6_22: has_14to23_patch
-
-linux_2_6_23: has_14to23_patch
-
-linux_2_6_24: has_24_patch
-
-linux_2_6_25: has_24_patch
-
-linux_2_6_26: has_26_patch
-
-linux_2_6_27: has_27_patch
-
-linux_2_6_28: has_28to32_patch
-
-linux_2_6_29: has_28to32_patch
-
-linux_2_6_30: has_28to32_patch
-
-linux_2_6_31: has_28to32_patch
-
-linux_2_6_32: has_28to32_patch
-
-linux_2_6_33: has_33to34_patch
-
-linux_2_6_34: has_33to34_patch
-
-linux_2_6_35: $(unpatch_code)
-
-do_unpatch_code:
- echo "Un-patching source code for use with linux-2.6.14 and up ..."
- patch -R -E -p1 < $(cur_patched)
- rm -f `readlink $(cur_patched)`
- rm -f $(cur_patched)
-
-# these below targets must be the same as the variable name prefixed by has_
-# otherwise below compat_patch: target will not work
-has_14to23_patch: $(14to23_patch)
- echo "Patching source code for linux-2.6.14-23 ..."
- if [ -e $(cur_patched) ]; then \
- make -C . clean; \
- fi
- patch -p1 < $(14to23_patch)
- cp $(14to23_patch) $@
- ln -s $@ $(cur_patched)
-
-has_24_patch: $(24_patch)
- echo "Patching source code for linux-2.6.24-25 ..."
- if [ -e $(cur_patched) ]; then \
- make -C . clean; \
- fi
- patch -p1 < $(24_patch)
- cp $(24_patch) $@
- ln -s $@ $(cur_patched)
-
-has_26_patch: $(26_patch)
- echo "Patching source code for linux-2.6.26 ..."
- if [ -e $(cur_patched) ]; then \
- make -C . clean; \
- fi
- patch -p1 < $(26_patch)
- cp $(26_patch) $@
- ln -s $@ $(cur_patched)
-
-has_27_patch: $(27_patch)
- echo "Patching source code for linux-2.6.27 ..."
- if [ -e $(cur_patched) ]; then \
- make -C . clean; \
- fi
- patch -p1 < $(27_patch)
- cp $(27_patch) $@
- ln -s $@ $(cur_patched)
-
-has_28to32_patch: $(28to32_patch)
- echo "Patching source code for linux-2.6.28-33 ..."
- if [ -e $(cur_patched) ]; then \
- make -C . clean; \
- fi
- patch -p1 < $(28to32_patch)
- cp $(28to32_patch) $@
- ln -s $@ $(cur_patched)
-
-has_33to34_patch: $(33to34_patch)
- echo "Patching source code for linux-2.6.33-34 ..."
- if [ -e $(cur_patched) ]; then \
- make -C . clean; \
- fi
- patch -p1 < $(33to34_patch)
- cp $(33to34_patch) $@
- ln -s $@ $(cur_patched)
-
-
-# ============ END code for kernel_check and source patching =================
-
-clean: $(unpatch_code)
- $(KBUILD_BASE) clean
- rm -f Module.symvers
-
-## The following compat_patch target is what we need to do to prepare a clean
-# compat_patch set after new code is check-in to svn. To keep patches fuzzless.
-# the new patches are written into .new files so svn diff of next file will
-# not trip on them.
-compat_patch: $(unpatch_code)
- test -z "$(svn diff|head)" || { \
- echo "please run make compat_patch after changse are submited to svn"; \
- exit 1; \
- }
- for the_patch in all_patches ; do \
- make -C . has_$(the_patch); \
- svn diff > ${!the_patch}.new; \
- done
-
-# the following is only for convienience
-# do not submit to Linus
-# it's also called from the toplevel makefile
-
-# INSTALL_MOD_DIR is set so that the drivers go into the correct location using Kbuild
-# it defaults to 'extra' otherwise
-INSTALL_MOD_DIR ?= kernel/drivers/scsi
-
-# this allows packaging of modules
-ifdef DESTDIR
-INSTALL_MOD_PATH=$(DESTDIR)
-else
-INSTALL_MOD_PATH=
-endif
-
-# this evil rule ensures that the modules get build if you specify $(ko)
-# as a dependency.
-ko = $(patsubst %.o,%.ko,$(obj-m))
-$(ko): all
-
-# now the actual command
-install_kernel: $(ko)
- $(KBUILD_BASE) modules_install INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) INSTALL_MOD_PATH=$(INSTALL_MOD_PATH)
-
-dpkg_divert:
- for module in $(ko) ; do \
- dpkg-divert --rename /lib/modules/$(KERNELRELEASE)/$(INSTALL_MOD_DIR)/$$module ; \
- done
-
-# vim: ft=make tw=72 sw=4 ts=4:
diff --git a/kernel/iscsi_tcp.c b/kernel/iscsi_tcp.c
deleted file mode 100644
index 0ccf2b4..0000000
--- a/kernel/iscsi_tcp.c
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- * iSCSI Initiator over TCP/IP Data-Path
- *
- * Copyright (C) 2004 Dmitry Yusupov
- * Copyright (C) 2004 Alex Aizman
- * Copyright (C) 2005 - 2006 Mike Christie
- * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
- * maintained by open-iscsi@googlegroups.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * See the file COPYING included with this distribution for more details.
- *
- * Credits:
- * Christoph Hellwig
- * FUJITA Tomonori
- * Arne Redlich
- * Zhenyu Wang
- */
-#include <linux/version.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/inet.h>
-#include <linux/slab.h>
-#include <linux/file.h>
-#include <linux/blkdev.h>
-#include <linux/crypto.h>
-#include <linux/delay.h>
-#include <linux/kfifo.h>
-#include <linux/scatterlist.h>
-#include <net/tcp.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi.h>
-#include "scsi_transport_iscsi.h"
-
-#include "iscsi_tcp.h"
-
-MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
- "Dmitry Yusupov <dmitry_yus@yahoo.com>, "
- "Alex Aizman <itn780@yahoo.com>");
-MODULE_DESCRIPTION("iSCSI/TCP data-path");
-MODULE_LICENSE("GPL");
-
-static struct scsi_transport_template *iscsi_sw_tcp_scsi_transport;
-static struct scsi_host_template iscsi_sw_tcp_sht;
-static struct iscsi_transport iscsi_sw_tcp_transport;
-
-static unsigned int iscsi_max_lun = 512;
-module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
-
-static int iscsi_sw_tcp_dbg;
-module_param_named(debug_iscsi_tcp, iscsi_sw_tcp_dbg, int,
- S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug_iscsi_tcp, "Turn on debugging for iscsi_tcp module "
- "Set to 1 to turn on, and zero to turn off. Default is off.");
-
-#define ISCSI_SW_TCP_DBG(_conn, dbg_fmt, arg...) \
- do { \
- if (iscsi_sw_tcp_dbg) \
- iscsi_conn_printk(KERN_INFO, _conn, \
- "%s " dbg_fmt, \
- __func__, ##arg); \
- } while (0);
-
-
-/**
- * iscsi_sw_tcp_recv - TCP receive in sendfile fashion
- * @rd_desc: read descriptor
- * @skb: socket buffer
- * @offset: offset in skb
- * @len: skb->len - offset
- */
-static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
- unsigned int offset, size_t len)
-{
- struct iscsi_conn *conn = rd_desc->arg.data;
- unsigned int consumed, total_consumed = 0;
- int status;
-
- ISCSI_SW_TCP_DBG(conn, "in %d bytes\n", skb->len - offset);
-
- do {
- status = 0;
- consumed = iscsi_tcp_recv_skb(conn, skb, offset, 0, &status);
- offset += consumed;
- total_consumed += consumed;
- } while (consumed != 0 && status != ISCSI_TCP_SKB_DONE);
-
- ISCSI_SW_TCP_DBG(conn, "read %d bytes status %d\n",
- skb->len - offset, status);
- return total_consumed;
-}
-
-/**
- * iscsi_sw_sk_state_check - check socket state
- * @sk: socket
- *
- * If the socket is in CLOSE or CLOSE_WAIT we should
- * not close the connection if there is still some
- * data pending.
- */
-static inline int iscsi_sw_sk_state_check(struct sock *sk)
-{
- struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data;
-
- if ((sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) &&
- !atomic_read(&sk->sk_rmem_alloc)) {
- ISCSI_SW_TCP_DBG(conn, "TCP_CLOSE|TCP_CLOSE_WAIT\n");
- iscsi_conn_failure(conn, ISCSI_ERR_TCP_CONN_CLOSE);
- return -ECONNRESET;
- }
- return 0;
-}
-
-static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag)
-{
- struct iscsi_conn *conn = sk->sk_user_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- read_descriptor_t rd_desc;
-
- read_lock(&sk->sk_callback_lock);
-
- /*
- * Use rd_desc to pass 'conn' to iscsi_tcp_recv.
- * We set count to 1 because we want the network layer to
- * hand us all the skbs that are available. iscsi_tcp_recv
- * handled pdus that cross buffers or pdus that still need data.
- */
- rd_desc.arg.data = conn;
- rd_desc.count = 1;
- tcp_read_sock(sk, &rd_desc, iscsi_sw_tcp_recv);
-
- iscsi_sw_sk_state_check(sk);
-
- read_unlock(&sk->sk_callback_lock);
-
- /* If we had to (atomically) map a highmem page,
- * unmap it now. */
- iscsi_tcp_segment_unmap(&tcp_conn->in.segment);
-}
-
-static void iscsi_sw_tcp_state_change(struct sock *sk)
-{
- struct iscsi_tcp_conn *tcp_conn;
- struct iscsi_sw_tcp_conn *tcp_sw_conn;
- struct iscsi_conn *conn;
- struct iscsi_session *session;
- void (*old_state_change)(struct sock *);
-
- read_lock(&sk->sk_callback_lock);
-
- conn = (struct iscsi_conn*)sk->sk_user_data;
- session = conn->session;
-
- iscsi_sw_sk_state_check(sk);
-
- tcp_conn = conn->dd_data;
- tcp_sw_conn = tcp_conn->dd_data;
- old_state_change = tcp_sw_conn->old_state_change;
-
- read_unlock(&sk->sk_callback_lock);
-
- old_state_change(sk);
-}
-
-/**
- * iscsi_write_space - Called when more output buffer space is available
- * @sk: socket space is available for
- **/
-static void iscsi_sw_tcp_write_space(struct sock *sk)
-{
- struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
-
- tcp_sw_conn->old_write_space(sk);
- ISCSI_SW_TCP_DBG(conn, "iscsi_write_space\n");
- iscsi_conn_queue_work(conn);
-}
-
-static void iscsi_sw_tcp_conn_set_callbacks(struct iscsi_conn *conn)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct sock *sk = tcp_sw_conn->sock->sk;
-
- /* assign new callbacks */
- write_lock_bh(&sk->sk_callback_lock);
- sk->sk_user_data = conn;
- tcp_sw_conn->old_data_ready = sk->sk_data_ready;
- tcp_sw_conn->old_state_change = sk->sk_state_change;
- tcp_sw_conn->old_write_space = sk->sk_write_space;
- sk->sk_data_ready = iscsi_sw_tcp_data_ready;
- sk->sk_state_change = iscsi_sw_tcp_state_change;
- sk->sk_write_space = iscsi_sw_tcp_write_space;
- write_unlock_bh(&sk->sk_callback_lock);
-}
-
-static void
-iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_conn *conn)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct sock *sk = tcp_sw_conn->sock->sk;
-
- /* restore socket callbacks, see also: iscsi_conn_set_callbacks() */
- write_lock_bh(&sk->sk_callback_lock);
- sk->sk_user_data = NULL;
- sk->sk_data_ready = tcp_sw_conn->old_data_ready;
- sk->sk_state_change = tcp_sw_conn->old_state_change;
- sk->sk_write_space = tcp_sw_conn->old_write_space;
- sk->sk_no_check = 0;
- write_unlock_bh(&sk->sk_callback_lock);
-}
-
-/**
- * iscsi_sw_tcp_xmit_segment - transmit segment
- * @tcp_conn: the iSCSI TCP connection
- * @segment: the buffer to transmnit
- *
- * This function transmits as much of the buffer as
- * the network layer will accept, and returns the number of
- * bytes transmitted.
- *
- * If CRC hashing is enabled, the function will compute the
- * hash as it goes. When the entire segment has been transmitted,
- * it will retrieve the hash value and send it as well.
- */
-static int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn,
- struct iscsi_segment *segment)
-{
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct socket *sk = tcp_sw_conn->sock;
- unsigned int copied = 0;
- int r = 0;
-
- while (!iscsi_tcp_segment_done(tcp_conn, segment, 0, r)) {
- struct scatterlist *sg;
- unsigned int offset, copy;
- int flags = 0;
-
- r = 0;
- offset = segment->copied;
- copy = segment->size - offset;
-
- if (segment->total_copied + segment->size < segment->total_size)
- flags |= MSG_MORE;
-
- /* Use sendpage if we can; else fall back to sendmsg */
- if (!segment->data) {
- sg = segment->sg;
- offset += segment->sg_offset + sg->offset;
- r = tcp_sw_conn->sendpage(sk, sg_page(sg), offset,
- copy, flags);
- } else {
- struct msghdr msg = { .msg_flags = flags };
- struct kvec iov = {
- .iov_base = segment->data + offset,
- .iov_len = copy
- };
-
- r = kernel_sendmsg(sk, &msg, &iov, 1, copy);
- }
-
- if (r < 0) {
- iscsi_tcp_segment_unmap(segment);
- return r;
- }
- copied += r;
- }
- return copied;
-}
-
-/**
- * iscsi_sw_tcp_xmit - TCP transmit
- **/
-static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct iscsi_segment *segment = &tcp_sw_conn->out.segment;
- unsigned int consumed = 0;
- int rc = 0;
-
- while (1) {
- rc = iscsi_sw_tcp_xmit_segment(tcp_conn, segment);
- /*
- * We may not have been able to send data because the conn
- * is getting stopped. libiscsi will know so propagate err
- * for it to do the right thing.
- */
- if (rc == -EAGAIN)
- return rc;
- else if (rc < 0) {
- rc = ISCSI_ERR_XMIT_FAILED;
- goto error;
- } else if (rc == 0)
- break;
-
- consumed += rc;
-
- if (segment->total_copied >= segment->total_size) {
- if (segment->done != NULL) {
- rc = segment->done(tcp_conn, segment);
- if (rc != 0)
- goto error;
- }
- }
- }
-
- ISCSI_SW_TCP_DBG(conn, "xmit %d bytes\n", consumed);
-
- conn->txdata_octets += consumed;
- return consumed;
-
-error:
- /* Transmit error. We could initiate error recovery
- * here. */
- ISCSI_SW_TCP_DBG(conn, "Error sending PDU, errno=%d\n", rc);
- iscsi_conn_failure(conn, rc);
- return -EIO;
-}
-
-/**
- * iscsi_tcp_xmit_qlen - return the number of bytes queued for xmit
- */
-static inline int iscsi_sw_tcp_xmit_qlen(struct iscsi_conn *conn)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct iscsi_segment *segment = &tcp_sw_conn->out.segment;
-
- return segment->total_copied - segment->total_size;
-}
-
-static int iscsi_sw_tcp_pdu_xmit(struct iscsi_task *task)
-{
- struct iscsi_conn *conn = task->conn;
- int rc;
-
- while (iscsi_sw_tcp_xmit_qlen(conn)) {
- rc = iscsi_sw_tcp_xmit(conn);
- if (rc == 0)
- return -EAGAIN;
- if (rc < 0)
- return rc;
- }
-
- return 0;
-}
-
-/*
- * This is called when we're done sending the header.
- * Simply copy the data_segment to the send segment, and return.
- */
-static int iscsi_sw_tcp_send_hdr_done(struct iscsi_tcp_conn *tcp_conn,
- struct iscsi_segment *segment)
-{
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
-
- tcp_sw_conn->out.segment = tcp_sw_conn->out.data_segment;
- ISCSI_SW_TCP_DBG(tcp_conn->iscsi_conn,
- "Header done. Next segment size %u total_size %u\n",
- tcp_sw_conn->out.segment.size,
- tcp_sw_conn->out.segment.total_size);
- return 0;
-}
-
-static void iscsi_sw_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr,
- size_t hdrlen)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
-
- ISCSI_SW_TCP_DBG(conn, "%s\n", conn->hdrdgst_en ?
- "digest enabled" : "digest disabled");
-
- /* Clear the data segment - needs to be filled in by the
- * caller using iscsi_tcp_send_data_prep() */
- memset(&tcp_sw_conn->out.data_segment, 0,
- sizeof(struct iscsi_segment));
-
- /* If header digest is enabled, compute the CRC and
- * place the digest into the same buffer. We make
- * sure that both iscsi_tcp_task and mtask have
- * sufficient room.
- */
- if (conn->hdrdgst_en) {
- iscsi_tcp_dgst_header(&tcp_sw_conn->tx_hash, hdr, hdrlen,
- hdr + hdrlen);
- hdrlen += ISCSI_DIGEST_SIZE;
- }
-
- /* Remember header pointer for later, when we need
- * to decide whether there's a payload to go along
- * with the header. */
- tcp_sw_conn->out.hdr = hdr;
-
- iscsi_segment_init_linear(&tcp_sw_conn->out.segment, hdr, hdrlen,
- iscsi_sw_tcp_send_hdr_done, NULL);
-}
-
-/*
- * Prepare the send buffer for the payload data.
- * Padding and checksumming will all be taken care
- * of by the iscsi_segment routines.
- */
-static int
-iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg,
- unsigned int count, unsigned int offset,
- unsigned int len)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct hash_desc *tx_hash = NULL;
- unsigned int hdr_spec_len;
-
- ISCSI_SW_TCP_DBG(conn, "offset=%d, datalen=%d %s\n", offset, len,
- conn->datadgst_en ?
- "digest enabled" : "digest disabled");
-
- /* Make sure the datalen matches what the caller
- said he would send. */
- hdr_spec_len = ntoh24(tcp_sw_conn->out.hdr->dlength);
- WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
-
- if (conn->datadgst_en)
- tx_hash = &tcp_sw_conn->tx_hash;
-
- return iscsi_segment_seek_sg(&tcp_sw_conn->out.data_segment,
- sg, count, offset, len,
- NULL, tx_hash);
-}
-
-static void
-iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data,
- size_t len)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct hash_desc *tx_hash = NULL;
- unsigned int hdr_spec_len;
-
- ISCSI_SW_TCP_DBG(conn, "datalen=%zd %s\n", len, conn->datadgst_en ?
- "digest enabled" : "digest disabled");
-
- /* Make sure the datalen matches what the caller
- said he would send. */
- hdr_spec_len = ntoh24(tcp_sw_conn->out.hdr->dlength);
- WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
-
- if (conn->datadgst_en)
- tx_hash = &tcp_sw_conn->tx_hash;
-
- iscsi_segment_init_linear(&tcp_sw_conn->out.data_segment,
- data, len, NULL, tx_hash);
-}
-
-static int iscsi_sw_tcp_pdu_init(struct iscsi_task *task,
- unsigned int offset, unsigned int count)
-{
- struct iscsi_conn *conn = task->conn;
- int err = 0;
-
- iscsi_sw_tcp_send_hdr_prep(conn, task->hdr, task->hdr_len);
-
- if (!count)
- return 0;
-
- if (!task->sc)
- iscsi_sw_tcp_send_linear_data_prep(conn, task->data, count);
- else {
- struct scsi_data_buffer *sdb = scsi_out(task->sc);
-
- err = iscsi_sw_tcp_send_data_prep(conn, sdb->table.sgl,
- sdb->table.nents, offset,
- count);
- }
-
- if (err) {
- /* got invalid offset/len */
- return -EIO;
- }
- return 0;
-}
-
-static int iscsi_sw_tcp_pdu_alloc(struct iscsi_task *task, uint8_t opcode)
-{
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
- task->hdr = task->dd_data + sizeof(*tcp_task);
- task->hdr_max = sizeof(struct iscsi_sw_tcp_hdrbuf) - ISCSI_DIGEST_SIZE;
- return 0;
-}
-
-static struct iscsi_cls_conn *
-iscsi_sw_tcp_conn_create(struct iscsi_cls_session *cls_session,
- uint32_t conn_idx)
-{
- struct iscsi_conn *conn;
- struct iscsi_cls_conn *cls_conn;
- struct iscsi_tcp_conn *tcp_conn;
- struct iscsi_sw_tcp_conn *tcp_sw_conn;
-
- cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*tcp_sw_conn),
- conn_idx);
- if (!cls_conn)
- return NULL;
- conn = cls_conn->dd_data;
- tcp_conn = conn->dd_data;
- tcp_sw_conn = tcp_conn->dd_data;
-
- tcp_sw_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
- CRYPTO_ALG_ASYNC);
- tcp_sw_conn->tx_hash.flags = 0;
- if (IS_ERR(tcp_sw_conn->tx_hash.tfm))
- goto free_conn;
-
- tcp_sw_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
- CRYPTO_ALG_ASYNC);
- tcp_sw_conn->rx_hash.flags = 0;
- if (IS_ERR(tcp_sw_conn->rx_hash.tfm))
- goto free_tx_tfm;
- tcp_conn->rx_hash = &tcp_sw_conn->rx_hash;
-
- return cls_conn;
-
-free_tx_tfm:
- crypto_free_hash(tcp_sw_conn->tx_hash.tfm);
-free_conn:
- iscsi_conn_printk(KERN_ERR, conn,
- "Could not create connection due to crc32c "
- "loading error. Make sure the crc32c "
- "module is built as a module or into the "
- "kernel\n");
- iscsi_tcp_conn_teardown(cls_conn);
- return NULL;
-}
-
-static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn)
-{
- struct iscsi_session *session = conn->session;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct socket *sock = tcp_sw_conn->sock;
-
- if (!sock)
- return;
-
- sock_hold(sock->sk);
- iscsi_sw_tcp_conn_restore_callbacks(conn);
- sock_put(sock->sk);
-
- spin_lock_bh(&session->lock);
- tcp_sw_conn->sock = NULL;
- spin_unlock_bh(&session->lock);
- sockfd_put(sock);
-}
-
-static void iscsi_sw_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
-
- iscsi_sw_tcp_release_conn(conn);
-
- if (tcp_sw_conn->tx_hash.tfm)
- crypto_free_hash(tcp_sw_conn->tx_hash.tfm);
- if (tcp_sw_conn->rx_hash.tfm)
- crypto_free_hash(tcp_sw_conn->rx_hash.tfm);
-
- iscsi_tcp_conn_teardown(cls_conn);
-}
-
-static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct socket *sock = tcp_sw_conn->sock;
-
- /* userspace may have goofed up and not bound us */
- if (!sock)
- return;
- /*
- * Make sure our recv side is stopped.
- * Older tools called conn stop before ep_disconnect
- * so IO could still be coming in.
- */
- write_lock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock);
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
- write_unlock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock);
-
- sock->sk->sk_err = EIO;
- wake_up_interruptible(sk_sleep(sock->sk));
-
- iscsi_conn_stop(cls_conn, flag);
- iscsi_sw_tcp_release_conn(conn);
-}
-
-static int iscsi_sw_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock,
- char *buf, int *port,
- int (*getname)(struct socket *,
- struct sockaddr *,
- int *addrlen))
-{
- struct sockaddr_storage *addr;
- struct sockaddr_in6 *sin6;
- struct sockaddr_in *sin;
- int rc = 0, len;
-
- addr = kmalloc(sizeof(*addr), GFP_KERNEL);
- if (!addr)
- return -ENOMEM;
-
- if (getname(sock, (struct sockaddr *) addr, &len)) {
- rc = -ENODEV;
- goto free_addr;
- }
-
- switch (addr->ss_family) {
- case AF_INET:
- sin = (struct sockaddr_in *)addr;
- spin_lock_bh(&conn->session->lock);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
- sprintf(buf, "%pI4", &sin->sin_addr.s_addr);
-#else
- sprintf(buf, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
-#endif
- *port = be16_to_cpu(sin->sin_port);
- spin_unlock_bh(&conn->session->lock);
- break;
- case AF_INET6:
- sin6 = (struct sockaddr_in6 *)addr;
- spin_lock_bh(&conn->session->lock);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
- sprintf(buf, "%pI6", &sin6->sin6_addr);
-#else
- sprintf(buf, NIP6_FMT, NIP6(sin6->sin6_addr));
-#endif
- *port = be16_to_cpu(sin6->sin6_port);
- spin_unlock_bh(&conn->session->lock);
- break;
- }
-free_addr:
- kfree(addr);
- return rc;
-}
-
-static int
-iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session,
- struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
- int is_leading)
-{
- struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
- struct iscsi_host *ihost = shost_priv(shost);
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- struct sock *sk;
- struct socket *sock;
- int err;
-
- /* lookup for existing socket */
- sock = sockfd_lookup((int)transport_eph, &err);
- if (!sock) {
- iscsi_conn_printk(KERN_ERR, conn,
- "sockfd_lookup failed %d\n", err);
- return -EEXIST;
- }
- /*
- * copy these values now because if we drop the session
- * userspace may still want to query the values since we will
- * be using them for the reconnect
- */
- err = iscsi_sw_tcp_get_addr(conn, sock, conn->portal_address,
- &conn->portal_port, kernel_getpeername);
- if (err)
- goto free_socket;
-
- err = iscsi_sw_tcp_get_addr(conn, sock, ihost->local_address,
- &ihost->local_port, kernel_getsockname);
- if (err)
- goto free_socket;
-
- err = iscsi_conn_bind(cls_session, cls_conn, is_leading);
- if (err)
- goto free_socket;
-
- /* bind iSCSI connection and socket */
- tcp_sw_conn->sock = sock;
-
- /* setup Socket parameters */
- sk = sock->sk;
- sk->sk_reuse = 1;
- sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */
- sk->sk_allocation = GFP_ATOMIC;
-
- iscsi_sw_tcp_conn_set_callbacks(conn);
- tcp_sw_conn->sendpage = tcp_sw_conn->sock->ops->sendpage;
- /*
- * set receive state machine into initial state
- */
- iscsi_tcp_hdr_recv_prep(tcp_conn);
- return 0;
-
-free_socket:
- sockfd_put(sock);
- return err;
-}
-
-static int iscsi_sw_tcp_conn_set_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf,
- int buflen)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_session *session = conn->session;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
- int value;
-
- switch(param) {
- case ISCSI_PARAM_HDRDGST_EN:
- iscsi_set_param(cls_conn, param, buf, buflen);
- break;
- case ISCSI_PARAM_DATADGST_EN:
- iscsi_set_param(cls_conn, param, buf, buflen);
- tcp_sw_conn->sendpage = conn->datadgst_en ?
- sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage;
- break;
- case ISCSI_PARAM_MAX_R2T:
- sscanf(buf, "%d", &value);
- if (value <= 0 || !is_power_of_2(value))
- return -EINVAL;
- if (session->max_r2t == value)
- break;
- iscsi_tcp_r2tpool_free(session);
- iscsi_set_param(cls_conn, param, buf, buflen);
- if (iscsi_tcp_r2tpool_alloc(session))
- return -ENOMEM;
- break;
- default:
- return iscsi_set_param(cls_conn, param, buf, buflen);
- }
-
- return 0;
-}
-
-static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- int len;
-
- switch(param) {
- case ISCSI_PARAM_CONN_PORT:
- spin_lock_bh(&conn->session->lock);
- len = sprintf(buf, "%hu\n", conn->portal_port);
- spin_unlock_bh(&conn->session->lock);
- break;
- case ISCSI_PARAM_CONN_ADDRESS:
- spin_lock_bh(&conn->session->lock);
- len = sprintf(buf, "%s\n", conn->portal_address);
- spin_unlock_bh(&conn->session->lock);
- break;
- default:
- return iscsi_conn_get_param(cls_conn, param, buf);
- }
-
- return len;
-}
-
-static void
-iscsi_sw_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
- struct iscsi_stats *stats)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
-
- stats->custom_length = 3;
- strcpy(stats->custom[0].desc, "tx_sendpage_failures");
- stats->custom[0].value = tcp_sw_conn->sendpage_failures_cnt;
- strcpy(stats->custom[1].desc, "rx_discontiguous_hdr");
- stats->custom[1].value = tcp_sw_conn->discontiguous_hdr_cnt;
- strcpy(stats->custom[2].desc, "eh_abort_cnt");
- stats->custom[2].value = conn->eh_abort_cnt;
-
- iscsi_tcp_conn_get_stats(cls_conn, stats);
-}
-
-static struct iscsi_cls_session *
-iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
- uint16_t qdepth, uint32_t initial_cmdsn)
-{
- struct iscsi_cls_session *cls_session;
- struct iscsi_session *session;
- struct Scsi_Host *shost;
-
- if (ep) {
- printk(KERN_ERR "iscsi_tcp: invalid ep %p.\n", ep);
- return NULL;
- }
-
- shost = iscsi_host_alloc(&iscsi_sw_tcp_sht, 0, 1);
- if (!shost)
- return NULL;
- shost->transportt = iscsi_sw_tcp_scsi_transport;
- shost->cmd_per_lun = qdepth;
- shost->max_lun = iscsi_max_lun;
- shost->max_id = 0;
- shost->max_channel = 0;
- shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE;
-
- if (iscsi_host_add(shost, NULL))
- goto free_host;
-
- cls_session = iscsi_session_setup(&iscsi_sw_tcp_transport, shost,
- cmds_max, 0,
- sizeof(struct iscsi_tcp_task) +
- sizeof(struct iscsi_sw_tcp_hdrbuf),
- initial_cmdsn, 0);
- if (!cls_session)
- goto remove_host;
- session = cls_session->dd_data;
-
- shost->can_queue = session->scsi_cmds_max;
- if (iscsi_tcp_r2tpool_alloc(session))
- goto remove_session;
- return cls_session;
-
-remove_session:
- iscsi_session_teardown(cls_session);
-remove_host:
- iscsi_host_remove(shost);
-free_host:
- iscsi_host_free(shost);
- return NULL;
-}
-
-static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
-{
- struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
-
- iscsi_tcp_r2tpool_free(cls_session->dd_data);
- iscsi_session_teardown(cls_session);
-
- iscsi_host_remove(shost);
- iscsi_host_free(shost);
-}
-
-static int iscsi_sw_tcp_slave_alloc(struct scsi_device *sdev)
-{
- set_bit(QUEUE_FLAG_BIDI, &sdev->request_queue->queue_flags);
- return 0;
-}
-
-static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev)
-{
- blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_ANY);
- blk_queue_dma_alignment(sdev->request_queue, 0);
- return 0;
-}
-
-static struct scsi_host_template iscsi_sw_tcp_sht = {
- .module = THIS_MODULE,
- .name = "iSCSI Initiator over TCP/IP",
- .queuecommand = iscsi_queuecommand,
- .change_queue_depth = iscsi_change_queue_depth,
- .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1,
- .sg_tablesize = 4096,
- .max_sectors = 0xFFFF,
- .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
- .eh_abort_handler = iscsi_eh_abort,
- .eh_device_reset_handler= iscsi_eh_device_reset,
- .eh_target_reset_handler = iscsi_eh_recover_target,
- .use_clustering = DISABLE_CLUSTERING,
- .slave_alloc = iscsi_sw_tcp_slave_alloc,
- .slave_configure = iscsi_sw_tcp_slave_configure,
- .target_alloc = iscsi_target_alloc,
- .proc_name = "iscsi_tcp",
- .this_id = -1,
-};
-
-static struct iscsi_transport iscsi_sw_tcp_transport = {
- .owner = THIS_MODULE,
- .name = "tcp",
- .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST
- | CAP_DATADGST,
- .param_mask = ISCSI_MAX_RECV_DLENGTH |
- ISCSI_MAX_XMIT_DLENGTH |
- ISCSI_HDRDGST_EN |
- ISCSI_DATADGST_EN |
- ISCSI_INITIAL_R2T_EN |
- ISCSI_MAX_R2T |
- ISCSI_IMM_DATA_EN |
- ISCSI_FIRST_BURST |
- ISCSI_MAX_BURST |
- ISCSI_PDU_INORDER_EN |
- ISCSI_DATASEQ_INORDER_EN |
- ISCSI_ERL |
- ISCSI_CONN_PORT |
- ISCSI_CONN_ADDRESS |
- ISCSI_EXP_STATSN |
- ISCSI_PERSISTENT_PORT |
- ISCSI_PERSISTENT_ADDRESS |
- ISCSI_TARGET_NAME | ISCSI_TPGT |
- ISCSI_USERNAME | ISCSI_PASSWORD |
- ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
- ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
- ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
- ISCSI_PING_TMO | ISCSI_RECV_TMO |
- ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
- .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
- ISCSI_HOST_INITIATOR_NAME |
- ISCSI_HOST_NETDEV_NAME,
- /* session management */
- .create_session = iscsi_sw_tcp_session_create,
- .destroy_session = iscsi_sw_tcp_session_destroy,
- /* connection management */
- .create_conn = iscsi_sw_tcp_conn_create,
- .bind_conn = iscsi_sw_tcp_conn_bind,
- .destroy_conn = iscsi_sw_tcp_conn_destroy,
- .set_param = iscsi_sw_tcp_conn_set_param,
- .get_conn_param = iscsi_sw_tcp_conn_get_param,
- .get_session_param = iscsi_session_get_param,
- .start_conn = iscsi_conn_start,
- .stop_conn = iscsi_sw_tcp_conn_stop,
- /* iscsi host params */
- .get_host_param = iscsi_host_get_param,
- .set_host_param = iscsi_host_set_param,
- /* IO */
- .send_pdu = iscsi_conn_send_pdu,
- .get_stats = iscsi_sw_tcp_conn_get_stats,
- /* iscsi task/cmd helpers */
- .init_task = iscsi_tcp_task_init,
- .xmit_task = iscsi_tcp_task_xmit,
- .cleanup_task = iscsi_tcp_cleanup_task,
- /* low level pdu helpers */
- .xmit_pdu = iscsi_sw_tcp_pdu_xmit,
- .init_pdu = iscsi_sw_tcp_pdu_init,
- .alloc_pdu = iscsi_sw_tcp_pdu_alloc,
- /* recovery */
- .session_recovery_timedout = iscsi_session_recovery_timedout,
-};
-
-static int __init iscsi_sw_tcp_init(void)
-{
- if (iscsi_max_lun < 1) {
- printk(KERN_ERR "iscsi_tcp: Invalid max_lun value of %u\n",
- iscsi_max_lun);
- return -EINVAL;
- }
-
- iscsi_sw_tcp_scsi_transport = iscsi_register_transport(
- &iscsi_sw_tcp_transport);
- if (!iscsi_sw_tcp_scsi_transport)
- return -ENODEV;
-
- return 0;
-}
-
-static void __exit iscsi_sw_tcp_exit(void)
-{
- iscsi_unregister_transport(&iscsi_sw_tcp_transport);
-}
-
-module_init(iscsi_sw_tcp_init);
-module_exit(iscsi_sw_tcp_exit);
diff --git a/kernel/iscsi_tcp.h b/kernel/iscsi_tcp.h
deleted file mode 100644
index 2a1cf23..0000000
--- a/kernel/iscsi_tcp.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * iSCSI Initiator TCP Transport
- * Copyright (C) 2004 Dmitry Yusupov
- * Copyright (C) 2004 Alex Aizman
- * Copyright (C) 2005 - 2006 Mike Christie
- * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
- * maintained by open-iscsi@googlegroups.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * See the file COPYING included with this distribution for more details.
- */
-
-#ifndef ISCSI_SW_TCP_H
-#define ISCSI_SW_TCP_H
-
-#include "libiscsi.h"
-#include "libiscsi_tcp.h"
-
-struct socket;
-struct iscsi_tcp_conn;
-
-/* Socket connection send helper */
-struct iscsi_sw_tcp_send {
- struct iscsi_hdr *hdr;
- struct iscsi_segment segment;
- struct iscsi_segment data_segment;
-};
-
-struct iscsi_sw_tcp_conn {
- struct socket *sock;
-
- struct iscsi_sw_tcp_send out;
- /* old values for socket callbacks */
- void (*old_data_ready)(struct sock *, int);
- void (*old_state_change)(struct sock *);
- void (*old_write_space)(struct sock *);
-
- /* data and header digests */
- struct hash_desc tx_hash; /* CRC32C (Tx) */
- struct hash_desc rx_hash; /* CRC32C (Rx) */
-
- /* MIB custom statistics */
- uint32_t sendpage_failures_cnt;
- uint32_t discontiguous_hdr_cnt;
-
- ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
-};
-
-struct iscsi_sw_tcp_hdrbuf {
- struct iscsi_hdr hdrbuf;
- char hdrextbuf[ISCSI_MAX_AHS_SIZE +
- ISCSI_DIGEST_SIZE];
-};
-
-#endif /* ISCSI_SW_TCP_H */
diff --git a/kernel/libiscsi.c b/kernel/libiscsi.c
deleted file mode 100644
index b25d389..0000000
--- a/kernel/libiscsi.c
+++ /dev/null
@@ -1,3462 +0,0 @@
-/*
- * iSCSI lib functions
- *
- * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2004 - 2006 Mike Christie
- * Copyright (C) 2004 - 2005 Dmitry Yusupov
- * Copyright (C) 2004 - 2005 Alex Aizman
- * maintained by open-iscsi@googlegroups.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-#include <linux/types.h>
-#include <linux/kfifo.h>
-#include <linux/delay.h>
-#include <linux/log2.h>
-#include <linux/slab.h>
-#include <asm/unaligned.h>
-#include <net/tcp.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_eh.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_transport.h>
-#include "iscsi_proto.h"
-#include "scsi_transport_iscsi.h"
-#include "libiscsi.h"
-
-static int iscsi_dbg_lib_conn;
-module_param_named(debug_libiscsi_conn, iscsi_dbg_lib_conn, int,
- S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug_libiscsi_conn,
- "Turn on debugging for connections in libiscsi module. "
- "Set to 1 to turn on, and zero to turn off. Default is off.");
-
-static int iscsi_dbg_lib_session;
-module_param_named(debug_libiscsi_session, iscsi_dbg_lib_session, int,
- S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug_libiscsi_session,
- "Turn on debugging for sessions in libiscsi module. "
- "Set to 1 to turn on, and zero to turn off. Default is off.");
-
-static int iscsi_dbg_lib_eh;
-module_param_named(debug_libiscsi_eh, iscsi_dbg_lib_eh, int,
- S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug_libiscsi_eh,
- "Turn on debugging for error handling in libiscsi module. "
- "Set to 1 to turn on, and zero to turn off. Default is off.");
-
-#define ISCSI_DBG_CONN(_conn, dbg_fmt, arg...) \
- do { \
- if (iscsi_dbg_lib_conn) \
- iscsi_conn_printk(KERN_INFO, _conn, \
- "%s " dbg_fmt, \
- __func__, ##arg); \
- } while (0);
-
-#define ISCSI_DBG_SESSION(_session, dbg_fmt, arg...) \
- do { \
- if (iscsi_dbg_lib_session) \
- iscsi_session_printk(KERN_INFO, _session, \
- "%s " dbg_fmt, \
- __func__, ##arg); \
- } while (0);
-
-#define ISCSI_DBG_EH(_session, dbg_fmt, arg...) \
- do { \
- if (iscsi_dbg_lib_eh) \
- iscsi_session_printk(KERN_INFO, _session, \
- "%s " dbg_fmt, \
- __func__, ##arg); \
- } while (0);
-
-/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
-#define SNA32_CHECK 2147483648UL
-
-static int iscsi_sna_lt(u32 n1, u32 n2)
-{
- return n1 != n2 && ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) ||
- (n1 > n2 && (n2 - n1 < SNA32_CHECK)));
-}
-
-/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
-static int iscsi_sna_lte(u32 n1, u32 n2)
-{
- return n1 == n2 || ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) ||
- (n1 > n2 && (n2 - n1 < SNA32_CHECK)));
-}
-
-inline void iscsi_conn_queue_work(struct iscsi_conn *conn)
-{
- struct Scsi_Host *shost = conn->session->host;
- struct iscsi_host *ihost = shost_priv(shost);
-
- if (ihost->workq)
- queue_work(ihost->workq, &conn->xmitwork);
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_queue_work);
-
-static void __iscsi_update_cmdsn(struct iscsi_session *session,
- uint32_t exp_cmdsn, uint32_t max_cmdsn)
-{
- /*
- * standard specifies this check for when to update expected and
- * max sequence numbers
- */
- if (iscsi_sna_lt(max_cmdsn, exp_cmdsn - 1))
- return;
-
- if (exp_cmdsn != session->exp_cmdsn &&
- !iscsi_sna_lt(exp_cmdsn, session->exp_cmdsn))
- session->exp_cmdsn = exp_cmdsn;
-
- if (max_cmdsn != session->max_cmdsn &&
- !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) {
- session->max_cmdsn = max_cmdsn;
- /*
- * if the window closed with IO queued, then kick the
- * xmit thread
- */
- if (!list_empty(&session->leadconn->cmdqueue) ||
- !list_empty(&session->leadconn->mgmtqueue))
- iscsi_conn_queue_work(session->leadconn);
- }
-}
-
-void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
-{
- __iscsi_update_cmdsn(session, be32_to_cpu(hdr->exp_cmdsn),
- be32_to_cpu(hdr->max_cmdsn));
-}
-EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
-
-/**
- * iscsi_prep_data_out_pdu - initialize Data-Out
- * @task: scsi command task
- * @r2t: R2T info
- * @hdr: iscsi data in pdu
- *
- * Notes:
- * Initialize Data-Out within this R2T sequence and finds
- * proper data_offset within this SCSI command.
- *
- * This function is called with connection lock taken.
- **/
-void iscsi_prep_data_out_pdu(struct iscsi_task *task, struct iscsi_r2t_info *r2t,
- struct iscsi_data *hdr)
-{
- struct iscsi_conn *conn = task->conn;
- unsigned int left = r2t->data_length - r2t->sent;
-
- task->hdr_len = sizeof(struct iscsi_data);
-
- memset(hdr, 0, sizeof(struct iscsi_data));
- hdr->ttt = r2t->ttt;
- hdr->datasn = cpu_to_be32(r2t->datasn);
- r2t->datasn++;
- hdr->opcode = ISCSI_OP_SCSI_DATA_OUT;
- memcpy(hdr->lun, task->lun, sizeof(hdr->lun));
- hdr->itt = task->hdr_itt;
- hdr->exp_statsn = r2t->exp_statsn;
- hdr->offset = cpu_to_be32(r2t->data_offset + r2t->sent);
- if (left > conn->max_xmit_dlength) {
- hton24(hdr->dlength, conn->max_xmit_dlength);
- r2t->data_count = conn->max_xmit_dlength;
- hdr->flags = 0;
- } else {
- hton24(hdr->dlength, left);
- r2t->data_count = left;
- hdr->flags = ISCSI_FLAG_CMD_FINAL;
- }
- conn->dataout_pdus_cnt++;
-}
-EXPORT_SYMBOL_GPL(iscsi_prep_data_out_pdu);
-
-static int iscsi_add_hdr(struct iscsi_task *task, unsigned len)
-{
- unsigned exp_len = task->hdr_len + len;
-
- if (exp_len > task->hdr_max) {
- WARN_ON(1);
- return -EINVAL;
- }
-
- WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */
- task->hdr_len = exp_len;
- return 0;
-}
-
-/*
- * make an extended cdb AHS
- */
-static int iscsi_prep_ecdb_ahs(struct iscsi_task *task)
-{
- struct scsi_cmnd *cmd = task->sc;
- unsigned rlen, pad_len;
- unsigned short ahslength;
- struct iscsi_ecdb_ahdr *ecdb_ahdr;
- int rc;
-
- ecdb_ahdr = iscsi_next_hdr(task);
- rlen = cmd->cmd_len - ISCSI_CDB_SIZE;
-
- BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb));
- ahslength = rlen + sizeof(ecdb_ahdr->reserved);
-
- pad_len = iscsi_padding(rlen);
-
- rc = iscsi_add_hdr(task, sizeof(ecdb_ahdr->ahslength) +
- sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len);
- if (rc)
- return rc;
-
- if (pad_len)
- memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
-
- ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
- ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
- ecdb_ahdr->reserved = 0;
- memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
-
- ISCSI_DBG_SESSION(task->conn->session,
- "iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
- "rlen %d pad_len %d ahs_length %d iscsi_headers_size "
- "%u\n", cmd->cmd_len, rlen, pad_len, ahslength,
- task->hdr_len);
- return 0;
-}
-
-static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
-{
- struct scsi_cmnd *sc = task->sc;
- struct iscsi_rlength_ahdr *rlen_ahdr;
- int rc;
-
- rlen_ahdr = iscsi_next_hdr(task);
- rc = iscsi_add_hdr(task, sizeof(*rlen_ahdr));
- if (rc)
- return rc;
-
- rlen_ahdr->ahslength =
- cpu_to_be16(sizeof(rlen_ahdr->read_length) +
- sizeof(rlen_ahdr->reserved));
- rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
- rlen_ahdr->reserved = 0;
- rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
-
- ISCSI_DBG_SESSION(task->conn->session,
- "bidi-in rlen_ahdr->read_length(%d) "
- "rlen_ahdr->ahslength(%d)\n",
- be32_to_cpu(rlen_ahdr->read_length),
- be16_to_cpu(rlen_ahdr->ahslength));
- return 0;
-}
-
-/**
- * iscsi_check_tmf_restrictions - check if a task is affected by TMF
- * @task: iscsi task
- * @opcode: opcode to check for
- *
- * During TMF a task has to be checked if it's affected.
- * All unrelated I/O can be passed through, but I/O to the
- * affected LUN should be restricted.
- * If 'fast_abort' is set we won't be sending any I/O to the
- * affected LUN.
- * Otherwise the target is waiting for all TTTs to be completed,
- * so we have to send all outstanding Data-Out PDUs to the target.
- */
-static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode)
-{
- struct iscsi_conn *conn = task->conn;
- struct iscsi_tm *tmf = &conn->tmhdr;
- unsigned int hdr_lun;
-
- if (conn->tmf_state == TMF_INITIAL)
- return 0;
-
- if ((tmf->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_SCSI_TMFUNC)
- return 0;
-
- switch (ISCSI_TM_FUNC_VALUE(tmf)) {
- case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
- /*
- * Allow PDUs for unrelated LUNs
- */
- hdr_lun = scsilun_to_int((struct scsi_lun *)tmf->lun);
- if (hdr_lun != task->sc->device->lun)
- return 0;
- /* fall through */
- case ISCSI_TM_FUNC_TARGET_WARM_RESET:
- /*
- * Fail all SCSI cmd PDUs
- */
- if (opcode != ISCSI_OP_SCSI_DATA_OUT) {
- iscsi_conn_printk(KERN_INFO, conn,
- "task [op %x/%x itt "
- "0x%x/0x%x] "
- "rejected.\n",
- task->hdr->opcode, opcode,
- task->itt, task->hdr_itt);
- return -EACCES;
- }
- /*
- * And also all data-out PDUs in response to R2T
- * if fast_abort is set.
- */
- if (conn->session->fast_abort) {
- iscsi_conn_printk(KERN_INFO, conn,
- "task [op %x/%x itt "
- "0x%x/0x%x] fast abort.\n",
- task->hdr->opcode, opcode,
- task->itt, task->hdr_itt);
- return -EACCES;
- }
- break;
- case ISCSI_TM_FUNC_ABORT_TASK:
- /*
- * the caller has already checked if the task
- * they want to abort was in the pending queue so if
- * we are here the cmd pdu has gone out already, and
- * we will only hit this for data-outs
- */
- if (opcode == ISCSI_OP_SCSI_DATA_OUT &&
- task->hdr_itt == tmf->rtt) {
- ISCSI_DBG_SESSION(conn->session,
- "Preventing task %x/%x from sending "
- "data-out due to abort task in "
- "progress\n", task->itt,
- task->hdr_itt);
- return -EACCES;
- }
- break;
- }
-
- return 0;
-}
-
-/**
- * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
- * @task: iscsi task
- *
- * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set
- * fields like dlength or final based on how much data it sends
- */
-static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
-{
- struct iscsi_conn *conn = task->conn;
- struct iscsi_session *session = conn->session;
- struct scsi_cmnd *sc = task->sc;
- struct iscsi_cmd *hdr;
- unsigned hdrlength, cmd_len;
- itt_t itt;
- int rc;
-
- rc = iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_CMD);
- if (rc)
- return rc;
-
- if (conn->session->tt->alloc_pdu) {
- rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD);
- if (rc)
- return rc;
- }
- hdr = (struct iscsi_cmd *) task->hdr;
- itt = hdr->itt;
- memset(hdr, 0, sizeof(*hdr));
-
- if (session->tt->parse_pdu_itt)
- hdr->itt = task->hdr_itt = itt;
- else
- hdr->itt = task->hdr_itt = build_itt(task->itt,
- task->conn->session->age);
- task->hdr_len = 0;
- rc = iscsi_add_hdr(task, sizeof(*hdr));
- if (rc)
- return rc;
- hdr->opcode = ISCSI_OP_SCSI_CMD;
- hdr->flags = ISCSI_ATTR_SIMPLE;
- int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
- memcpy(task->lun, hdr->lun, sizeof(task->lun));
- hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
- cmd_len = sc->cmd_len;
- if (cmd_len < ISCSI_CDB_SIZE)
- memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len);
- else if (cmd_len > ISCSI_CDB_SIZE) {
- rc = iscsi_prep_ecdb_ahs(task);
- if (rc)
- return rc;
- cmd_len = ISCSI_CDB_SIZE;
- }
- memcpy(hdr->cdb, sc->cmnd, cmd_len);
-
- task->imm_count = 0;
- if (scsi_bidi_cmnd(sc)) {
- hdr->flags |= ISCSI_FLAG_CMD_READ;
- rc = iscsi_prep_bidi_ahs(task);
- if (rc)
- return rc;
- }
- if (sc->sc_data_direction == DMA_TO_DEVICE) {
- unsigned out_len = scsi_out(sc)->length;
- struct iscsi_r2t_info *r2t = &task->unsol_r2t;
-
- hdr->data_length = cpu_to_be32(out_len);
- hdr->flags |= ISCSI_FLAG_CMD_WRITE;
- /*
- * Write counters:
- *
- * imm_count bytes to be sent right after
- * SCSI PDU Header
- *
- * unsol_count bytes(as Data-Out) to be sent
- * without R2T ack right after
- * immediate data
- *
- * r2t data_length bytes to be sent via R2T ack's
- *
- * pad_count bytes to be sent as zero-padding
- */
- memset(r2t, 0, sizeof(*r2t));
-
- if (session->imm_data_en) {
- if (out_len >= session->first_burst)
- task->imm_count = min(session->first_burst,
- conn->max_xmit_dlength);
- else
- task->imm_count = min(out_len,
- conn->max_xmit_dlength);
- hton24(hdr->dlength, task->imm_count);
- } else
- zero_data(hdr->dlength);
-
- if (!session->initial_r2t_en) {
- r2t->data_length = min(session->first_burst, out_len) -
- task->imm_count;
- r2t->data_offset = task->imm_count;
- r2t->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
- r2t->exp_statsn = cpu_to_be32(conn->exp_statsn);
- }
-
- if (!task->unsol_r2t.data_length)
- /* No unsolicit Data-Out's */
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- } else {
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- zero_data(hdr->dlength);
- hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
-
- if (sc->sc_data_direction == DMA_FROM_DEVICE)
- hdr->flags |= ISCSI_FLAG_CMD_READ;
- }
-
- /* calculate size of additional header segments (AHSs) */
- hdrlength = task->hdr_len - sizeof(*hdr);
-
- WARN_ON(hdrlength & (ISCSI_PAD_LEN-1));
- hdrlength /= ISCSI_PAD_LEN;
-
- WARN_ON(hdrlength >= 256);
- hdr->hlength = hdrlength & 0xFF;
- hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn);
-
- if (session->tt->init_task && session->tt->init_task(task))
- return -EIO;
-
- task->state = ISCSI_TASK_RUNNING;
- session->cmdsn++;
-
- conn->scsicmd_pdus_cnt++;
- ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x "
- "itt 0x%x len %d bidi_len %d cmdsn %d win %d]\n",
- scsi_bidi_cmnd(sc) ? "bidirectional" :
- sc->sc_data_direction == DMA_TO_DEVICE ?
- "write" : "read", conn->id, sc, sc->cmnd[0],
- task->itt, scsi_bufflen(sc),
- scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
- session->cmdsn,
- session->max_cmdsn - session->exp_cmdsn + 1);
- return 0;
-}
-
-/**
- * iscsi_free_task - free a task
- * @task: iscsi cmd task
- *
- * Must be called with session lock.
- * This function returns the scsi command to scsi-ml or cleans
- * up mgmt tasks then returns the task to the pool.
- */
-static void iscsi_free_task(struct iscsi_task *task)
-{
- struct iscsi_conn *conn = task->conn;
- struct iscsi_session *session = conn->session;
- struct scsi_cmnd *sc = task->sc;
-
- ISCSI_DBG_SESSION(session, "freeing task itt 0x%x state %d sc %p\n",
- task->itt, task->state, task->sc);
-
- session->tt->cleanup_task(task);
- task->state = ISCSI_TASK_FREE;
- task->sc = NULL;
- /*
- * login task is preallocated so do not free
- */
- if (conn->login_task == task)
- return;
-
- kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
-
- if (sc) {
- task->sc = NULL;
- /* SCSI eh reuses commands to verify us */
- sc->SCp.ptr = NULL;
- /*
- * queue command may call this to free the task, but
- * not have setup the sc callback
- */
- if (sc->scsi_done)
- sc->scsi_done(sc);
- }
-}
-
-void __iscsi_get_task(struct iscsi_task *task)
-{
- atomic_inc(&task->refcount);
-}
-EXPORT_SYMBOL_GPL(__iscsi_get_task);
-
-static void __iscsi_put_task(struct iscsi_task *task)
-{
- if (atomic_dec_and_test(&task->refcount))
- iscsi_free_task(task);
-}
-
-void iscsi_put_task(struct iscsi_task *task)
-{
- struct iscsi_session *session = task->conn->session;
-
- spin_lock_bh(&session->lock);
- __iscsi_put_task(task);
- spin_unlock_bh(&session->lock);
-}
-EXPORT_SYMBOL_GPL(iscsi_put_task);
-
-/**
- * iscsi_complete_task - finish a task
- * @task: iscsi cmd task
- * @state: state to complete task with
- *
- * Must be called with session lock.
- */
-static void iscsi_complete_task(struct iscsi_task *task, int state)
-{
- struct iscsi_conn *conn = task->conn;
-
- ISCSI_DBG_SESSION(conn->session,
- "complete task itt 0x%x state %d sc %p\n",
- task->itt, task->state, task->sc);
- if (task->state == ISCSI_TASK_COMPLETED ||
- task->state == ISCSI_TASK_ABRT_TMF ||
- task->state == ISCSI_TASK_ABRT_SESS_RECOV)
- return;
- WARN_ON_ONCE(task->state == ISCSI_TASK_FREE);
- task->state = state;
-
- if (!list_empty(&task->running))
- list_del_init(&task->running);
-
- if (conn->task == task)
- conn->task = NULL;
-
- if (conn->ping_task == task)
- conn->ping_task = NULL;
-
- /* release get from queueing */
- __iscsi_put_task(task);
-}
-
-/**
- * iscsi_complete_scsi_task - finish scsi task normally
- * @task: iscsi task for scsi cmd
- * @exp_cmdsn: expected cmd sn in cpu format
- * @max_cmdsn: max cmd sn in cpu format
- *
- * This is used when drivers do not need or cannot perform
- * lower level pdu processing.
- *
- * Called with session lock
- */
-void iscsi_complete_scsi_task(struct iscsi_task *task,
- uint32_t exp_cmdsn, uint32_t max_cmdsn)
-{
- struct iscsi_conn *conn = task->conn;
-
- ISCSI_DBG_SESSION(conn->session, "[itt 0x%x]\n", task->itt);
-
- conn->last_recv = jiffies;
- __iscsi_update_cmdsn(conn->session, exp_cmdsn, max_cmdsn);
- iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
-}
-EXPORT_SYMBOL_GPL(iscsi_complete_scsi_task);
-
-
-/*
- * session lock must be held and if not called for a task that is
- * still pending or from the xmit thread, then xmit thread must
- * be suspended.
- */
-static void fail_scsi_task(struct iscsi_task *task, int err)
-{
- struct iscsi_conn *conn = task->conn;
- struct scsi_cmnd *sc;
- int state;
-
- /*
- * if a command completes and we get a successful tmf response
- * we will hit this because the scsi eh abort code does not take
- * a ref to the task.
- */
- sc = task->sc;
- if (!sc)
- return;
-
- if (task->state == ISCSI_TASK_PENDING) {
- /*
- * cmd never made it to the xmit thread, so we should not count
- * the cmd in the sequencing
- */
- conn->session->queued_cmdsn--;
- /* it was never sent so just complete like normal */
- state = ISCSI_TASK_COMPLETED;
- } else if (err == DID_TRANSPORT_DISRUPTED)
- state = ISCSI_TASK_ABRT_SESS_RECOV;
- else
- state = ISCSI_TASK_ABRT_TMF;
-
- sc->result = err << 16;
- if (!scsi_bidi_cmnd(sc))
- scsi_set_resid(sc, scsi_bufflen(sc));
- else {
- scsi_out(sc)->resid = scsi_out(sc)->length;
- scsi_in(sc)->resid = scsi_in(sc)->length;
- }
-
- iscsi_complete_task(task, state);
-}
-
-static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
- struct iscsi_task *task)
-{
- struct iscsi_session *session = conn->session;
- struct iscsi_hdr *hdr = task->hdr;
- struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
- uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK;
-
- if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
- return -ENOTCONN;
-
- if (opcode != ISCSI_OP_LOGIN && opcode != ISCSI_OP_TEXT)
- nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
- /*
- * pre-format CmdSN for outgoing PDU.
- */
- nop->cmdsn = cpu_to_be32(session->cmdsn);
- if (hdr->itt != RESERVED_ITT) {
- /*
- * TODO: We always use immediate for normal session pdus.
- * If we start to send tmfs or nops as non-immediate then
- * we should start checking the cmdsn numbers for mgmt tasks.
- *
- * During discovery sessions iscsid sends TEXT as non immediate,
- * but we always only send one PDU at a time.
- */
- if (conn->c_stage == ISCSI_CONN_STARTED &&
- !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
- session->queued_cmdsn++;
- session->cmdsn++;
- }
- }
-
- if (session->tt->init_task && session->tt->init_task(task))
- return -EIO;
-
- if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
- session->state = ISCSI_STATE_LOGGING_OUT;
-
- task->state = ISCSI_TASK_RUNNING;
- ISCSI_DBG_SESSION(session, "mgmtpdu [op 0x%x hdr->itt 0x%x "
- "datalen %d]\n", hdr->opcode & ISCSI_OPCODE_MASK,
- hdr->itt, task->data_count);
- return 0;
-}
-
-static struct iscsi_task *
-__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- char *data, uint32_t data_size)
-{
- struct iscsi_session *session = conn->session;
- struct iscsi_host *ihost = shost_priv(session->host);
- uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK;
- struct iscsi_task *task;
- itt_t itt;
-
- if (session->state == ISCSI_STATE_TERMINATE)
- return NULL;
-
- if (opcode == ISCSI_OP_LOGIN || opcode == ISCSI_OP_TEXT) {
- /*
- * Login and Text are sent serially, in
- * request-followed-by-response sequence.
- * Same task can be used. Same ITT must be used.
- * Note that login_task is preallocated at conn_create().
- */
- if (conn->login_task->state != ISCSI_TASK_FREE) {
- iscsi_conn_printk(KERN_ERR, conn, "Login/Text in "
- "progress. Cannot start new task.\n");
- return NULL;
- }
-
- task = conn->login_task;
- } else {
- if (session->state != ISCSI_STATE_LOGGED_IN)
- return NULL;
-
- BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
- BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
-
- if (!kfifo_out(&session->cmdpool.queue,
- (void*)&task, sizeof(void*)))
- return NULL;
- }
- /*
- * released in complete pdu for task we expect a response for, and
- * released by the lld when it has transmitted the task for
- * pdus we do not expect a response for.
- */
- atomic_set(&task->refcount, 1);
- task->conn = conn;
- task->sc = NULL;
- INIT_LIST_HEAD(&task->running);
- task->state = ISCSI_TASK_PENDING;
-
- if (data_size) {
- memcpy(task->data, data, data_size);
- task->data_count = data_size;
- } else
- task->data_count = 0;
-
- if (conn->session->tt->alloc_pdu) {
- if (conn->session->tt->alloc_pdu(task, hdr->opcode)) {
- iscsi_conn_printk(KERN_ERR, conn, "Could not allocate "
- "pdu for mgmt task.\n");
- goto free_task;
- }
- }
-
- itt = task->hdr->itt;
- task->hdr_len = sizeof(struct iscsi_hdr);
- memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr));
-
- if (hdr->itt != RESERVED_ITT) {
- if (session->tt->parse_pdu_itt)
- task->hdr->itt = itt;
- else
- task->hdr->itt = build_itt(task->itt,
- task->conn->session->age);
- }
-
- if (!ihost->workq) {
- if (iscsi_prep_mgmt_task(conn, task))
- goto free_task;
-
- if (session->tt->xmit_task(task))
- goto free_task;
- } else {
- list_add_tail(&task->running, &conn->mgmtqueue);
- iscsi_conn_queue_work(conn);
- }
-
- return task;
-
-free_task:
- __iscsi_put_task(task);
- return NULL;
-}
-
-int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
- char *data, uint32_t data_size)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_session *session = conn->session;
- int err = 0;
-
- spin_lock_bh(&session->lock);
- if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
- err = -EPERM;
- spin_unlock_bh(&session->lock);
- return err;
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
-
-/**
- * iscsi_cmd_rsp - SCSI Command Response processing
- * @conn: iscsi connection
- * @hdr: iscsi header
- * @task: scsi command task
- * @data: cmd data buffer
- * @datalen: len of buffer
- *
- * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and
- * then completes the command and task.
- **/
-static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- struct iscsi_task *task, char *data,
- int datalen)
-{
- struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr;
- struct iscsi_session *session = conn->session;
- struct scsi_cmnd *sc = task->sc;
-
- iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
- conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
-
- sc->result = (DID_OK << 16) | rhdr->cmd_status;
-
- if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) {
- sc->result = DID_ERROR << 16;
- goto out;
- }
-
- if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) {
- uint16_t senselen;
-
- if (datalen < 2) {
-invalid_datalen:
- iscsi_conn_printk(KERN_ERR, conn,
- "Got CHECK_CONDITION but invalid data "
- "buffer size of %d\n", datalen);
- sc->result = DID_BAD_TARGET << 16;
- goto out;
- }
-
- senselen = get_unaligned_be16(data);
- if (datalen < senselen)
- goto invalid_datalen;
-
- memcpy(sc->sense_buffer, data + 2,
- min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
- ISCSI_DBG_SESSION(session, "copied %d bytes of sense\n",
- min_t(uint16_t, senselen,
- SCSI_SENSE_BUFFERSIZE));
- }
-
- if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
- ISCSI_FLAG_CMD_BIDI_OVERFLOW)) {
- int res_count = be32_to_cpu(rhdr->bi_residual_count);
-
- if (scsi_bidi_cmnd(sc) && res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
- res_count <= scsi_in(sc)->length))
- scsi_in(sc)->resid = res_count;
- else
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- }
-
- if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW |
- ISCSI_FLAG_CMD_OVERFLOW)) {
- int res_count = be32_to_cpu(rhdr->residual_count);
-
- if (res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
- res_count <= scsi_bufflen(sc)))
- /* write side for bidi or uni-io set_resid */
- scsi_set_resid(sc, res_count);
- else
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- }
-out:
- ISCSI_DBG_SESSION(session, "cmd rsp done [sc %p res %d itt 0x%x]\n",
- sc, sc->result, task->itt);
- conn->scsirsp_pdus_cnt++;
- iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
-}
-
-/**
- * iscsi_data_in_rsp - SCSI Data-In Response processing
- * @conn: iscsi connection
- * @hdr: iscsi pdu
- * @task: scsi command task
- **/
-static void
-iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- struct iscsi_task *task)
-{
- struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)hdr;
- struct scsi_cmnd *sc = task->sc;
-
- if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
- return;
-
- iscsi_update_cmdsn(conn->session, (struct iscsi_nopin *)hdr);
- sc->result = (DID_OK << 16) | rhdr->cmd_status;
- conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
- if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
- ISCSI_FLAG_DATA_OVERFLOW)) {
- int res_count = be32_to_cpu(rhdr->residual_count);
-
- if (res_count > 0 &&
- (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
- res_count <= scsi_in(sc)->length))
- scsi_in(sc)->resid = res_count;
- else
- sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
- }
-
- ISCSI_DBG_SESSION(conn->session, "data in with status done "
- "[sc %p res %d itt 0x%x]\n",
- sc, sc->result, task->itt);
- conn->scsirsp_pdus_cnt++;
- iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
-}
-
-static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
-{
- struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr;
-
- conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
- conn->tmfrsp_pdus_cnt++;
-
- if (conn->tmf_state != TMF_QUEUED)
- return;
-
- if (tmf->response == ISCSI_TMF_RSP_COMPLETE)
- conn->tmf_state = TMF_SUCCESS;
- else if (tmf->response == ISCSI_TMF_RSP_NO_TASK)
- conn->tmf_state = TMF_NOT_FOUND;
- else
- conn->tmf_state = TMF_FAILED;
- wake_up(&conn->ehwait);
-}
-
-static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
-{
- struct iscsi_nopout hdr;
- struct iscsi_task *task;
-
- if (!rhdr && conn->ping_task)
- return;
-
- memset(&hdr, 0, sizeof(struct iscsi_nopout));
- hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
- hdr.flags = ISCSI_FLAG_CMD_FINAL;
-
- if (rhdr) {
- memcpy(hdr.lun, rhdr->lun, 8);
- hdr.ttt = rhdr->ttt;
- hdr.itt = RESERVED_ITT;
- } else
- hdr.ttt = RESERVED_ITT;
-
- task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
- if (!task)
- iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
- else if (!rhdr) {
- /* only track our nops */
- conn->ping_task = task;
- conn->last_ping = jiffies;
- }
-}
-
-static int iscsi_nop_out_rsp(struct iscsi_task *task,
- struct iscsi_nopin *nop, char *data, int datalen)
-{
- struct iscsi_conn *conn = task->conn;
- int rc = 0;
-
- if (conn->ping_task != task) {
- /*
- * If this is not in response to one of our
- * nops then it must be from userspace.
- */
- if (iscsi_recv_pdu(conn->cls_conn, (struct iscsi_hdr *)nop,
- data, datalen))
- rc = ISCSI_ERR_CONN_FAILED;
- } else
- mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
- iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
- return rc;
-}
-
-static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- char *data, int datalen)
-{
- struct iscsi_reject *reject = (struct iscsi_reject *)hdr;
- struct iscsi_hdr rejected_pdu;
- int opcode, rc = 0;
-
- conn->exp_statsn = be32_to_cpu(reject->statsn) + 1;
-
- if (ntoh24(reject->dlength) > datalen ||
- ntoh24(reject->dlength) < sizeof(struct iscsi_hdr)) {
- iscsi_conn_printk(KERN_ERR, conn, "Cannot handle rejected "
- "pdu. Invalid data length (pdu dlength "
- "%u, datalen %d\n", ntoh24(reject->dlength),
- datalen);
- return ISCSI_ERR_PROTO;
- }
- memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
- opcode = rejected_pdu.opcode & ISCSI_OPCODE_MASK;
-
- switch (reject->reason) {
- case ISCSI_REASON_DATA_DIGEST_ERROR:
- iscsi_conn_printk(KERN_ERR, conn,
- "pdu (op 0x%x itt 0x%x) rejected "
- "due to DataDigest error.\n",
- rejected_pdu.itt, opcode);
- break;
- case ISCSI_REASON_IMM_CMD_REJECT:
- iscsi_conn_printk(KERN_ERR, conn,
- "pdu (op 0x%x itt 0x%x) rejected. Too many "
- "immediate commands.\n",
- rejected_pdu.itt, opcode);
- /*
- * We only send one TMF at a time so if the target could not
- * handle it, then it should get fixed (RFC mandates that
- * a target can handle one immediate TMF per conn).
- *
- * For nops-outs, we could have sent more than one if
- * the target is sending us lots of nop-ins
- */
- if (opcode != ISCSI_OP_NOOP_OUT)
- return 0;
-
- if (rejected_pdu.itt == cpu_to_be32(ISCSI_RESERVED_TAG))
- /*
- * nop-out in response to target's nop-out rejected.
- * Just resend.
- */
- iscsi_send_nopout(conn,
- (struct iscsi_nopin*)&rejected_pdu);
- else {
- struct iscsi_task *task;
- /*
- * Our nop as ping got dropped. We know the target
- * and transport are ok so just clean up
- */
- task = iscsi_itt_to_task(conn, rejected_pdu.itt);
- if (!task) {
- iscsi_conn_printk(KERN_ERR, conn,
- "Invalid pdu reject. Could "
- "not lookup rejected task.\n");
- rc = ISCSI_ERR_BAD_ITT;
- } else
- rc = iscsi_nop_out_rsp(task,
- (struct iscsi_nopin*)&rejected_pdu,
- NULL, 0);
- }
- break;
- default:
- iscsi_conn_printk(KERN_ERR, conn,
- "pdu (op 0x%x itt 0x%x) rejected. Reason "
- "code 0x%x\n", rejected_pdu.itt,
- rejected_pdu.opcode, reject->reason);
- break;
- }
- return rc;
-}
-
-/**
- * iscsi_itt_to_task - look up task by itt
- * @conn: iscsi connection
- * @itt: itt
- *
- * This should be used for mgmt tasks like login and nops, or if
- * the LDD's itt space does not include the session age.
- *
- * The session lock must be held.
- */
-struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
-{
- struct iscsi_session *session = conn->session;
- int i;
-
- if (itt == RESERVED_ITT)
- return NULL;
-
- if (session->tt->parse_pdu_itt)
- session->tt->parse_pdu_itt(conn, itt, &i, NULL);
- else
- i = get_itt(itt);
- if (i >= session->cmds_max)
- return NULL;
-
- return session->cmds[i];
-}
-EXPORT_SYMBOL_GPL(iscsi_itt_to_task);
-
-/**
- * __iscsi_complete_pdu - complete pdu
- * @conn: iscsi conn
- * @hdr: iscsi header
- * @data: data buffer
- * @datalen: len of data buffer
- *
- * Completes pdu processing by freeing any resources allocated at
- * queuecommand or send generic. session lock must be held and verify
- * itt must have been called.
- */
-int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- char *data, int datalen)
-{
- struct iscsi_session *session = conn->session;
- int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0;
- struct iscsi_task *task;
- uint32_t itt;
-
- conn->last_recv = jiffies;
- rc = iscsi_verify_itt(conn, hdr->itt);
- if (rc)
- return rc;
-
- if (hdr->itt != RESERVED_ITT)
- itt = get_itt(hdr->itt);
- else
- itt = ~0U;
-
- ISCSI_DBG_SESSION(session, "[op 0x%x cid %d itt 0x%x len %d]\n",
- opcode, conn->id, itt, datalen);
-
- if (itt == ~0U) {
- iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
-
- switch(opcode) {
- case ISCSI_OP_NOOP_IN:
- if (datalen) {
- rc = ISCSI_ERR_PROTO;
- break;
- }
-
- if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
- break;
-
- iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
- break;
- case ISCSI_OP_REJECT:
- rc = iscsi_handle_reject(conn, hdr, data, datalen);
- break;
- case ISCSI_OP_ASYNC_EVENT:
- conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
- if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
- rc = ISCSI_ERR_CONN_FAILED;
- break;
- default:
- rc = ISCSI_ERR_BAD_OPCODE;
- break;
- }
- goto out;
- }
-
- switch(opcode) {
- case ISCSI_OP_SCSI_CMD_RSP:
- case ISCSI_OP_SCSI_DATA_IN:
- task = iscsi_itt_to_ctask(conn, hdr->itt);
- if (!task)
- return ISCSI_ERR_BAD_ITT;
- task->last_xfer = jiffies;
- break;
- case ISCSI_OP_R2T:
- /*
- * LLD handles R2Ts if they need to.
- */
- return 0;
- case ISCSI_OP_LOGOUT_RSP:
- case ISCSI_OP_LOGIN_RSP:
- case ISCSI_OP_TEXT_RSP:
- case ISCSI_OP_SCSI_TMFUNC_RSP:
- case ISCSI_OP_NOOP_IN:
- task = iscsi_itt_to_task(conn, hdr->itt);
- if (!task)
- return ISCSI_ERR_BAD_ITT;
- break;
- default:
- return ISCSI_ERR_BAD_OPCODE;
- }
-
- switch(opcode) {
- case ISCSI_OP_SCSI_CMD_RSP:
- iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen);
- break;
- case ISCSI_OP_SCSI_DATA_IN:
- iscsi_data_in_rsp(conn, hdr, task);
- break;
- case ISCSI_OP_LOGOUT_RSP:
- iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
- if (datalen) {
- rc = ISCSI_ERR_PROTO;
- break;
- }
- conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
- goto recv_pdu;
- case ISCSI_OP_LOGIN_RSP:
- case ISCSI_OP_TEXT_RSP:
- iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
- /*
- * login related PDU's exp_statsn is handled in
- * userspace
- */
- goto recv_pdu;
- case ISCSI_OP_SCSI_TMFUNC_RSP:
- iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
- if (datalen) {
- rc = ISCSI_ERR_PROTO;
- break;
- }
-
- iscsi_tmf_rsp(conn, hdr);
- iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
- break;
- case ISCSI_OP_NOOP_IN:
- iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
- if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
- rc = ISCSI_ERR_PROTO;
- break;
- }
- conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
-
- rc = iscsi_nop_out_rsp(task, (struct iscsi_nopin*)hdr,
- data, datalen);
- break;
- default:
- rc = ISCSI_ERR_BAD_OPCODE;
- break;
- }
-
-out:
- return rc;
-recv_pdu:
- if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
- rc = ISCSI_ERR_CONN_FAILED;
- iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
- return rc;
-}
-EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
-
-int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- char *data, int datalen)
-{
- int rc;
-
- spin_lock(&conn->session->lock);
- rc = __iscsi_complete_pdu(conn, hdr, data, datalen);
- spin_unlock(&conn->session->lock);
- return rc;
-}
-EXPORT_SYMBOL_GPL(iscsi_complete_pdu);
-
-int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
-{
- struct iscsi_session *session = conn->session;
- int age = 0, i = 0;
-
- if (itt == RESERVED_ITT)
- return 0;
-
- if (session->tt->parse_pdu_itt)
- session->tt->parse_pdu_itt(conn, itt, &i, &age);
- else {
- i = get_itt(itt);
- age = ((__force u32)itt >> ISCSI_AGE_SHIFT) & ISCSI_AGE_MASK;
- }
-
- if (age != session->age) {
- iscsi_conn_printk(KERN_ERR, conn,
- "received itt %x expected session age (%x)\n",
- (__force u32)itt, session->age);
- return ISCSI_ERR_BAD_ITT;
- }
-
- if (i >= session->cmds_max) {
- iscsi_conn_printk(KERN_ERR, conn,
- "received invalid itt index %u (max cmds "
- "%u.\n", i, session->cmds_max);
- return ISCSI_ERR_BAD_ITT;
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_verify_itt);
-
-/**
- * iscsi_itt_to_ctask - look up ctask by itt
- * @conn: iscsi connection
- * @itt: itt
- *
- * This should be used for cmd tasks.
- *
- * The session lock must be held.
- */
-struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
-{
- struct iscsi_task *task;
-
- if (iscsi_verify_itt(conn, itt))
- return NULL;
-
- task = iscsi_itt_to_task(conn, itt);
- if (!task || !task->sc)
- return NULL;
-
- if (task->sc->SCp.phase != conn->session->age) {
- iscsi_session_printk(KERN_ERR, conn->session,
- "task's session age %d, expected %d\n",
- task->sc->SCp.phase, conn->session->age);
- return NULL;
- }
-
- return task;
-}
-EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask);
-
-void iscsi_session_failure(struct iscsi_session *session,
- enum iscsi_err err)
-{
- struct iscsi_conn *conn;
- struct device *dev;
- unsigned long flags;
-
- spin_lock_irqsave(&session->lock, flags);
- conn = session->leadconn;
- if (session->state == ISCSI_STATE_TERMINATE || !conn) {
- spin_unlock_irqrestore(&session->lock, flags);
- return;
- }
-
- dev = get_device(&conn->cls_conn->dev);
- spin_unlock_irqrestore(&session->lock, flags);
- if (!dev)
- return;
- /*
- * if the host is being removed bypass the connection
- * recovery initialization because we are going to kill
- * the session.
- */
- if (err == ISCSI_ERR_INVALID_HOST)
- iscsi_conn_error_event(conn->cls_conn, err);
- else
- iscsi_conn_failure(conn, err);
- put_device(dev);
-}
-EXPORT_SYMBOL_GPL(iscsi_session_failure);
-
-void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
-{
- struct iscsi_session *session = conn->session;
- unsigned long flags;
-
- spin_lock_irqsave(&session->lock, flags);
- if (session->state == ISCSI_STATE_FAILED) {
- spin_unlock_irqrestore(&session->lock, flags);
- return;
- }
-
- if (conn->stop_stage == 0)
- session->state = ISCSI_STATE_FAILED;
- spin_unlock_irqrestore(&session->lock, flags);
-
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
- iscsi_conn_error_event(conn->cls_conn, err);
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_failure);
-
-static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
-{
- struct iscsi_session *session = conn->session;
-
- /*
- * Check for iSCSI window and take care of CmdSN wrap-around
- */
- if (!iscsi_sna_lte(session->queued_cmdsn, session->max_cmdsn)) {
- ISCSI_DBG_SESSION(session, "iSCSI CmdSN closed. ExpCmdSn "
- "%u MaxCmdSN %u CmdSN %u/%u\n",
- session->exp_cmdsn, session->max_cmdsn,
- session->cmdsn, session->queued_cmdsn);
- return -ENOSPC;
- }
- return 0;
-}
-
-static int iscsi_xmit_task(struct iscsi_conn *conn)
-{
- struct iscsi_task *task = conn->task;
- int rc;
-
- if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx))
- return -ENODATA;
-
- __iscsi_get_task(task);
- spin_unlock_bh(&conn->session->lock);
- rc = conn->session->tt->xmit_task(task);
- spin_lock_bh(&conn->session->lock);
- if (!rc) {
- /* done with this task */
- task->last_xfer = jiffies;
- conn->task = NULL;
- }
- __iscsi_put_task(task);
- return rc;
-}
-
-/**
- * iscsi_requeue_task - requeue task to run from session workqueue
- * @task: task to requeue
- *
- * LLDs that need to run a task from the session workqueue should call
- * this. The session lock must be held. This should only be called
- * by software drivers.
- */
-void iscsi_requeue_task(struct iscsi_task *task)
-{
- struct iscsi_conn *conn = task->conn;
-
- /*
- * this may be on the requeue list already if the xmit_task callout
- * is handling the r2ts while we are adding new ones
- */
- if (list_empty(&task->running))
- list_add_tail(&task->running, &conn->requeue);
- iscsi_conn_queue_work(conn);
-}
-EXPORT_SYMBOL_GPL(iscsi_requeue_task);
-
-/**
- * iscsi_data_xmit - xmit any command into the scheduled connection
- * @conn: iscsi connection
- *
- * Notes:
- * The function can return -EAGAIN in which case the caller must
- * re-schedule it again later or recover. '0' return code means
- * successful xmit.
- **/
-static int iscsi_data_xmit(struct iscsi_conn *conn)
-{
- struct iscsi_task *task;
- int rc = 0;
-
- spin_lock_bh(&conn->session->lock);
- if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
- ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n");
- spin_unlock_bh(&conn->session->lock);
- return -ENODATA;
- }
-
- if (conn->task) {
- rc = iscsi_xmit_task(conn);
- if (rc)
- goto done;
- }
-
- /*
- * process mgmt pdus like nops before commands since we should
- * only have one nop-out as a ping from us and targets should not
- * overflow us with nop-ins
- */
-check_mgmt:
- while (!list_empty(&conn->mgmtqueue)) {
- conn->task = list_entry(conn->mgmtqueue.next,
- struct iscsi_task, running);
- list_del_init(&conn->task->running);
- if (iscsi_prep_mgmt_task(conn, conn->task)) {
- __iscsi_put_task(conn->task);
- conn->task = NULL;
- continue;
- }
- rc = iscsi_xmit_task(conn);
- if (rc)
- goto done;
- }
-
- /* process pending command queue */
- while (!list_empty(&conn->cmdqueue)) {
- conn->task = list_entry(conn->cmdqueue.next, struct iscsi_task,
- running);
- list_del_init(&conn->task->running);
- if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
- fail_scsi_task(conn->task, DID_IMM_RETRY);
- continue;
- }
- rc = iscsi_prep_scsi_cmd_pdu(conn->task);
- if (rc) {
- if (rc == -ENOMEM || rc == -EACCES) {
- list_add_tail(&conn->task->running,
- &conn->cmdqueue);
- conn->task = NULL;
- goto done;
- } else
- fail_scsi_task(conn->task, DID_ABORT);
- continue;
- }
- rc = iscsi_xmit_task(conn);
- if (rc)
- goto done;
- /*
- * we could continuously get new task requests so
- * we need to check the mgmt queue for nops that need to
- * be sent to aviod starvation
- */
- if (!list_empty(&conn->mgmtqueue))
- goto check_mgmt;
- }
-
- while (!list_empty(&conn->requeue)) {
- /*
- * we always do fastlogout - conn stop code will clean up.
- */
- if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
- break;
-
- task = list_entry(conn->requeue.next, struct iscsi_task,
- running);
- if (iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_DATA_OUT))
- break;
-
- conn->task = task;
- list_del_init(&conn->task->running);
- conn->task->state = ISCSI_TASK_RUNNING;
- rc = iscsi_xmit_task(conn);
- if (rc)
- goto done;
- if (!list_empty(&conn->mgmtqueue))
- goto check_mgmt;
- }
- spin_unlock_bh(&conn->session->lock);
- return -ENODATA;
-
-done:
- spin_unlock_bh(&conn->session->lock);
- return rc;
-}
-
-static void iscsi_xmitworker(struct work_struct *work)
-{
- struct iscsi_conn *conn =
- container_of(work, struct iscsi_conn, xmitwork);
- int rc;
- /*
- * serialize Xmit worker on a per-connection basis.
- */
- do {
- rc = iscsi_data_xmit(conn);
- } while (rc >= 0 || rc == -EAGAIN);
-}
-
-static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
- struct scsi_cmnd *sc)
-{
- struct iscsi_task *task;
-
- if (!kfifo_out(&conn->session->cmdpool.queue,
- (void *) &task, sizeof(void *)))
- return NULL;
-
- sc->SCp.phase = conn->session->age;
- sc->SCp.ptr = (char *) task;
-
- atomic_set(&task->refcount, 1);
- task->state = ISCSI_TASK_PENDING;
- task->conn = conn;
- task->sc = sc;
- task->have_checked_conn = 0;
- task->last_timeout = jiffies;
- task->last_xfer = jiffies;
- INIT_LIST_HEAD(&task->running);
- return task;
-}
-
-enum {
- FAILURE_BAD_HOST = 1,
- FAILURE_SESSION_FAILED,
- FAILURE_SESSION_FREED,
- FAILURE_WINDOW_CLOSED,
- FAILURE_OOM,
- FAILURE_SESSION_TERMINATE,
- FAILURE_SESSION_IN_RECOVERY,
- FAILURE_SESSION_RECOVERY_TIMEOUT,
- FAILURE_SESSION_LOGGING_OUT,
- FAILURE_SESSION_NOT_READY,
-};
-
-int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
-{
- struct iscsi_cls_session *cls_session;
- struct Scsi_Host *host;
- struct iscsi_host *ihost;
- int reason = 0;
- struct iscsi_session *session;
- struct iscsi_conn *conn;
- struct iscsi_task *task = NULL;
-
- sc->scsi_done = done;
- sc->result = 0;
- sc->SCp.ptr = NULL;
-
- host = sc->device->host;
- ihost = shost_priv(host);
- spin_unlock(host->host_lock);
-
- cls_session = starget_to_session(scsi_target(sc->device));
- session = cls_session->dd_data;
- spin_lock(&session->lock);
-
- reason = iscsi_session_chkready(cls_session);
- if (reason) {
- sc->result = reason;
- goto fault;
- }
-
- if (session->state != ISCSI_STATE_LOGGED_IN) {
- /*
- * to handle the race between when we set the recovery state
- * and block the session we requeue here (commands could
- * be entering our queuecommand while a block is starting
- * up because the block code is not locked)
- */
- switch (session->state) {
- case ISCSI_STATE_FAILED:
- case ISCSI_STATE_IN_RECOVERY:
- reason = FAILURE_SESSION_IN_RECOVERY;
- sc->result = DID_IMM_RETRY << 16;
- break;
- case ISCSI_STATE_LOGGING_OUT:
- reason = FAILURE_SESSION_LOGGING_OUT;
- sc->result = DID_IMM_RETRY << 16;
- break;
- case ISCSI_STATE_RECOVERY_FAILED:
- reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
- sc->result = DID_TRANSPORT_FAILFAST << 16;
- break;
- case ISCSI_STATE_TERMINATE:
- reason = FAILURE_SESSION_TERMINATE;
- sc->result = DID_NO_CONNECT << 16;
- break;
- default:
- reason = FAILURE_SESSION_FREED;
- sc->result = DID_NO_CONNECT << 16;
- }
- goto fault;
- }
-
- conn = session->leadconn;
- if (!conn) {
- reason = FAILURE_SESSION_FREED;
- sc->result = DID_NO_CONNECT << 16;
- goto fault;
- }
-
- if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
- reason = FAILURE_SESSION_IN_RECOVERY;
- sc->result = DID_REQUEUE;
- goto fault;
- }
-
- if (iscsi_check_cmdsn_window_closed(conn)) {
- reason = FAILURE_WINDOW_CLOSED;
- goto reject;
- }
-
- task = iscsi_alloc_task(conn, sc);
- if (!task) {
- reason = FAILURE_OOM;
- goto reject;
- }
-
- if (!ihost->workq) {
- reason = iscsi_prep_scsi_cmd_pdu(task);
- if (reason) {
- if (reason == -ENOMEM || reason == -EACCES) {
- reason = FAILURE_OOM;
- goto prepd_reject;
- } else {
- sc->result = DID_ABORT << 16;
- goto prepd_fault;
- }
- }
- if (session->tt->xmit_task(task)) {
- session->cmdsn--;
- reason = FAILURE_SESSION_NOT_READY;
- goto prepd_reject;
- }
- } else {
- list_add_tail(&task->running, &conn->cmdqueue);
- iscsi_conn_queue_work(conn);
- }
-
- session->queued_cmdsn++;
- spin_unlock(&session->lock);
- spin_lock(host->host_lock);
- return 0;
-
-prepd_reject:
- sc->scsi_done = NULL;
- iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
-reject:
- spin_unlock(&session->lock);
- ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
- sc->cmnd[0], reason);
- spin_lock(host->host_lock);
- return SCSI_MLQUEUE_TARGET_BUSY;
-
-prepd_fault:
- sc->scsi_done = NULL;
- iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
-fault:
- spin_unlock(&session->lock);
- ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
- sc->cmnd[0], reason);
- if (!scsi_bidi_cmnd(sc))
- scsi_set_resid(sc, scsi_bufflen(sc));
- else {
- scsi_out(sc)->resid = scsi_out(sc)->length;
- scsi_in(sc)->resid = scsi_in(sc)->length;
- }
- done(sc);
- spin_lock(host->host_lock);
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_queuecommand);
-
-int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
-{
- switch (reason) {
- case SCSI_QDEPTH_DEFAULT:
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- break;
- case SCSI_QDEPTH_QFULL:
- scsi_track_queue_full(sdev, depth);
- break;
- case SCSI_QDEPTH_RAMP_UP:
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- break;
- default:
- return -EOPNOTSUPP;
- }
- return sdev->queue_depth;
-}
-EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
-
-int iscsi_target_alloc(struct scsi_target *starget)
-{
- struct iscsi_cls_session *cls_session = starget_to_session(starget);
- struct iscsi_session *session = cls_session->dd_data;
-
-#if 0
- starget->can_queue = session->scsi_cmds_max;
-#endif
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_target_alloc);
-
-static void iscsi_tmf_timedout(unsigned long data)
-{
- struct iscsi_conn *conn = (struct iscsi_conn *)data;
- struct iscsi_session *session = conn->session;
-
- spin_lock(&session->lock);
- if (conn->tmf_state == TMF_QUEUED) {
- conn->tmf_state = TMF_TIMEDOUT;
- ISCSI_DBG_EH(session, "tmf timedout\n");
- /* unblock eh_abort() */
- wake_up(&conn->ehwait);
- }
- spin_unlock(&session->lock);
-}
-
-static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
- struct iscsi_tm *hdr, int age,
- int timeout)
-{
- struct iscsi_session *session = conn->session;
- struct iscsi_task *task;
-
- task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
- NULL, 0);
- if (!task) {
- spin_unlock_bh(&session->lock);
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- spin_lock_bh(&session->lock);
- ISCSI_DBG_EH(session, "tmf exec failure\n");
- return -EPERM;
- }
- conn->tmfcmd_pdus_cnt++;
- conn->tmf_timer.expires = timeout * HZ + jiffies;
- conn->tmf_timer.function = iscsi_tmf_timedout;
- conn->tmf_timer.data = (unsigned long)conn;
- add_timer(&conn->tmf_timer);
- ISCSI_DBG_EH(session, "tmf set timeout\n");
-
- spin_unlock_bh(&session->lock);
- mutex_unlock(&session->eh_mutex);
-
- /*
- * block eh thread until:
- *
- * 1) tmf response
- * 2) tmf timeout
- * 3) session is terminated or restarted or userspace has
- * given up on recovery
- */
- wait_event_interruptible(conn->ehwait, age != session->age ||
- session->state != ISCSI_STATE_LOGGED_IN ||
- conn->tmf_state != TMF_QUEUED);
- if (signal_pending(current))
- flush_signals(current);
- del_timer_sync(&conn->tmf_timer);
-
- mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
- /* if the session drops it will clean up the task */
- if (age != session->age ||
- session->state != ISCSI_STATE_LOGGED_IN)
- return -ENOTCONN;
- return 0;
-}
-
-/*
- * Fail commands. session lock held and recv side suspended and xmit
- * thread flushed
- */
-static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun,
- int error)
-{
- struct iscsi_task *task;
- int i;
-
- for (i = 0; i < conn->session->cmds_max; i++) {
- task = conn->session->cmds[i];
- if (!task->sc || task->state == ISCSI_TASK_FREE)
- continue;
-
- if (lun != -1 && lun != task->sc->device->lun)
- continue;
-
- ISCSI_DBG_SESSION(conn->session,
- "failing sc %p itt 0x%x state %d\n",
- task->sc, task->itt, task->state);
- fail_scsi_task(task, error);
- }
-}
-
-/**
- * iscsi_suspend_queue - suspend iscsi_queuecommand
- * @conn: iscsi conn to stop queueing IO on
- *
- * This grabs the session lock to make sure no one is in
- * xmit_task/queuecommand, and then sets suspend to prevent
- * new commands from being queued. This only needs to be called
- * by offload drivers that need to sync a path like ep disconnect
- * with the iscsi_queuecommand/xmit_task. To start IO again libiscsi
- * will call iscsi_start_tx and iscsi_unblock_session when in FFP.
- */
-void iscsi_suspend_queue(struct iscsi_conn *conn)
-{
- spin_lock_bh(&conn->session->lock);
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- spin_unlock_bh(&conn->session->lock);
-}
-EXPORT_SYMBOL_GPL(iscsi_suspend_queue);
-
-/**
- * iscsi_suspend_tx - suspend iscsi_data_xmit
- * @conn: iscsi conn tp stop processing IO on.
- *
- * This function sets the suspend bit to prevent iscsi_data_xmit
- * from sending new IO, and if work is queued on the xmit thread
- * it will wait for it to be completed.
- */
-void iscsi_suspend_tx(struct iscsi_conn *conn)
-{
- struct Scsi_Host *shost = conn->session->host;
- struct iscsi_host *ihost = shost_priv(shost);
-
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- if (ihost->workq)
- flush_workqueue(ihost->workq);
-}
-EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
-
-static void iscsi_start_tx(struct iscsi_conn *conn)
-{
- clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- iscsi_conn_queue_work(conn);
-}
-
-/*
- * We want to make sure a ping is in flight. It has timed out.
- * And we are not busy processing a pdu that is making
- * progress but got started before the ping and is taking a while
- * to complete so the ping is just stuck behind it in a queue.
- */
-static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
-{
- if (conn->ping_task &&
- time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
- (conn->ping_timeout * HZ), jiffies))
- return 1;
- else
- return 0;
-}
-
-static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
-{
- enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
- struct iscsi_task *task = NULL, *running_task;
- struct iscsi_cls_session *cls_session;
- struct iscsi_session *session;
- struct iscsi_conn *conn;
- int i;
-
- cls_session = starget_to_session(scsi_target(sc->device));
- session = cls_session->dd_data;
-
- ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc);
-
- spin_lock(&session->lock);
- if (session->state != ISCSI_STATE_LOGGED_IN) {
- /*
- * We are probably in the middle of iscsi recovery so let
- * that complete and handle the error.
- */
- rc = BLK_EH_RESET_TIMER;
- goto done;
- }
-
- conn = session->leadconn;
- if (!conn) {
- /* In the middle of shuting down */
- rc = BLK_EH_RESET_TIMER;
- goto done;
- }
-
- task = (struct iscsi_task *)sc->SCp.ptr;
- if (!task) {
- /*
- * Raced with completion. Just reset timer, and let it
- * complete normally
- */
- rc = BLK_EH_RESET_TIMER;
- goto done;
- }
-
- /*
- * If we have sent (at least queued to the network layer) a pdu or
- * recvd one for the task since the last timeout ask for
- * more time. If on the next timeout we have not made progress
- * we can check if it is the task or connection when we send the
- * nop as a ping.
- */
- if (time_after(task->last_xfer, task->last_timeout)) {
- ISCSI_DBG_EH(session, "Command making progress. Asking "
- "scsi-ml for more time to complete. "
- "Last data xfer at %lu. Last timeout was at "
- "%lu\n.", task->last_xfer, task->last_timeout);
- task->have_checked_conn = 0;
- rc = BLK_EH_RESET_TIMER;
- goto done;
- }
-
- if (!conn->recv_timeout && !conn->ping_timeout)
- goto done;
- /*
- * if the ping timedout then we are in the middle of cleaning up
- * and can let the iscsi eh handle it
- */
- if (iscsi_has_ping_timed_out(conn)) {
- rc = BLK_EH_RESET_TIMER;
- goto done;
- }
-
- for (i = 0; i < conn->session->cmds_max; i++) {
- running_task = conn->session->cmds[i];
- if (!running_task->sc || running_task == task ||
- running_task->state != ISCSI_TASK_RUNNING)
- continue;
-
- /*
- * Only check if cmds started before this one have made
- * progress, or this could never fail
- */
- if (time_after(running_task->sc->jiffies_at_alloc,
- task->sc->jiffies_at_alloc))
- continue;
-
- if (time_after(running_task->last_xfer, task->last_timeout)) {
- /*
- * This task has not made progress, but a task
- * started before us has transferred data since
- * we started/last-checked. We could be queueing
- * too many tasks or the LU is bad.
- *
- * If the device is bad the cmds ahead of us on
- * other devs will complete, and this loop will
- * eventually fail starting the scsi eh.
- */
- ISCSI_DBG_EH(session, "Command has not made progress "
- "but commands ahead of it have. "
- "Asking scsi-ml for more time to "
- "complete. Our last xfer vs running task "
- "last xfer %lu/%lu. Last check %lu.\n",
- task->last_xfer, running_task->last_xfer,
- task->last_timeout);
- rc = BLK_EH_RESET_TIMER;
- goto done;
- }
- }
-
- /* Assumes nop timeout is shorter than scsi cmd timeout */
- if (task->have_checked_conn)
- goto done;
-
- /*
- * Checking the transport already or nop from a cmd timeout still
- * running
- */
- if (conn->ping_task) {
- task->have_checked_conn = 1;
- rc = BLK_EH_RESET_TIMER;
- goto done;
- }
-
- /* Make sure there is a transport check done */
- iscsi_send_nopout(conn, NULL);
- task->have_checked_conn = 1;
- rc = BLK_EH_RESET_TIMER;
-
-done:
- if (task)
- task->last_timeout = jiffies;
- spin_unlock(&session->lock);
- ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
- "timer reset" : "nh");
- return rc;
-}
-
-static void iscsi_check_transport_timeouts(unsigned long data)
-{
- struct iscsi_conn *conn = (struct iscsi_conn *)data;
- struct iscsi_session *session = conn->session;
- unsigned long recv_timeout, next_timeout = 0, last_recv;
-
- spin_lock(&session->lock);
- if (session->state != ISCSI_STATE_LOGGED_IN)
- goto done;
-
- recv_timeout = conn->recv_timeout;
- if (!recv_timeout)
- goto done;
-
- recv_timeout *= HZ;
- last_recv = conn->last_recv;
-
- if (iscsi_has_ping_timed_out(conn)) {
- iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs "
- "expired, recv timeout %d, last rx %lu, "
- "last ping %lu, now %lu\n",
- conn->ping_timeout, conn->recv_timeout,
- last_recv, conn->last_ping, jiffies);
- spin_unlock(&session->lock);
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- return;
- }
-
- if (time_before_eq(last_recv + recv_timeout, jiffies)) {
- /* send a ping to try to provoke some traffic */
- ISCSI_DBG_CONN(conn, "Sending nopout as ping\n");
- iscsi_send_nopout(conn, NULL);
- next_timeout = conn->last_ping + (conn->ping_timeout * HZ);
- } else
- next_timeout = last_recv + recv_timeout;
-
- ISCSI_DBG_CONN(conn, "Setting next tmo %lu\n", next_timeout);
- mod_timer(&conn->transport_timer, next_timeout);
-done:
- spin_unlock(&session->lock);
-}
-
-static void iscsi_prep_abort_task_pdu(struct iscsi_task *task,
- struct iscsi_tm *hdr)
-{
- memset(hdr, 0, sizeof(*hdr));
- hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
- hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK;
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- memcpy(hdr->lun, task->lun, sizeof(hdr->lun));
- hdr->rtt = task->hdr_itt;
- hdr->refcmdsn = task->cmdsn;
-}
-
-int iscsi_eh_abort(struct scsi_cmnd *sc)
-{
- struct iscsi_cls_session *cls_session;
- struct iscsi_session *session;
- struct iscsi_conn *conn;
- struct iscsi_task *task;
- struct iscsi_tm *hdr;
- int rc, age;
-
- cls_session = starget_to_session(scsi_target(sc->device));
- session = cls_session->dd_data;
-
- ISCSI_DBG_EH(session, "aborting sc %p\n", sc);
-
- mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
- /*
- * if session was ISCSI_STATE_IN_RECOVERY then we may not have
- * got the command.
- */
- if (!sc->SCp.ptr) {
- ISCSI_DBG_EH(session, "sc never reached iscsi layer or "
- "it completed.\n");
- spin_unlock_bh(&session->lock);
- mutex_unlock(&session->eh_mutex);
- return SUCCESS;
- }
-
- /*
- * If we are not logged in or we have started a new session
- * then let the host reset code handle this
- */
- if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN ||
- sc->SCp.phase != session->age) {
- spin_unlock_bh(&session->lock);
- mutex_unlock(&session->eh_mutex);
- ISCSI_DBG_EH(session, "failing abort due to dropped "
- "session.\n");
- return FAILED;
- }
-
- conn = session->leadconn;
- conn->eh_abort_cnt++;
- age = session->age;
-
- task = (struct iscsi_task *)sc->SCp.ptr;
- ISCSI_DBG_EH(session, "aborting [sc %p itt 0x%x]\n",
- sc, task->itt);
-
- /* task completed before time out */
- if (!task->sc) {
- ISCSI_DBG_EH(session, "sc completed while abort in progress\n");
- goto success;
- }
-
- if (task->state == ISCSI_TASK_PENDING) {
- fail_scsi_task(task, DID_ABORT);
- goto success;
- }
-
- /* only have one tmf outstanding at a time */
- if (conn->tmf_state != TMF_INITIAL)
- goto failed;
- conn->tmf_state = TMF_QUEUED;
-
- hdr = &conn->tmhdr;
- iscsi_prep_abort_task_pdu(task, hdr);
-
- if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) {
- rc = FAILED;
- goto failed;
- }
-
- switch (conn->tmf_state) {
- case TMF_SUCCESS:
- spin_unlock_bh(&session->lock);
- /*
- * stop tx side incase the target had sent a abort rsp but
- * the initiator was still writing out data.
- */
- iscsi_suspend_tx(conn);
- /*
- * we do not stop the recv side because targets have been
- * good and have never sent us a successful tmf response
- * then sent more data for the cmd.
- */
- spin_lock_bh(&session->lock);
- fail_scsi_task(task, DID_ABORT);
- conn->tmf_state = TMF_INITIAL;
- memset(hdr, 0, sizeof(*hdr));
- spin_unlock_bh(&session->lock);
- iscsi_start_tx(conn);
- goto success_unlocked;
- case TMF_TIMEDOUT:
- spin_unlock_bh(&session->lock);
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- goto failed_unlocked;
- case TMF_NOT_FOUND:
- if (!sc->SCp.ptr) {
- conn->tmf_state = TMF_INITIAL;
- memset(hdr, 0, sizeof(*hdr));
- /* task completed before tmf abort response */
- ISCSI_DBG_EH(session, "sc completed while abort in "
- "progress\n");
- goto success;
- }
- /* fall through */
- default:
- conn->tmf_state = TMF_INITIAL;
- goto failed;
- }
-
-success:
- spin_unlock_bh(&session->lock);
-success_unlocked:
- ISCSI_DBG_EH(session, "abort success [sc %p itt 0x%x]\n",
- sc, task->itt);
- mutex_unlock(&session->eh_mutex);
- return SUCCESS;
-
-failed:
- spin_unlock_bh(&session->lock);
-failed_unlocked:
- ISCSI_DBG_EH(session, "abort failed [sc %p itt 0x%x]\n", sc,
- task ? task->itt : 0);
- mutex_unlock(&session->eh_mutex);
- return FAILED;
-}
-EXPORT_SYMBOL_GPL(iscsi_eh_abort);
-
-static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
-{
- memset(hdr, 0, sizeof(*hdr));
- hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
- hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK;
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
- hdr->rtt = RESERVED_ITT;
-}
-
-int iscsi_eh_device_reset(struct scsi_cmnd *sc)
-{
- struct iscsi_cls_session *cls_session;
- struct iscsi_session *session;
- struct iscsi_conn *conn;
- struct iscsi_tm *hdr;
- int rc = FAILED;
-
- cls_session = starget_to_session(scsi_target(sc->device));
- session = cls_session->dd_data;
-
- ISCSI_DBG_EH(session, "LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
-
- mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
- /*
- * Just check if we are not logged in. We cannot check for
- * the phase because the reset could come from an ioctl.
- */
- if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
- goto unlock;
- conn = session->leadconn;
-
- /* only have one tmf outstanding at a time */
- if (conn->tmf_state != TMF_INITIAL)
- goto unlock;
- conn->tmf_state = TMF_QUEUED;
-
- hdr = &conn->tmhdr;
- iscsi_prep_lun_reset_pdu(sc, hdr);
-
- if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
- session->lu_reset_timeout)) {
- rc = FAILED;
- goto unlock;
- }
-
- switch (conn->tmf_state) {
- case TMF_SUCCESS:
- break;
- case TMF_TIMEDOUT:
- spin_unlock_bh(&session->lock);
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- goto done;
- default:
- conn->tmf_state = TMF_INITIAL;
- goto unlock;
- }
-
- rc = SUCCESS;
- spin_unlock_bh(&session->lock);
-
- iscsi_suspend_tx(conn);
-
- spin_lock_bh(&session->lock);
- memset(hdr, 0, sizeof(*hdr));
- fail_scsi_tasks(conn, sc->device->lun, DID_ERROR);
- conn->tmf_state = TMF_INITIAL;
- spin_unlock_bh(&session->lock);
-
- iscsi_start_tx(conn);
- goto done;
-
-unlock:
- spin_unlock_bh(&session->lock);
-done:
- ISCSI_DBG_EH(session, "dev reset result = %s\n",
- rc == SUCCESS ? "SUCCESS" : "FAILED");
- mutex_unlock(&session->eh_mutex);
- return rc;
-}
-EXPORT_SYMBOL_GPL(iscsi_eh_device_reset);
-
-void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
-{
- struct iscsi_session *session = cls_session->dd_data;
-
- spin_lock_bh(&session->lock);
- if (session->state != ISCSI_STATE_LOGGED_IN) {
- session->state = ISCSI_STATE_RECOVERY_FAILED;
- if (session->leadconn)
- wake_up(&session->leadconn->ehwait);
- }
- spin_unlock_bh(&session->lock);
-}
-EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout);
-
-/**
- * iscsi_eh_session_reset - drop session and attempt relogin
- * @sc: scsi command
- *
- * This function will wait for a relogin, session termination from
- * userspace, or a recovery/replacement timeout.
- */
-int iscsi_eh_session_reset(struct scsi_cmnd *sc)
-{
- struct iscsi_cls_session *cls_session;
- struct iscsi_session *session;
- struct iscsi_conn *conn;
-
- cls_session = starget_to_session(scsi_target(sc->device));
- session = cls_session->dd_data;
- conn = session->leadconn;
-
- mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
- if (session->state == ISCSI_STATE_TERMINATE) {
-failed:
- ISCSI_DBG_EH(session,
- "failing session reset: Could not log back into "
- "%s, %s [age %d]\n", session->targetname,
- conn->persistent_address, session->age);
- spin_unlock_bh(&session->lock);
- mutex_unlock(&session->eh_mutex);
- return FAILED;
- }
-
- spin_unlock_bh(&session->lock);
- mutex_unlock(&session->eh_mutex);
- /*
- * we drop the lock here but the leadconn cannot be destoyed while
- * we are in the scsi eh
- */
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-
- ISCSI_DBG_EH(session, "wait for relogin\n");
- wait_event_interruptible(conn->ehwait,
- session->state == ISCSI_STATE_TERMINATE ||
- session->state == ISCSI_STATE_LOGGED_IN ||
- session->state == ISCSI_STATE_RECOVERY_FAILED);
- if (signal_pending(current))
- flush_signals(current);
-
- mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
- if (session->state == ISCSI_STATE_LOGGED_IN) {
- ISCSI_DBG_EH(session,
- "session reset succeeded for %s,%s\n",
- session->targetname, conn->persistent_address);
- } else
- goto failed;
- spin_unlock_bh(&session->lock);
- mutex_unlock(&session->eh_mutex);
- return SUCCESS;
-}
-EXPORT_SYMBOL_GPL(iscsi_eh_session_reset);
-
-static void iscsi_prep_tgt_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
-{
- memset(hdr, 0, sizeof(*hdr));
- hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
- hdr->flags = ISCSI_TM_FUNC_TARGET_WARM_RESET & ISCSI_FLAG_TM_FUNC_MASK;
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- hdr->rtt = RESERVED_ITT;
-}
-
-/**
- * iscsi_eh_target_reset - reset target
- * @sc: scsi command
- *
- * This will attempt to send a warm target reset.
- */
-int iscsi_eh_target_reset(struct scsi_cmnd *sc)
-{
- struct iscsi_cls_session *cls_session;
- struct iscsi_session *session;
- struct iscsi_conn *conn;
- struct iscsi_tm *hdr;
- int rc = FAILED;
-
- cls_session = starget_to_session(scsi_target(sc->device));
- session = cls_session->dd_data;
-
- ISCSI_DBG_EH(session, "tgt Reset [sc %p tgt %s]\n", sc,
- session->targetname);
-
- mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
- /*
- * Just check if we are not logged in. We cannot check for
- * the phase because the reset could come from an ioctl.
- */
- if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
- goto unlock;
- conn = session->leadconn;
-
- /* only have one tmf outstanding at a time */
- if (conn->tmf_state != TMF_INITIAL)
- goto unlock;
- conn->tmf_state = TMF_QUEUED;
-
- hdr = &conn->tmhdr;
- iscsi_prep_tgt_reset_pdu(sc, hdr);
-
- if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
- session->tgt_reset_timeout)) {
- rc = FAILED;
- goto unlock;
- }
-
- switch (conn->tmf_state) {
- case TMF_SUCCESS:
- break;
- case TMF_TIMEDOUT:
- spin_unlock_bh(&session->lock);
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- goto done;
- default:
- conn->tmf_state = TMF_INITIAL;
- goto unlock;
- }
-
- rc = SUCCESS;
- spin_unlock_bh(&session->lock);
-
- iscsi_suspend_tx(conn);
-
- spin_lock_bh(&session->lock);
- memset(hdr, 0, sizeof(*hdr));
- fail_scsi_tasks(conn, -1, DID_ERROR);
- conn->tmf_state = TMF_INITIAL;
- spin_unlock_bh(&session->lock);
-
- iscsi_start_tx(conn);
- goto done;
-
-unlock:
- spin_unlock_bh(&session->lock);
-done:
- ISCSI_DBG_EH(session, "tgt %s reset result = %s\n", session->targetname,
- rc == SUCCESS ? "SUCCESS" : "FAILED");
- mutex_unlock(&session->eh_mutex);
- return rc;
-}
-EXPORT_SYMBOL_GPL(iscsi_eh_target_reset);
-
-/**
- * iscsi_eh_recover_target - reset target and possibly the session
- * @sc: scsi command
- *
- * This will attempt to send a warm target reset. If that fails,
- * we will escalate to ERL0 session recovery.
- */
-int iscsi_eh_recover_target(struct scsi_cmnd *sc)
-{
- int rc;
-
- rc = iscsi_eh_target_reset(sc);
- if (rc == FAILED)
- rc = iscsi_eh_session_reset(sc);
- return rc;
-}
-EXPORT_SYMBOL_GPL(iscsi_eh_recover_target);
-
-/*
- * Pre-allocate a pool of @max items of @item_size. By default, the pool
- * should be accessed via kfifo_{get,put} on q->queue.
- * Optionally, the caller can obtain the array of object pointers
- * by passing in a non-NULL @items pointer
- */
-int
-iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
-{
- int i, num_arrays = 1;
-
- memset(q, 0, sizeof(*q));
-
- q->max = max;
-
- /* If the user passed an items pointer, he wants a copy of
- * the array. */
- if (items)
- num_arrays++;
- q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL);
- if (q->pool == NULL)
- return -ENOMEM;
-
- kfifo_init(&q->queue, (void*)q->pool, max * sizeof(void*));
-
- for (i = 0; i < max; i++) {
- q->pool[i] = kzalloc(item_size, GFP_KERNEL);
- if (q->pool[i] == NULL) {
- q->max = i;
- goto enomem;
- }
- kfifo_in(&q->queue, (void*)&q->pool[i], sizeof(void*));
- }
-
- if (items) {
- *items = q->pool + max;
- memcpy(*items, q->pool, max * sizeof(void *));
- }
-
- return 0;
-
-enomem:
- iscsi_pool_free(q);
- return -ENOMEM;
-}
-EXPORT_SYMBOL_GPL(iscsi_pool_init);
-
-void iscsi_pool_free(struct iscsi_pool *q)
-{
- int i;
-
- for (i = 0; i < q->max; i++)
- kfree(q->pool[i]);
- kfree(q->pool);
-}
-EXPORT_SYMBOL_GPL(iscsi_pool_free);
-
-/**
- * iscsi_host_add - add host to system
- * @shost: scsi host
- * @pdev: parent device
- *
- * This should be called by partial offload and software iscsi drivers
- * to add a host to the system.
- */
-int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev)
-{
- if (!shost->can_queue)
- shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX;
-
- if (!shost->cmd_per_lun)
- shost->cmd_per_lun = ISCSI_DEF_CMD_PER_LUN;
-
- if (!shost->transportt->eh_timed_out)
- shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
- return scsi_add_host(shost, pdev);
-}
-EXPORT_SYMBOL_GPL(iscsi_host_add);
-
-/**
- * iscsi_host_alloc - allocate a host and driver data
- * @sht: scsi host template
- * @dd_data_size: driver host data size
- * @xmit_can_sleep: bool indicating if LLD will queue IO from a work queue
- *
- * This should be called by partial offload and software iscsi drivers.
- * To access the driver specific memory use the iscsi_host_priv() macro.
- */
-struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
- int dd_data_size, bool xmit_can_sleep)
-{
- struct Scsi_Host *shost;
- struct iscsi_host *ihost;
-
- shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size);
- if (!shost)
- return NULL;
- ihost = shost_priv(shost);
-
- if (xmit_can_sleep) {
- snprintf(ihost->workq_name, sizeof(ihost->workq_name),
- "iscsi_q_%d", shost->host_no);
- ihost->workq = create_singlethread_workqueue(ihost->workq_name);
- if (!ihost->workq)
- goto free_host;
- }
-
- spin_lock_init(&ihost->lock);
- ihost->state = ISCSI_HOST_SETUP;
- ihost->num_sessions = 0;
- init_waitqueue_head(&ihost->session_removal_wq);
- return shost;
-
-free_host:
- scsi_host_put(shost);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(iscsi_host_alloc);
-
-static void iscsi_notify_host_removed(struct iscsi_cls_session *cls_session)
-{
- iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_INVALID_HOST);
-}
-
-/**
- * iscsi_host_remove - remove host and sessions
- * @shost: scsi host
- *
- * If there are any sessions left, this will initiate the removal and wait
- * for the completion.
- */
-void iscsi_host_remove(struct Scsi_Host *shost)
-{
- struct iscsi_host *ihost = shost_priv(shost);
- unsigned long flags;
-
- spin_lock_irqsave(&ihost->lock, flags);
- ihost->state = ISCSI_HOST_REMOVED;
- spin_unlock_irqrestore(&ihost->lock, flags);
-
- iscsi_host_for_each_session(shost, iscsi_notify_host_removed);
- wait_event_interruptible(ihost->session_removal_wq,
- ihost->num_sessions == 0);
- if (signal_pending(current))
- flush_signals(current);
-
- scsi_remove_host(shost);
- if (ihost->workq)
- destroy_workqueue(ihost->workq);
-}
-EXPORT_SYMBOL_GPL(iscsi_host_remove);
-
-void iscsi_host_free(struct Scsi_Host *shost)
-{
- struct iscsi_host *ihost = shost_priv(shost);
-
- kfree(ihost->netdev);
- kfree(ihost->hwaddress);
- kfree(ihost->initiatorname);
- scsi_host_put(shost);
-}
-EXPORT_SYMBOL_GPL(iscsi_host_free);
-
-static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost)
-{
- struct iscsi_host *ihost = shost_priv(shost);
- unsigned long flags;
-
- shost = scsi_host_get(shost);
- if (!shost) {
- printk(KERN_ERR "Invalid state. Cannot notify host removal "
- "of session teardown event because host already "
- "removed.\n");
- return;
- }
-
- spin_lock_irqsave(&ihost->lock, flags);
- ihost->num_sessions--;
- if (ihost->num_sessions == 0)
- wake_up(&ihost->session_removal_wq);
- spin_unlock_irqrestore(&ihost->lock, flags);
- scsi_host_put(shost);
-}
-
-/**
- * iscsi_session_setup - create iscsi cls session and host and session
- * @iscsit: iscsi transport template
- * @shost: scsi host
- * @cmds_max: session can queue
- * @cmd_task_size: LLD task private data size
- * @initial_cmdsn: initial CmdSN
- *
- * This can be used by software iscsi_transports that allocate
- * a session per scsi host.
- *
- * Callers should set cmds_max to the largest total numer (mgmt + scsi) of
- * tasks they support. The iscsi layer reserves ISCSI_MGMT_CMDS_MAX tasks
- * for nop handling and login/logout requests.
- */
-struct iscsi_cls_session *
-iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
- uint16_t cmds_max, int dd_size, int cmd_task_size,
- uint32_t initial_cmdsn, unsigned int id)
-{
- struct iscsi_host *ihost = shost_priv(shost);
- struct iscsi_session *session;
- struct iscsi_cls_session *cls_session;
- int cmd_i, scsi_cmds, total_cmds = cmds_max;
- unsigned long flags;
-
- spin_lock_irqsave(&ihost->lock, flags);
- if (ihost->state == ISCSI_HOST_REMOVED) {
- spin_unlock_irqrestore(&ihost->lock, flags);
- return NULL;
- }
- ihost->num_sessions++;
- spin_unlock_irqrestore(&ihost->lock, flags);
-
- if (!total_cmds)
- total_cmds = ISCSI_DEF_XMIT_CMDS_MAX;
- /*
- * The iscsi layer needs some tasks for nop handling and tmfs,
- * so the cmds_max must at least be greater than ISCSI_MGMT_CMDS_MAX
- * + 1 command for scsi IO.
- */
- if (total_cmds < ISCSI_TOTAL_CMDS_MIN) {
- printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
- "must be a power of two that is at least %d.\n",
- total_cmds, ISCSI_TOTAL_CMDS_MIN);
- goto dec_session_count;
- }
-
- if (total_cmds > ISCSI_TOTAL_CMDS_MAX) {
- printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
- "must be a power of 2 less than or equal to %d.\n",
- cmds_max, ISCSI_TOTAL_CMDS_MAX);
- total_cmds = ISCSI_TOTAL_CMDS_MAX;
- }
-
- if (!is_power_of_2(total_cmds)) {
- printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
- "must be a power of 2.\n", total_cmds);
- total_cmds = rounddown_pow_of_two(total_cmds);
- if (total_cmds < ISCSI_TOTAL_CMDS_MIN)
- return NULL;
- printk(KERN_INFO "iscsi: Rounding can_queue to %d.\n",
- total_cmds);
- }
- scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX;
-
- cls_session = iscsi_alloc_session(shost, iscsit,
- sizeof(struct iscsi_session) +
- dd_size);
- if (!cls_session)
- goto dec_session_count;
- session = cls_session->dd_data;
- session->cls_session = cls_session;
- session->host = shost;
- session->state = ISCSI_STATE_FREE;
- session->fast_abort = 1;
- session->tgt_reset_timeout = 30;
- session->lu_reset_timeout = 15;
- session->abort_timeout = 10;
- session->scsi_cmds_max = scsi_cmds;
- session->cmds_max = total_cmds;
- session->queued_cmdsn = session->cmdsn = initial_cmdsn;
- session->exp_cmdsn = initial_cmdsn + 1;
- session->max_cmdsn = initial_cmdsn + 1;
- session->max_r2t = 1;
- session->tt = iscsit;
- session->dd_data = cls_session->dd_data + sizeof(*session);
- mutex_init(&session->eh_mutex);
- spin_lock_init(&session->lock);
-
- /* initialize SCSI PDU commands pool */
- if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
- (void***)&session->cmds,
- cmd_task_size + sizeof(struct iscsi_task)))
- goto cmdpool_alloc_fail;
-
- /* pre-format cmds pool with ITT */
- for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
- struct iscsi_task *task = session->cmds[cmd_i];
-
- if (cmd_task_size)
- task->dd_data = &task[1];
- task->itt = cmd_i;
- task->state = ISCSI_TASK_FREE;
- INIT_LIST_HEAD(&task->running);
- }
-
- if (!try_module_get(iscsit->owner))
- goto module_get_fail;
-
- if (iscsi_add_session(cls_session, id))
- goto cls_session_fail;
-
- return cls_session;
-
-cls_session_fail:
- module_put(iscsit->owner);
-module_get_fail:
- iscsi_pool_free(&session->cmdpool);
-cmdpool_alloc_fail:
- iscsi_free_session(cls_session);
-dec_session_count:
- iscsi_host_dec_session_cnt(shost);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(iscsi_session_setup);
-
-/**
- * iscsi_session_teardown - destroy session, host, and cls_session
- * @cls_session: iscsi session
- *
- * The driver must have called iscsi_remove_session before
- * calling this.
- */
-void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
-{
- struct iscsi_session *session = cls_session->dd_data;
- struct module *owner = cls_session->transport->owner;
- struct Scsi_Host *shost = session->host;
-
- iscsi_pool_free(&session->cmdpool);
-
- kfree(session->password);
- kfree(session->password_in);
- kfree(session->username);
- kfree(session->username_in);
- kfree(session->targetname);
- kfree(session->initiatorname);
- kfree(session->ifacename);
-
- iscsi_destroy_session(cls_session);
- iscsi_host_dec_session_cnt(shost);
- module_put(owner);
-}
-EXPORT_SYMBOL_GPL(iscsi_session_teardown);
-
-/**
- * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn
- * @cls_session: iscsi_cls_session
- * @dd_size: private driver data size
- * @conn_idx: cid
- */
-struct iscsi_cls_conn *
-iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
- uint32_t conn_idx)
-{
- struct iscsi_session *session = cls_session->dd_data;
- struct iscsi_conn *conn;
- struct iscsi_cls_conn *cls_conn;
- char *data;
-
- cls_conn = iscsi_create_conn(cls_session, sizeof(*conn) + dd_size,
- conn_idx);
- if (!cls_conn)
- return NULL;
- conn = cls_conn->dd_data;
- memset(conn, 0, sizeof(*conn) + dd_size);
-
- conn->dd_data = cls_conn->dd_data + sizeof(*conn);
- conn->session = session;
- conn->cls_conn = cls_conn;
- conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
- conn->id = conn_idx;
- conn->exp_statsn = 0;
- conn->tmf_state = TMF_INITIAL;
-
- init_timer(&conn->transport_timer);
- conn->transport_timer.data = (unsigned long)conn;
- conn->transport_timer.function = iscsi_check_transport_timeouts;
-
- INIT_LIST_HEAD(&conn->mgmtqueue);
- INIT_LIST_HEAD(&conn->cmdqueue);
- INIT_LIST_HEAD(&conn->requeue);
- INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
-
- /* allocate login_task used for the login/text sequences */
- spin_lock_bh(&session->lock);
- if (!kfifo_out(&session->cmdpool.queue,
- (void*)&conn->login_task,
- sizeof(void*))) {
- spin_unlock_bh(&session->lock);
- goto login_task_alloc_fail;
- }
- spin_unlock_bh(&session->lock);
-
- data = (char *) __get_free_pages(GFP_KERNEL,
- get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
- if (!data)
- goto login_task_data_alloc_fail;
- conn->login_task->data = conn->data = data;
-
- init_timer(&conn->tmf_timer);
- init_waitqueue_head(&conn->ehwait);
-
- return cls_conn;
-
-login_task_data_alloc_fail:
- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
- sizeof(void*));
-login_task_alloc_fail:
- iscsi_destroy_conn(cls_conn);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_setup);
-
-/**
- * iscsi_conn_teardown - teardown iscsi connection
- * cls_conn: iscsi class connection
- *
- * TODO: we may need to make this into a two step process
- * like scsi-mls remove + put host
- */
-void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_session *session = conn->session;
- unsigned long flags;
-
- del_timer_sync(&conn->transport_timer);
-
- spin_lock_bh(&session->lock);
- conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
- if (session->leadconn == conn) {
- /*
- * leading connection? then give up on recovery.
- */
- session->state = ISCSI_STATE_TERMINATE;
- wake_up(&conn->ehwait);
- }
- spin_unlock_bh(&session->lock);
-
- /*
- * Block until all in-progress commands for this connection
- * time out or fail.
- */
- for (;;) {
- spin_lock_irqsave(session->host->host_lock, flags);
- if (!session->host->host_busy) { /* OK for ERL == 0 */
- spin_unlock_irqrestore(session->host->host_lock, flags);
- break;
- }
- spin_unlock_irqrestore(session->host->host_lock, flags);
- msleep_interruptible(500);
- iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): "
- "host_busy %d host_failed %d\n",
- session->host->host_busy,
- session->host->host_failed);
- /*
- * force eh_abort() to unblock
- */
- wake_up(&conn->ehwait);
- }
-
- /* flush queued up work because we free the connection below */
- iscsi_suspend_tx(conn);
-
- spin_lock_bh(&session->lock);
- free_pages((unsigned long) conn->data,
- get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
- kfree(conn->persistent_address);
- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
- sizeof(void*));
- if (session->leadconn == conn)
- session->leadconn = NULL;
- spin_unlock_bh(&session->lock);
-
- iscsi_destroy_conn(cls_conn);
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_teardown);
-
-int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_session *session = conn->session;
-
- if (!session) {
- iscsi_conn_printk(KERN_ERR, conn,
- "can't start unbound connection\n");
- return -EPERM;
- }
-
- if ((session->imm_data_en || !session->initial_r2t_en) &&
- session->first_burst > session->max_burst) {
- iscsi_conn_printk(KERN_INFO, conn, "invalid burst lengths: "
- "first_burst %d max_burst %d\n",
- session->first_burst, session->max_burst);
- return -EINVAL;
- }
-
- if (conn->ping_timeout && !conn->recv_timeout) {
- iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of "
- "zero. Using 5 seconds\n.");
- conn->recv_timeout = 5;
- }
-
- if (conn->recv_timeout && !conn->ping_timeout) {
- iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of "
- "zero. Using 5 seconds.\n");
- conn->ping_timeout = 5;
- }
-
- spin_lock_bh(&session->lock);
- conn->c_stage = ISCSI_CONN_STARTED;
- session->state = ISCSI_STATE_LOGGED_IN;
- session->queued_cmdsn = session->cmdsn;
-
- conn->last_recv = jiffies;
- conn->last_ping = jiffies;
- if (conn->recv_timeout && conn->ping_timeout)
- mod_timer(&conn->transport_timer,
- jiffies + (conn->recv_timeout * HZ));
-
- switch(conn->stop_stage) {
- case STOP_CONN_RECOVER:
- /*
- * unblock eh_abort() if it is blocked. re-try all
- * commands after successful recovery
- */
- conn->stop_stage = 0;
- conn->tmf_state = TMF_INITIAL;
- session->age++;
- if (session->age == 16)
- session->age = 0;
- break;
- case STOP_CONN_TERM:
- conn->stop_stage = 0;
- break;
- default:
- break;
- }
- spin_unlock_bh(&session->lock);
-
- iscsi_unblock_session(session->cls_session);
- wake_up(&conn->ehwait);
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_start);
-
-static void
-fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
-{
- struct iscsi_task *task;
- int i, state;
-
- for (i = 0; i < conn->session->cmds_max; i++) {
- task = conn->session->cmds[i];
- if (task->sc)
- continue;
-
- if (task->state == ISCSI_TASK_FREE)
- continue;
-
- ISCSI_DBG_SESSION(conn->session,
- "failing mgmt itt 0x%x state %d\n",
- task->itt, task->state);
- state = ISCSI_TASK_ABRT_SESS_RECOV;
- if (task->state == ISCSI_TASK_PENDING)
- state = ISCSI_TASK_COMPLETED;
- iscsi_complete_task(task, state);
-
- }
-}
-
-static void iscsi_start_session_recovery(struct iscsi_session *session,
- struct iscsi_conn *conn, int flag)
-{
- int old_stop_stage;
-
- mutex_lock(&session->eh_mutex);
- spin_lock_bh(&session->lock);
- if (conn->stop_stage == STOP_CONN_TERM) {
- spin_unlock_bh(&session->lock);
- mutex_unlock(&session->eh_mutex);
- return;
- }
-
- /*
- * When this is called for the in_login state, we only want to clean
- * up the login task and connection. We do not need to block and set
- * the recovery state again
- */
- if (flag == STOP_CONN_TERM)
- session->state = ISCSI_STATE_TERMINATE;
- else if (conn->stop_stage != STOP_CONN_RECOVER)
- session->state = ISCSI_STATE_IN_RECOVERY;
-
- old_stop_stage = conn->stop_stage;
- conn->stop_stage = flag;
- spin_unlock_bh(&session->lock);
-
- del_timer_sync(&conn->transport_timer);
- iscsi_suspend_tx(conn);
-
- spin_lock_bh(&session->lock);
- conn->c_stage = ISCSI_CONN_STOPPED;
- spin_unlock_bh(&session->lock);
-
- /*
- * for connection level recovery we should not calculate
- * header digest. conn->hdr_size used for optimization
- * in hdr_extract() and will be re-negotiated at
- * set_param() time.
- */
- if (flag == STOP_CONN_RECOVER) {
- conn->hdrdgst_en = 0;
- conn->datadgst_en = 0;
- if (session->state == ISCSI_STATE_IN_RECOVERY &&
- old_stop_stage != STOP_CONN_RECOVER) {
- ISCSI_DBG_SESSION(session, "blocking session\n");
- iscsi_block_session(session->cls_session);
- }
- }
-
- /*
- * flush queues.
- */
- spin_lock_bh(&session->lock);
- fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
- fail_mgmt_tasks(session, conn);
- memset(&conn->tmhdr, 0, sizeof(conn->tmhdr));
- spin_unlock_bh(&session->lock);
- mutex_unlock(&session->eh_mutex);
-}
-
-void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_session *session = conn->session;
-
- switch (flag) {
- case STOP_CONN_RECOVER:
- case STOP_CONN_TERM:
- iscsi_start_session_recovery(session, conn, flag);
- break;
- default:
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid stop flag %d\n", flag);
- }
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_stop);
-
-int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
- struct iscsi_cls_conn *cls_conn, int is_leading)
-{
- struct iscsi_session *session = cls_session->dd_data;
- struct iscsi_conn *conn = cls_conn->dd_data;
-
- spin_lock_bh(&session->lock);
- if (is_leading)
- session->leadconn = conn;
- spin_unlock_bh(&session->lock);
-
- /*
- * Unblock xmitworker(), Login Phase will pass through.
- */
- clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
- clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_bind);
-
-static int iscsi_switch_str_param(char **param, char *new_val_buf)
-{
- char *new_val;
-
- if (*param) {
- if (!strcmp(*param, new_val_buf))
- return 0;
- }
-
- new_val = kstrdup(new_val_buf, GFP_NOIO);
- if (!new_val)
- return -ENOMEM;
-
- kfree(*param);
- *param = new_val;
- return 0;
-}
-
-int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf, int buflen)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_session *session = conn->session;
- uint32_t value;
-
- switch(param) {
- case ISCSI_PARAM_FAST_ABORT:
- sscanf(buf, "%d", &session->fast_abort);
- break;
- case ISCSI_PARAM_ABORT_TMO:
- sscanf(buf, "%d", &session->abort_timeout);
- break;
- case ISCSI_PARAM_LU_RESET_TMO:
- sscanf(buf, "%d", &session->lu_reset_timeout);
- break;
- case ISCSI_PARAM_TGT_RESET_TMO:
- sscanf(buf, "%d", &session->tgt_reset_timeout);
- break;
- case ISCSI_PARAM_PING_TMO:
- sscanf(buf, "%d", &conn->ping_timeout);
- break;
- case ISCSI_PARAM_RECV_TMO:
- sscanf(buf, "%d", &conn->recv_timeout);
- break;
- case ISCSI_PARAM_MAX_RECV_DLENGTH:
- sscanf(buf, "%d", &conn->max_recv_dlength);
- break;
- case ISCSI_PARAM_MAX_XMIT_DLENGTH:
- sscanf(buf, "%d", &conn->max_xmit_dlength);
- break;
- case ISCSI_PARAM_HDRDGST_EN:
- sscanf(buf, "%d", &conn->hdrdgst_en);
- break;
- case ISCSI_PARAM_DATADGST_EN:
- sscanf(buf, "%d", &conn->datadgst_en);
- break;
- case ISCSI_PARAM_INITIAL_R2T_EN:
- sscanf(buf, "%d", &session->initial_r2t_en);
- break;
- case ISCSI_PARAM_MAX_R2T:
- sscanf(buf, "%d", &session->max_r2t);
- break;
- case ISCSI_PARAM_IMM_DATA_EN:
- sscanf(buf, "%d", &session->imm_data_en);
- break;
- case ISCSI_PARAM_FIRST_BURST:
- sscanf(buf, "%d", &session->first_burst);
- break;
- case ISCSI_PARAM_MAX_BURST:
- sscanf(buf, "%d", &session->max_burst);
- break;
- case ISCSI_PARAM_PDU_INORDER_EN:
- sscanf(buf, "%d", &session->pdu_inorder_en);
- break;
- case ISCSI_PARAM_DATASEQ_INORDER_EN:
- sscanf(buf, "%d", &session->dataseq_inorder_en);
- break;
- case ISCSI_PARAM_ERL:
- sscanf(buf, "%d", &session->erl);
- break;
- case ISCSI_PARAM_IFMARKER_EN:
- sscanf(buf, "%d", &value);
- BUG_ON(value);
- break;
- case ISCSI_PARAM_OFMARKER_EN:
- sscanf(buf, "%d", &value);
- BUG_ON(value);
- break;
- case ISCSI_PARAM_EXP_STATSN:
- sscanf(buf, "%u", &conn->exp_statsn);
- break;
- case ISCSI_PARAM_USERNAME:
- return iscsi_switch_str_param(&session->username, buf);
- case ISCSI_PARAM_USERNAME_IN:
- return iscsi_switch_str_param(&session->username_in, buf);
- case ISCSI_PARAM_PASSWORD:
- return iscsi_switch_str_param(&session->password, buf);
- case ISCSI_PARAM_PASSWORD_IN:
- return iscsi_switch_str_param(&session->password_in, buf);
- case ISCSI_PARAM_TARGET_NAME:
- return iscsi_switch_str_param(&session->targetname, buf);
- case ISCSI_PARAM_TPGT:
- sscanf(buf, "%d", &session->tpgt);
- break;
- case ISCSI_PARAM_PERSISTENT_PORT:
- sscanf(buf, "%d", &conn->persistent_port);
- break;
- case ISCSI_PARAM_PERSISTENT_ADDRESS:
- return iscsi_switch_str_param(&conn->persistent_address, buf);
- case ISCSI_PARAM_IFACE_NAME:
- return iscsi_switch_str_param(&session->ifacename, buf);
- case ISCSI_PARAM_INITIATOR_NAME:
- return iscsi_switch_str_param(&session->initiatorname, buf);
- default:
- return -ENOSYS;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_set_param);
-
-int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
- enum iscsi_param param, char *buf)
-{
- struct iscsi_session *session = cls_session->dd_data;
- int len;
-
- switch(param) {
- case ISCSI_PARAM_FAST_ABORT:
- len = sprintf(buf, "%d\n", session->fast_abort);
- break;
- case ISCSI_PARAM_ABORT_TMO:
- len = sprintf(buf, "%d\n", session->abort_timeout);
- break;
- case ISCSI_PARAM_LU_RESET_TMO:
- len = sprintf(buf, "%d\n", session->lu_reset_timeout);
- break;
- case ISCSI_PARAM_TGT_RESET_TMO:
- len = sprintf(buf, "%d\n", session->tgt_reset_timeout);
- break;
- case ISCSI_PARAM_INITIAL_R2T_EN:
- len = sprintf(buf, "%d\n", session->initial_r2t_en);
- break;
- case ISCSI_PARAM_MAX_R2T:
- len = sprintf(buf, "%hu\n", session->max_r2t);
- break;
- case ISCSI_PARAM_IMM_DATA_EN:
- len = sprintf(buf, "%d\n", session->imm_data_en);
- break;
- case ISCSI_PARAM_FIRST_BURST:
- len = sprintf(buf, "%u\n", session->first_burst);
- break;
- case ISCSI_PARAM_MAX_BURST:
- len = sprintf(buf, "%u\n", session->max_burst);
- break;
- case ISCSI_PARAM_PDU_INORDER_EN:
- len = sprintf(buf, "%d\n", session->pdu_inorder_en);
- break;
- case ISCSI_PARAM_DATASEQ_INORDER_EN:
- len = sprintf(buf, "%d\n", session->dataseq_inorder_en);
- break;
- case ISCSI_PARAM_ERL:
- len = sprintf(buf, "%d\n", session->erl);
- break;
- case ISCSI_PARAM_TARGET_NAME:
- len = sprintf(buf, "%s\n", session->targetname);
- break;
- case ISCSI_PARAM_TPGT:
- len = sprintf(buf, "%d\n", session->tpgt);
- break;
- case ISCSI_PARAM_USERNAME:
- len = sprintf(buf, "%s\n", session->username);
- break;
- case ISCSI_PARAM_USERNAME_IN:
- len = sprintf(buf, "%s\n", session->username_in);
- break;
- case ISCSI_PARAM_PASSWORD:
- len = sprintf(buf, "%s\n", session->password);
- break;
- case ISCSI_PARAM_PASSWORD_IN:
- len = sprintf(buf, "%s\n", session->password_in);
- break;
- case ISCSI_PARAM_IFACE_NAME:
- len = sprintf(buf, "%s\n", session->ifacename);
- break;
- case ISCSI_PARAM_INITIATOR_NAME:
- len = sprintf(buf, "%s\n", session->initiatorname);
- break;
- default:
- return -ENOSYS;
- }
-
- return len;
-}
-EXPORT_SYMBOL_GPL(iscsi_session_get_param);
-
-int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- int len;
-
- switch(param) {
- case ISCSI_PARAM_PING_TMO:
- len = sprintf(buf, "%u\n", conn->ping_timeout);
- break;
- case ISCSI_PARAM_RECV_TMO:
- len = sprintf(buf, "%u\n", conn->recv_timeout);
- break;
- case ISCSI_PARAM_MAX_RECV_DLENGTH:
- len = sprintf(buf, "%u\n", conn->max_recv_dlength);
- break;
- case ISCSI_PARAM_MAX_XMIT_DLENGTH:
- len = sprintf(buf, "%u\n", conn->max_xmit_dlength);
- break;
- case ISCSI_PARAM_HDRDGST_EN:
- len = sprintf(buf, "%d\n", conn->hdrdgst_en);
- break;
- case ISCSI_PARAM_DATADGST_EN:
- len = sprintf(buf, "%d\n", conn->datadgst_en);
- break;
- case ISCSI_PARAM_IFMARKER_EN:
- len = sprintf(buf, "%d\n", conn->ifmarker_en);
- break;
- case ISCSI_PARAM_OFMARKER_EN:
- len = sprintf(buf, "%d\n", conn->ofmarker_en);
- break;
- case ISCSI_PARAM_EXP_STATSN:
- len = sprintf(buf, "%u\n", conn->exp_statsn);
- break;
- case ISCSI_PARAM_PERSISTENT_PORT:
- len = sprintf(buf, "%d\n", conn->persistent_port);
- break;
- case ISCSI_PARAM_PERSISTENT_ADDRESS:
- len = sprintf(buf, "%s\n", conn->persistent_address);
- break;
- default:
- return -ENOSYS;
- }
-
- return len;
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_get_param);
-
-int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
- char *buf)
-{
- struct iscsi_host *ihost = shost_priv(shost);
- int len;
-
- switch (param) {
- case ISCSI_HOST_PARAM_NETDEV_NAME:
- len = sprintf(buf, "%s\n", ihost->netdev);
- break;
- case ISCSI_HOST_PARAM_HWADDRESS:
- len = sprintf(buf, "%s\n", ihost->hwaddress);
- break;
- case ISCSI_HOST_PARAM_INITIATOR_NAME:
- len = sprintf(buf, "%s\n", ihost->initiatorname);
- break;
- case ISCSI_HOST_PARAM_IPADDRESS:
- len = sprintf(buf, "%s\n", ihost->local_address);
- break;
- default:
- return -ENOSYS;
- }
-
- return len;
-}
-EXPORT_SYMBOL_GPL(iscsi_host_get_param);
-
-int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param,
- char *buf, int buflen)
-{
- struct iscsi_host *ihost = shost_priv(shost);
-
- switch (param) {
- case ISCSI_HOST_PARAM_NETDEV_NAME:
- return iscsi_switch_str_param(&ihost->netdev, buf);
- case ISCSI_HOST_PARAM_HWADDRESS:
- return iscsi_switch_str_param(&ihost->hwaddress, buf);
- case ISCSI_HOST_PARAM_INITIATOR_NAME:
- return iscsi_switch_str_param(&ihost->initiatorname, buf);
- default:
- return -ENOSYS;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_host_set_param);
-
-MODULE_AUTHOR("Mike Christie");
-MODULE_DESCRIPTION("iSCSI library functions");
-MODULE_LICENSE("GPL");
diff --git a/kernel/libiscsi.h b/kernel/libiscsi.h
deleted file mode 100644
index 0563539..0000000
--- a/kernel/libiscsi.h
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * iSCSI lib definitions
- *
- * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2004 - 2006 Mike Christie
- * Copyright (C) 2004 - 2005 Dmitry Yusupov
- * Copyright (C) 2004 - 2005 Alex Aizman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-#ifndef LIBISCSI_H
-#define LIBISCSI_H
-
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include "iscsi_proto.h"
-#include "iscsi_if.h"
-#include "scsi_transport_iscsi.h"
-
-struct scsi_transport_template;
-struct scsi_host_template;
-struct scsi_device;
-struct Scsi_Host;
-struct scsi_target;
-struct scsi_cmnd;
-struct socket;
-struct iscsi_transport;
-struct iscsi_cls_session;
-struct iscsi_cls_conn;
-struct iscsi_session;
-struct iscsi_nopin;
-struct device;
-
-#define ISCSI_DEF_XMIT_CMDS_MAX 128 /* must be power of 2 */
-#define ISCSI_MGMT_CMDS_MAX 15
-
-#define ISCSI_DEF_CMD_PER_LUN 32
-
-/* Task Mgmt states */
-enum {
- TMF_INITIAL,
- TMF_QUEUED,
- TMF_SUCCESS,
- TMF_FAILED,
- TMF_TIMEDOUT,
- TMF_NOT_FOUND,
-};
-
-/* Connection suspend "bit" */
-#define ISCSI_SUSPEND_BIT 1
-
-#define ISCSI_ITT_MASK 0x1fff
-#define ISCSI_TOTAL_CMDS_MAX 4096
-/* this must be a power of two greater than ISCSI_MGMT_CMDS_MAX */
-#define ISCSI_TOTAL_CMDS_MIN 16
-#define ISCSI_AGE_SHIFT 28
-#define ISCSI_AGE_MASK 0xf
-
-#define ISCSI_ADDRESS_BUF_LEN 64
-
-enum {
- /* this is the maximum possible storage for AHSs */
- ISCSI_MAX_AHS_SIZE = sizeof(struct iscsi_ecdb_ahdr) +
- sizeof(struct iscsi_rlength_ahdr),
- ISCSI_DIGEST_SIZE = sizeof(__u32),
-};
-
-
-enum {
- ISCSI_TASK_FREE,
- ISCSI_TASK_COMPLETED,
- ISCSI_TASK_PENDING,
- ISCSI_TASK_RUNNING,
- ISCSI_TASK_ABRT_TMF, /* aborted due to TMF */
- ISCSI_TASK_ABRT_SESS_RECOV, /* aborted due to session recovery */
-};
-
-struct iscsi_r2t_info {
- __be32 ttt; /* copied from R2T */
- __be32 exp_statsn; /* copied from R2T */
- uint32_t data_length; /* copied from R2T */
- uint32_t data_offset; /* copied from R2T */
- int data_count; /* DATA-Out payload progress */
- int datasn;
- /* LLDs should set/update these values */
- int sent; /* R2T sequence progress */
-};
-
-struct iscsi_task {
- /*
- * Because LLDs allocate their hdr differently, this is a pointer
- * and length to that storage. It must be setup at session
- * creation time.
- */
- struct iscsi_hdr *hdr;
- unsigned short hdr_max;
- unsigned short hdr_len; /* accumulated size of hdr used */
- /* copied values in case we need to send tmfs */
- itt_t hdr_itt;
- __be32 cmdsn;
- uint8_t lun[8];
-
- int itt; /* this ITT */
-
- unsigned imm_count; /* imm-data (bytes) */
- /* offset in unsolicited stream (bytes); */
- struct iscsi_r2t_info unsol_r2t;
- char *data; /* mgmt payload */
- unsigned data_count;
- struct scsi_cmnd *sc; /* associated SCSI cmd*/
- struct iscsi_conn *conn; /* used connection */
-
- /* data processing tracking */
- unsigned long last_xfer;
- unsigned long last_timeout;
- int have_checked_conn;
- /* state set/tested under session->lock */
- int state;
- atomic_t refcount;
- struct list_head running; /* running cmd list */
- void *dd_data; /* driver/transport data */
-};
-
-static inline int iscsi_task_has_unsol_data(struct iscsi_task *task)
-{
- return task->unsol_r2t.data_length > task->unsol_r2t.sent;
-}
-
-static inline void* iscsi_next_hdr(struct iscsi_task *task)
-{
- return (void*)task->hdr + task->hdr_len;
-}
-
-/* Connection's states */
-enum {
- ISCSI_CONN_INITIAL_STAGE,
- ISCSI_CONN_STARTED,
- ISCSI_CONN_STOPPED,
- ISCSI_CONN_CLEANUP_WAIT,
-};
-
-struct iscsi_conn {
- struct iscsi_cls_conn *cls_conn; /* ptr to class connection */
- void *dd_data; /* iscsi_transport data */
- struct iscsi_session *session; /* parent session */
- /*
- * conn_stop() flag: stop to recover, stop to terminate
- */
- int stop_stage;
- struct timer_list transport_timer;
- unsigned long last_recv;
- unsigned long last_ping;
- int ping_timeout;
- int recv_timeout;
- struct iscsi_task *ping_task;
-
- /* iSCSI connection-wide sequencing */
- uint32_t exp_statsn;
-
- /* control data */
- int id; /* CID */
- int c_stage; /* connection state */
- /*
- * Preallocated buffer for pdus that have data but do not
- * originate from scsi-ml. We never have two pdus using the
- * buffer at the same time. It is only allocated to
- * the default max recv size because the pdus we support
- * should always fit in this buffer
- */
- char *data;
- struct iscsi_task *login_task; /* mtask used for login/text */
- struct iscsi_task *task; /* xmit task in progress */
-
- /* xmit */
- struct list_head mgmtqueue; /* mgmt (control) xmit queue */
- struct list_head cmdqueue; /* data-path cmd queue */
- struct list_head requeue; /* tasks needing another run */
- struct work_struct xmitwork; /* per-conn. xmit workqueue */
- unsigned long suspend_tx; /* suspend Tx */
- unsigned long suspend_rx; /* suspend Rx */
-
- /* abort */
- wait_queue_head_t ehwait; /* used in eh_abort() */
- struct iscsi_tm tmhdr;
- struct timer_list tmf_timer;
- int tmf_state; /* see TMF_INITIAL, etc.*/
-
- /* negotiated params */
- unsigned max_recv_dlength; /* initiator_max_recv_dsl*/
- unsigned max_xmit_dlength; /* target_max_recv_dsl */
- int hdrdgst_en;
- int datadgst_en;
- int ifmarker_en;
- int ofmarker_en;
- /* values userspace uses to id a conn */
- int persistent_port;
- char *persistent_address;
- /* remote portal currently connected to */
- int portal_port;
- char portal_address[ISCSI_ADDRESS_BUF_LEN];
-
- /* MIB-statistics */
- uint64_t txdata_octets;
- uint64_t rxdata_octets;
- uint32_t scsicmd_pdus_cnt;
- uint32_t dataout_pdus_cnt;
- uint32_t scsirsp_pdus_cnt;
- uint32_t datain_pdus_cnt;
- uint32_t r2t_pdus_cnt;
- uint32_t tmfcmd_pdus_cnt;
- int32_t tmfrsp_pdus_cnt;
-
- /* custom statistics */
- uint32_t eh_abort_cnt;
- uint32_t fmr_unalign_cnt;
-};
-
-struct iscsi_pool {
- struct kfifo queue; /* FIFO Queue */
- void **pool; /* Pool of elements */
- int max; /* Max number of elements */
-};
-
-/* Session's states */
-enum {
- ISCSI_STATE_FREE = 1,
- ISCSI_STATE_LOGGED_IN,
- ISCSI_STATE_FAILED,
- ISCSI_STATE_TERMINATE,
- ISCSI_STATE_IN_RECOVERY,
- ISCSI_STATE_RECOVERY_FAILED,
- ISCSI_STATE_LOGGING_OUT,
-};
-
-struct iscsi_session {
- struct iscsi_cls_session *cls_session;
- /*
- * Syncs up the scsi eh thread with the iscsi eh thread when sending
- * task management functions. This must be taken before the session
- * and recv lock.
- */
- struct mutex eh_mutex;
-
- /* iSCSI session-wide sequencing */
- uint32_t cmdsn;
- uint32_t exp_cmdsn;
- uint32_t max_cmdsn;
-
- /* This tracks the reqs queued into the initiator */
- uint32_t queued_cmdsn;
-
- /* configuration */
- int abort_timeout;
- int lu_reset_timeout;
- int tgt_reset_timeout;
- int initial_r2t_en;
- unsigned max_r2t;
- int imm_data_en;
- unsigned first_burst;
- unsigned max_burst;
- int time2wait;
- int time2retain;
- int pdu_inorder_en;
- int dataseq_inorder_en;
- int erl;
- int fast_abort;
- int tpgt;
- char *username;
- char *username_in;
- char *password;
- char *password_in;
- char *targetname;
- char *ifacename;
- char *initiatorname;
- /* control data */
- struct iscsi_transport *tt;
- struct Scsi_Host *host;
- struct iscsi_conn *leadconn; /* leading connection */
- spinlock_t lock; /* protects session state, *
- * sequence numbers, *
- * session resources: *
- * - cmdpool, *
- * - mgmtpool, *
- * - r2tpool */
- int state; /* session state */
- int age; /* counts session re-opens */
-
- int scsi_cmds_max; /* max scsi commands */
- int cmds_max; /* size of cmds array */
- struct iscsi_task **cmds; /* Original Cmds arr */
- struct iscsi_pool cmdpool; /* PDU's pool */
- void *dd_data; /* LLD private data */
-};
-
-enum {
- ISCSI_HOST_SETUP,
- ISCSI_HOST_REMOVED,
-};
-
-struct iscsi_host {
- char *initiatorname;
- /* hw address or netdev iscsi connection is bound to */
- char *hwaddress;
- char *netdev;
- /* local address */
- int local_port;
- char local_address[ISCSI_ADDRESS_BUF_LEN];
-
- wait_queue_head_t session_removal_wq;
- /* protects sessions and state */
- spinlock_t lock;
- int num_sessions;
- int state;
-
- struct workqueue_struct *workq;
- char workq_name[20];
-};
-
-/*
- * scsi host template
- */
-extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth,
- int reason);
-extern int iscsi_eh_abort(struct scsi_cmnd *sc);
-extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
-extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
-extern int iscsi_eh_device_reset(struct scsi_cmnd *sc);
-extern int iscsi_queuecommand(struct scsi_cmnd *sc,
- void (*done)(struct scsi_cmnd *));
-
-/*
- * iSCSI host helpers.
- */
-#define iscsi_host_priv(_shost) \
- (shost_priv(_shost) + sizeof(struct iscsi_host))
-
-extern int iscsi_host_set_param(struct Scsi_Host *shost,
- enum iscsi_host_param param, char *buf,
- int buflen);
-extern int iscsi_host_get_param(struct Scsi_Host *shost,
- enum iscsi_host_param param, char *buf);
-extern int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev);
-extern struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
- int dd_data_size,
- bool xmit_can_sleep);
-extern void iscsi_host_remove(struct Scsi_Host *shost);
-extern void iscsi_host_free(struct Scsi_Host *shost);
-extern int iscsi_target_alloc(struct scsi_target *starget);
-
-/*
- * session management
- */
-extern struct iscsi_cls_session *
-iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost,
- uint16_t, int, int, uint32_t, unsigned int);
-extern void iscsi_session_teardown(struct iscsi_cls_session *);
-extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
-extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf, int buflen);
-extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
- enum iscsi_param param, char *buf);
-
-#define iscsi_session_printk(prefix, _sess, fmt, a...) \
- iscsi_cls_session_printk(prefix, _sess->cls_session, fmt, ##a)
-
-/*
- * connection management
- */
-extern struct iscsi_cls_conn *iscsi_conn_setup(struct iscsi_cls_session *,
- int, uint32_t);
-extern void iscsi_conn_teardown(struct iscsi_cls_conn *);
-extern int iscsi_conn_start(struct iscsi_cls_conn *);
-extern void iscsi_conn_stop(struct iscsi_cls_conn *, int);
-extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *,
- int);
-extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err);
-extern void iscsi_session_failure(struct iscsi_session *session,
- enum iscsi_err err);
-extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf);
-extern void iscsi_suspend_tx(struct iscsi_conn *conn);
-extern void iscsi_suspend_queue(struct iscsi_conn *conn);
-extern void iscsi_conn_queue_work(struct iscsi_conn *conn);
-
-#define iscsi_conn_printk(prefix, _c, fmt, a...) \
- iscsi_cls_conn_printk(prefix, ((struct iscsi_conn *)_c)->cls_conn, \
- fmt, ##a)
-
-/*
- * pdu and task processing
- */
-extern void iscsi_update_cmdsn(struct iscsi_session *, struct iscsi_nopin *);
-extern void iscsi_prep_data_out_pdu(struct iscsi_task *task,
- struct iscsi_r2t_info *r2t,
- struct iscsi_data *hdr);
-extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *,
- char *, uint32_t);
-extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
- char *, int);
-extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
- char *, int);
-extern int iscsi_verify_itt(struct iscsi_conn *, itt_t);
-extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t);
-extern struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *, itt_t);
-extern void iscsi_requeue_task(struct iscsi_task *task);
-extern void iscsi_put_task(struct iscsi_task *task);
-extern void __iscsi_get_task(struct iscsi_task *task);
-extern void iscsi_complete_scsi_task(struct iscsi_task *task,
- uint32_t exp_cmdsn, uint32_t max_cmdsn);
-
-/*
- * generic helpers
- */
-extern void iscsi_pool_free(struct iscsi_pool *);
-extern int iscsi_pool_init(struct iscsi_pool *, int, void ***, int);
-
-/*
- * inline functions to deal with padding.
- */
-static inline unsigned int
-iscsi_padded(unsigned int len)
-{
- return (len + ISCSI_PAD_LEN - 1) & ~(ISCSI_PAD_LEN - 1);
-}
-
-static inline unsigned int
-iscsi_padding(unsigned int len)
-{
- len &= (ISCSI_PAD_LEN - 1);
- if (len)
- len = ISCSI_PAD_LEN - len;
- return len;
-}
-
-#endif
diff --git a/kernel/libiscsi_tcp.c b/kernel/libiscsi_tcp.c
deleted file mode 100644
index 1122de4..0000000
--- a/kernel/libiscsi_tcp.c
+++ /dev/null
@@ -1,1184 +0,0 @@
-/*
- * iSCSI over TCP/IP Data-Path lib
- *
- * Copyright (C) 2004 Dmitry Yusupov
- * Copyright (C) 2004 Alex Aizman
- * Copyright (C) 2005 - 2006 Mike Christie
- * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
- * maintained by open-iscsi@googlegroups.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * See the file COPYING included with this distribution for more details.
- *
- * Credits:
- * Christoph Hellwig
- * FUJITA Tomonori
- * Arne Redlich
- * Zhenyu Wang
- */
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/inet.h>
-#include <linux/slab.h>
-#include <linux/file.h>
-#include <linux/blkdev.h>
-#include <linux/crypto.h>
-#include <linux/delay.h>
-#include <linux/kfifo.h>
-#include <linux/scatterlist.h>
-#include <net/tcp.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi.h>
-#include "scsi_transport_iscsi.h"
-
-#include "iscsi_tcp.h"
-
-MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
- "Dmitry Yusupov <dmitry_yus@yahoo.com>, "
- "Alex Aizman <itn780@yahoo.com>");
-MODULE_DESCRIPTION("iSCSI/TCP data-path");
-MODULE_LICENSE("GPL");
-
-static int iscsi_dbg_libtcp;
-module_param_named(debug_libiscsi_tcp, iscsi_dbg_libtcp, int,
- S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug_libiscsi_tcp, "Turn on debugging for libiscsi_tcp "
- "module. Set to 1 to turn on, and zero to turn off. Default "
- "is off.");
-
-#define ISCSI_DBG_TCP(_conn, dbg_fmt, arg...) \
- do { \
- if (iscsi_dbg_libtcp) \
- iscsi_conn_printk(KERN_INFO, _conn, \
- "%s " dbg_fmt, \
- __func__, ##arg); \
- } while (0);
-
-static int iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
- struct iscsi_segment *segment);
-
-/*
- * Scatterlist handling: inside the iscsi_segment, we
- * remember an index into the scatterlist, and set data/size
- * to the current scatterlist entry. For highmem pages, we
- * kmap as needed.
- *
- * Note that the page is unmapped when we return from
- * TCP's data_ready handler, so we may end up mapping and
- * unmapping the same page repeatedly. The whole reason
- * for this is that we shouldn't keep the page mapped
- * outside the softirq.
- */
-
-/**
- * iscsi_tcp_segment_init_sg - init indicated scatterlist entry
- * @segment: the buffer object
- * @sg: scatterlist
- * @offset: byte offset into that sg entry
- *
- * This function sets up the segment so that subsequent
- * data is copied to the indicated sg entry, at the given
- * offset.
- */
-static inline void
-iscsi_tcp_segment_init_sg(struct iscsi_segment *segment,
- struct scatterlist *sg, unsigned int offset)
-{
- segment->sg = sg;
- segment->sg_offset = offset;
- segment->size = min(sg->length - offset,
- segment->total_size - segment->total_copied);
- segment->data = NULL;
-}
-
-/**
- * iscsi_tcp_segment_map - map the current S/G page
- * @segment: iscsi_segment
- * @recv: 1 if called from recv path
- *
- * We only need to possibly kmap data if scatter lists are being used,
- * because the iscsi passthrough and internal IO paths will never use high
- * mem pages.
- */
-static void iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv)
-{
- struct scatterlist *sg;
-
- if (segment->data != NULL || !segment->sg)
- return;
-
- sg = segment->sg;
- BUG_ON(segment->sg_mapped);
- BUG_ON(sg->length == 0);
-
- /*
- * If the page count is greater than one it is ok to send
- * to the network layer's zero copy send path. If not we
- * have to go the slow sendmsg path. We always map for the
- * recv path.
- */
- if (page_count(sg_page(sg)) >= 1 && !recv)
- return;
-
- segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0);
- segment->data = segment->sg_mapped + sg->offset + segment->sg_offset;
-}
-
-void iscsi_tcp_segment_unmap(struct iscsi_segment *segment)
-{
- if (segment->sg_mapped) {
- kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0);
- segment->sg_mapped = NULL;
- segment->data = NULL;
- }
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_segment_unmap);
-
-/*
- * Splice the digest buffer into the buffer
- */
-static inline void
-iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest)
-{
- segment->data = digest;
- segment->digest_len = ISCSI_DIGEST_SIZE;
- segment->total_size += ISCSI_DIGEST_SIZE;
- segment->size = ISCSI_DIGEST_SIZE;
- segment->copied = 0;
- segment->sg = NULL;
- segment->hash = NULL;
-}
-
-/**
- * iscsi_tcp_segment_done - check whether the segment is complete
- * @tcp_conn: iscsi tcp connection
- * @segment: iscsi segment to check
- * @recv: set to one of this is called from the recv path
- * @copied: number of bytes copied
- *
- * Check if we're done receiving this segment. If the receive
- * buffer is full but we expect more data, move on to the
- * next entry in the scatterlist.
- *
- * If the amount of data we received isn't a multiple of 4,
- * we will transparently receive the pad bytes, too.
- *
- * This function must be re-entrant.
- */
-int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
- struct iscsi_segment *segment, int recv,
- unsigned copied)
-{
- struct scatterlist sg;
- unsigned int pad;
-
- ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copied %u %u size %u %s\n",
- segment->copied, copied, segment->size,
- recv ? "recv" : "xmit");
- if (segment->hash && copied) {
- /*
- * If a segment is kmapd we must unmap it before sending
- * to the crypto layer since that will try to kmap it again.
- */
- iscsi_tcp_segment_unmap(segment);
-
- if (!segment->data) {
- sg_init_table(&sg, 1);
- sg_set_page(&sg, sg_page(segment->sg), copied,
- segment->copied + segment->sg_offset +
- segment->sg->offset);
- } else
- sg_init_one(&sg, segment->data + segment->copied,
- copied);
- crypto_hash_update(segment->hash, &sg, copied);
- }
-
- segment->copied += copied;
- if (segment->copied < segment->size) {
- iscsi_tcp_segment_map(segment, recv);
- return 0;
- }
-
- segment->total_copied += segment->copied;
- segment->copied = 0;
- segment->size = 0;
-
- /* Unmap the current scatterlist page, if there is one. */
- iscsi_tcp_segment_unmap(segment);
-
- /* Do we have more scatterlist entries? */
- ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "total copied %u total size %u\n",
- segment->total_copied, segment->total_size);
- if (segment->total_copied < segment->total_size) {
- /* Proceed to the next entry in the scatterlist. */
- iscsi_tcp_segment_init_sg(segment, sg_next(segment->sg),
- 0);
- iscsi_tcp_segment_map(segment, recv);
- BUG_ON(segment->size == 0);
- return 0;
- }
-
- /* Do we need to handle padding? */
- if (!(tcp_conn->iscsi_conn->session->tt->caps & CAP_PADDING_OFFLOAD)) {
- pad = iscsi_padding(segment->total_copied);
- if (pad != 0) {
- ISCSI_DBG_TCP(tcp_conn->iscsi_conn,
- "consume %d pad bytes\n", pad);
- segment->total_size += pad;
- segment->size = pad;
- segment->data = segment->padbuf;
- return 0;
- }
- }
-
- /*
- * Set us up for transferring the data digest. hdr digest
- * is completely handled in hdr done function.
- */
- if (segment->hash) {
- crypto_hash_final(segment->hash, segment->digest);
- iscsi_tcp_segment_splice_digest(segment,
- recv ? segment->recv_digest : segment->digest);
- return 0;
- }
-
- return 1;
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_segment_done);
-
-/**
- * iscsi_tcp_segment_recv - copy data to segment
- * @tcp_conn: the iSCSI TCP connection
- * @segment: the buffer to copy to
- * @ptr: data pointer
- * @len: amount of data available
- *
- * This function copies up to @len bytes to the
- * given buffer, and returns the number of bytes
- * consumed, which can actually be less than @len.
- *
- * If hash digest is enabled, the function will update the
- * hash while copying.
- * Combining these two operations doesn't buy us a lot (yet),
- * but in the future we could implement combined copy+crc,
- * just way we do for network layer checksums.
- */
-static int
-iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn,
- struct iscsi_segment *segment, const void *ptr,
- unsigned int len)
-{
- unsigned int copy = 0, copied = 0;
-
- while (!iscsi_tcp_segment_done(tcp_conn, segment, 1, copy)) {
- if (copied == len) {
- ISCSI_DBG_TCP(tcp_conn->iscsi_conn,
- "copied %d bytes\n", len);
- break;
- }
-
- copy = min(len - copied, segment->size - segment->copied);
- ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copying %d\n", copy);
- memcpy(segment->data + segment->copied, ptr + copied, copy);
- copied += copy;
- }
- return copied;
-}
-
-inline void
-iscsi_tcp_dgst_header(struct hash_desc *hash, const void *hdr, size_t hdrlen,
- unsigned char digest[ISCSI_DIGEST_SIZE])
-{
- struct scatterlist sg;
-
- sg_init_one(&sg, hdr, hdrlen);
- crypto_hash_digest(hash, &sg, hdrlen, digest);
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_dgst_header);
-
-static inline int
-iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn,
- struct iscsi_segment *segment)
-{
- if (!segment->digest_len)
- return 1;
-
- if (memcmp(segment->recv_digest, segment->digest,
- segment->digest_len)) {
- ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "digest mismatch\n");
- return 0;
- }
-
- return 1;
-}
-
-/*
- * Helper function to set up segment buffer
- */
-static inline void
-__iscsi_segment_init(struct iscsi_segment *segment, size_t size,
- iscsi_segment_done_fn_t *done, struct hash_desc *hash)
-{
- memset(segment, 0, sizeof(*segment));
- segment->total_size = size;
- segment->done = done;
-
- if (hash) {
- segment->hash = hash;
- crypto_hash_init(hash);
- }
-}
-
-inline void
-iscsi_segment_init_linear(struct iscsi_segment *segment, void *data,
- size_t size, iscsi_segment_done_fn_t *done,
- struct hash_desc *hash)
-{
- __iscsi_segment_init(segment, size, done, hash);
- segment->data = data;
- segment->size = size;
-}
-EXPORT_SYMBOL_GPL(iscsi_segment_init_linear);
-
-inline int
-iscsi_segment_seek_sg(struct iscsi_segment *segment,
- struct scatterlist *sg_list, unsigned int sg_count,
- unsigned int offset, size_t size,
- iscsi_segment_done_fn_t *done, struct hash_desc *hash)
-{
- struct scatterlist *sg;
- unsigned int i;
-
- __iscsi_segment_init(segment, size, done, hash);
- for_each_sg(sg_list, sg, sg_count, i) {
- if (offset < sg->length) {
- iscsi_tcp_segment_init_sg(segment, sg, offset);
- return 0;
- }
- offset -= sg->length;
- }
-
- return ISCSI_ERR_DATA_OFFSET;
-}
-EXPORT_SYMBOL_GPL(iscsi_segment_seek_sg);
-
-/**
- * iscsi_tcp_hdr_recv_prep - prep segment for hdr reception
- * @tcp_conn: iscsi connection to prep for
- *
- * This function always passes NULL for the hash argument, because when this
- * function is called we do not yet know the final size of the header and want
- * to delay the digest processing until we know that.
- */
-void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn)
-{
- ISCSI_DBG_TCP(tcp_conn->iscsi_conn,
- "(%s)\n", tcp_conn->iscsi_conn->hdrdgst_en ?
- "digest enabled" : "digest disabled");
- iscsi_segment_init_linear(&tcp_conn->in.segment,
- tcp_conn->in.hdr_buf, sizeof(struct iscsi_hdr),
- iscsi_tcp_hdr_recv_done, NULL);
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_hdr_recv_prep);
-
-/*
- * Handle incoming reply to any other type of command
- */
-static int
-iscsi_tcp_data_recv_done(struct iscsi_tcp_conn *tcp_conn,
- struct iscsi_segment *segment)
-{
- struct iscsi_conn *conn = tcp_conn->iscsi_conn;
- int rc = 0;
-
- if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
- return ISCSI_ERR_DATA_DGST;
-
- rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr,
- conn->data, tcp_conn->in.datalen);
- if (rc)
- return rc;
-
- iscsi_tcp_hdr_recv_prep(tcp_conn);
- return 0;
-}
-
-static void
-iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
-{
- struct iscsi_conn *conn = tcp_conn->iscsi_conn;
- struct hash_desc *rx_hash = NULL;
-
- if (conn->datadgst_en &&
- !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
- rx_hash = tcp_conn->rx_hash;
-
- iscsi_segment_init_linear(&tcp_conn->in.segment,
- conn->data, tcp_conn->in.datalen,
- iscsi_tcp_data_recv_done, rx_hash);
-}
-
-/**
- * iscsi_tcp_cleanup_task - free tcp_task resources
- * @task: iscsi task
- *
- * must be called with session lock
- */
-void iscsi_tcp_cleanup_task(struct iscsi_task *task)
-{
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct iscsi_r2t_info *r2t;
-
- /* nothing to do for mgmt */
- if (!task->sc)
- return;
-
- /* flush task's r2t queues */
- while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- ISCSI_DBG_TCP(task->conn, "pending r2t dropped\n");
- }
-
- r2t = tcp_task->r2t;
- if (r2t != NULL) {
- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- tcp_task->r2t = NULL;
- }
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_cleanup_task);
-
-/**
- * iscsi_tcp_data_in - SCSI Data-In Response processing
- * @conn: iscsi connection
- * @task: scsi command task
- */
-static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
- int datasn = be32_to_cpu(rhdr->datasn);
- unsigned total_in_length = scsi_in(task->sc)->length;
-
- /*
- * lib iscsi will update this in the completion handling if there
- * is status.
- */
- if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
- iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
-
- if (tcp_conn->in.datalen == 0)
- return 0;
-
- if (tcp_task->exp_datasn != datasn) {
- ISCSI_DBG_TCP(conn, "task->exp_datasn(%d) != rhdr->datasn(%d)"
- "\n", tcp_task->exp_datasn, datasn);
- return ISCSI_ERR_DATASN;
- }
-
- tcp_task->exp_datasn++;
-
- tcp_task->data_offset = be32_to_cpu(rhdr->offset);
- if (tcp_task->data_offset + tcp_conn->in.datalen > total_in_length) {
- ISCSI_DBG_TCP(conn, "data_offset(%d) + data_len(%d) > "
- "total_length_in(%d)\n", tcp_task->data_offset,
- tcp_conn->in.datalen, total_in_length);
- return ISCSI_ERR_DATA_OFFSET;
- }
-
- conn->datain_pdus_cnt++;
- return 0;
-}
-
-/**
- * iscsi_tcp_r2t_rsp - iSCSI R2T Response processing
- * @conn: iscsi connection
- * @task: scsi command task
- */
-static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
-{
- struct iscsi_session *session = conn->session;
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr;
- struct iscsi_r2t_info *r2t;
- int r2tsn = be32_to_cpu(rhdr->r2tsn);
- int rc;
-
- if (tcp_conn->in.datalen) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2t with datalen %d\n",
- tcp_conn->in.datalen);
- return ISCSI_ERR_DATALEN;
- }
-
- if (tcp_task->exp_datasn != r2tsn){
- ISCSI_DBG_TCP(conn, "task->exp_datasn(%d) != rhdr->r2tsn(%d)\n",
- tcp_task->exp_datasn, r2tsn);
- return ISCSI_ERR_R2TSN;
- }
-
- /* fill-in new R2T associated with the task */
- iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
-
- if (!task->sc || session->state != ISCSI_STATE_LOGGED_IN) {
- iscsi_conn_printk(KERN_INFO, conn,
- "dropping R2T itt %d in recovery.\n",
- task->itt);
- return 0;
- }
-
- rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
- if (!rc) {
- iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
- "Target has sent more R2Ts than it "
- "negotiated for or driver has has leaked.\n");
- return ISCSI_ERR_PROTO;
- }
-
- r2t->exp_statsn = rhdr->statsn;
- r2t->data_length = be32_to_cpu(rhdr->data_length);
- if (r2t->data_length == 0) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with zero data len\n");
- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
- }
-
- if (r2t->data_length > session->max_burst)
- ISCSI_DBG_TCP(conn, "invalid R2T with data len %u and max "
- "burst %u. Attempting to execute request.\n",
- r2t->data_length, session->max_burst);
-
- r2t->data_offset = be32_to_cpu(rhdr->data_offset);
- if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) {
- iscsi_conn_printk(KERN_ERR, conn,
- "invalid R2T with data len %u at offset %u "
- "and total length %d\n", r2t->data_length,
- r2t->data_offset, scsi_out(task->sc)->length);
- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- return ISCSI_ERR_DATALEN;
- }
-
- r2t->ttt = rhdr->ttt; /* no flip */
- r2t->datasn = 0;
- r2t->sent = 0;
-
- tcp_task->exp_datasn = r2tsn + 1;
- kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
- conn->r2t_pdus_cnt++;
-
- iscsi_requeue_task(task);
- return 0;
-}
-
-/*
- * Handle incoming reply to DataIn command
- */
-static int
-iscsi_tcp_process_data_in(struct iscsi_tcp_conn *tcp_conn,
- struct iscsi_segment *segment)
-{
- struct iscsi_conn *conn = tcp_conn->iscsi_conn;
- struct iscsi_hdr *hdr = tcp_conn->in.hdr;
- int rc;
-
- if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
- return ISCSI_ERR_DATA_DGST;
-
- /* check for non-exceptional status */
- if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
- rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
- if (rc)
- return rc;
- }
-
- iscsi_tcp_hdr_recv_prep(tcp_conn);
- return 0;
-}
-
-/**
- * iscsi_tcp_hdr_dissect - process PDU header
- * @conn: iSCSI connection
- * @hdr: PDU header
- *
- * This function analyzes the header of the PDU received,
- * and performs several sanity checks. If the PDU is accompanied
- * by data, the receive buffer is set up to copy the incoming data
- * to the correct location.
- */
-static int
-iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
-{
- int rc = 0, opcode, ahslen;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_task *task;
-
- /* verify PDU length */
- tcp_conn->in.datalen = ntoh24(hdr->dlength);
- if (tcp_conn->in.datalen > conn->max_recv_dlength) {
- iscsi_conn_printk(KERN_ERR, conn,
- "iscsi_tcp: datalen %d > %d\n",
- tcp_conn->in.datalen, conn->max_recv_dlength);
- return ISCSI_ERR_DATALEN;
- }
-
- /* Additional header segments. So far, we don't
- * process additional headers.
- */
- ahslen = hdr->hlength << 2;
-
- opcode = hdr->opcode & ISCSI_OPCODE_MASK;
- /* verify itt (itt encoding: age+cid+itt) */
- rc = iscsi_verify_itt(conn, hdr->itt);
- if (rc)
- return rc;
-
- ISCSI_DBG_TCP(conn, "opcode 0x%x ahslen %d datalen %d\n",
- opcode, ahslen, tcp_conn->in.datalen);
-
- switch(opcode) {
- case ISCSI_OP_SCSI_DATA_IN:
- spin_lock(&conn->session->lock);
- task = iscsi_itt_to_ctask(conn, hdr->itt);
- if (!task)
- rc = ISCSI_ERR_BAD_ITT;
- else
- rc = iscsi_tcp_data_in(conn, task);
- if (rc) {
- spin_unlock(&conn->session->lock);
- break;
- }
-
- if (tcp_conn->in.datalen) {
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct hash_desc *rx_hash = NULL;
- struct scsi_data_buffer *sdb = scsi_in(task->sc);
-
- /*
- * Setup copy of Data-In into the Scsi_Cmnd
- * Scatterlist case:
- * We set up the iscsi_segment to point to the next
- * scatterlist entry to copy to. As we go along,
- * we move on to the next scatterlist entry and
- * update the digest per-entry.
- */
- if (conn->datadgst_en &&
- !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
- rx_hash = tcp_conn->rx_hash;
-
- ISCSI_DBG_TCP(conn, "iscsi_tcp_begin_data_in( "
- "offset=%d, datalen=%d)\n",
- tcp_task->data_offset,
- tcp_conn->in.datalen);
- task->last_xfer = jiffies;
- rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
- sdb->table.sgl,
- sdb->table.nents,
- tcp_task->data_offset,
- tcp_conn->in.datalen,
- iscsi_tcp_process_data_in,
- rx_hash);
- spin_unlock(&conn->session->lock);
- return rc;
- }
- rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
- spin_unlock(&conn->session->lock);
- break;
- case ISCSI_OP_SCSI_CMD_RSP:
- if (tcp_conn->in.datalen) {
- iscsi_tcp_data_recv_prep(tcp_conn);
- return 0;
- }
- rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
- break;
- case ISCSI_OP_R2T:
- spin_lock(&conn->session->lock);
- task = iscsi_itt_to_ctask(conn, hdr->itt);
- if (!task)
- rc = ISCSI_ERR_BAD_ITT;
- else if (ahslen)
- rc = ISCSI_ERR_AHSLEN;
- else if (task->sc->sc_data_direction == DMA_TO_DEVICE) {
- task->last_xfer = jiffies;
- rc = iscsi_tcp_r2t_rsp(conn, task);
- } else
- rc = ISCSI_ERR_PROTO;
- spin_unlock(&conn->session->lock);
- break;
- case ISCSI_OP_LOGIN_RSP:
- case ISCSI_OP_TEXT_RSP:
- case ISCSI_OP_REJECT:
- case ISCSI_OP_ASYNC_EVENT:
- /*
- * It is possible that we could get a PDU with a buffer larger
- * than 8K, but there are no targets that currently do this.
- * For now we fail until we find a vendor that needs it
- */
- if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) {
- iscsi_conn_printk(KERN_ERR, conn,
- "iscsi_tcp: received buffer of "
- "len %u but conn buffer is only %u "
- "(opcode %0x)\n",
- tcp_conn->in.datalen,
- ISCSI_DEF_MAX_RECV_SEG_LEN, opcode);
- rc = ISCSI_ERR_PROTO;
- break;
- }
-
- /* If there's data coming in with the response,
- * receive it to the connection's buffer.
- */
- if (tcp_conn->in.datalen) {
- iscsi_tcp_data_recv_prep(tcp_conn);
- return 0;
- }
- /* fall through */
- case ISCSI_OP_LOGOUT_RSP:
- case ISCSI_OP_NOOP_IN:
- case ISCSI_OP_SCSI_TMFUNC_RSP:
- rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
- break;
- default:
- rc = ISCSI_ERR_BAD_OPCODE;
- break;
- }
-
- if (rc == 0) {
- /* Anything that comes with data should have
- * been handled above. */
- if (tcp_conn->in.datalen)
- return ISCSI_ERR_PROTO;
- iscsi_tcp_hdr_recv_prep(tcp_conn);
- }
-
- return rc;
-}
-
-/**
- * iscsi_tcp_hdr_recv_done - process PDU header
- *
- * This is the callback invoked when the PDU header has
- * been received. If the header is followed by additional
- * header segments, we go back for more data.
- */
-static int
-iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
- struct iscsi_segment *segment)
-{
- struct iscsi_conn *conn = tcp_conn->iscsi_conn;
- struct iscsi_hdr *hdr;
-
- /* Check if there are additional header segments
- * *prior* to computing the digest, because we
- * may need to go back to the caller for more.
- */
- hdr = (struct iscsi_hdr *) tcp_conn->in.hdr_buf;
- if (segment->copied == sizeof(struct iscsi_hdr) && hdr->hlength) {
- /* Bump the header length - the caller will
- * just loop around and get the AHS for us, and
- * call again. */
- unsigned int ahslen = hdr->hlength << 2;
-
- /* Make sure we don't overflow */
- if (sizeof(*hdr) + ahslen > sizeof(tcp_conn->in.hdr_buf))
- return ISCSI_ERR_AHSLEN;
-
- segment->total_size += ahslen;
- segment->size += ahslen;
- return 0;
- }
-
- /* We're done processing the header. See if we're doing
- * header digests; if so, set up the recv_digest buffer
- * and go back for more. */
- if (conn->hdrdgst_en &&
- !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) {
- if (segment->digest_len == 0) {
- /*
- * Even if we offload the digest processing we
- * splice it in so we can increment the skb/segment
- * counters in preparation for the data segment.
- */
- iscsi_tcp_segment_splice_digest(segment,
- segment->recv_digest);
- return 0;
- }
-
- iscsi_tcp_dgst_header(tcp_conn->rx_hash, hdr,
- segment->total_copied - ISCSI_DIGEST_SIZE,
- segment->digest);
-
- if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
- return ISCSI_ERR_HDR_DGST;
- }
-
- tcp_conn->in.hdr = hdr;
- return iscsi_tcp_hdr_dissect(conn, hdr);
-}
-
-/**
- * iscsi_tcp_recv_segment_is_hdr - tests if we are reading in a header
- * @tcp_conn: iscsi tcp conn
- *
- * returns non zero if we are currently processing or setup to process
- * a header.
- */
-inline int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn)
-{
- return tcp_conn->in.segment.done == iscsi_tcp_hdr_recv_done;
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_recv_segment_is_hdr);
-
-/**
- * iscsi_tcp_recv_skb - Process skb
- * @conn: iscsi connection
- * @skb: network buffer with header and/or data segment
- * @offset: offset in skb
- * @offload: bool indicating if transfer was offloaded
- *
- * Will return status of transfer in status. And will return
- * number of bytes copied.
- */
-int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
- unsigned int offset, bool offloaded, int *status)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_segment *segment = &tcp_conn->in.segment;
- struct skb_seq_state seq;
- unsigned int consumed = 0;
- int rc = 0;
-
- ISCSI_DBG_TCP(conn, "in %d bytes\n", skb->len - offset);
- /*
- * Update for each skb instead of pdu, because over slow networks a
- * data_in's data could take a while to read in. We also want to
- * account for r2ts.
- */
- conn->last_recv = jiffies;
-
- if (unlikely(conn->suspend_rx)) {
- ISCSI_DBG_TCP(conn, "Rx suspended!\n");
- *status = ISCSI_TCP_SUSPENDED;
- return 0;
- }
-
- if (offloaded) {
- segment->total_copied = segment->total_size;
- goto segment_done;
- }
-
- skb_prepare_seq_read(skb, offset, skb->len, &seq);
- while (1) {
- unsigned int avail;
- const u8 *ptr;
-
- avail = skb_seq_read(consumed, &ptr, &seq);
- if (avail == 0) {
- ISCSI_DBG_TCP(conn, "no more data avail. Consumed %d\n",
- consumed);
- *status = ISCSI_TCP_SKB_DONE;
- skb_abort_seq_read(&seq);
- goto skb_done;
- }
- BUG_ON(segment->copied >= segment->size);
-
- ISCSI_DBG_TCP(conn, "skb %p ptr=%p avail=%u\n", skb, ptr,
- avail);
- rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail);
- BUG_ON(rc == 0);
- consumed += rc;
-
- if (segment->total_copied >= segment->total_size) {
- skb_abort_seq_read(&seq);
- goto segment_done;
- }
- }
-
-segment_done:
- *status = ISCSI_TCP_SEGMENT_DONE;
- ISCSI_DBG_TCP(conn, "segment done\n");
- rc = segment->done(tcp_conn, segment);
- if (rc != 0) {
- *status = ISCSI_TCP_CONN_ERR;
- ISCSI_DBG_TCP(conn, "Error receiving PDU, errno=%d\n", rc);
- iscsi_conn_failure(conn, rc);
- return 0;
- }
- /* The done() functions sets up the next segment. */
-
-skb_done:
- conn->rxdata_octets += consumed;
- return consumed;
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_recv_skb);
-
-/**
- * iscsi_tcp_task_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
- * @conn: iscsi connection
- * @task: scsi command task
- * @sc: scsi command
- */
-int iscsi_tcp_task_init(struct iscsi_task *task)
-{
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct iscsi_conn *conn = task->conn;
- struct scsi_cmnd *sc = task->sc;
- int err;
-
- if (!sc) {
- /*
- * mgmt tasks do not have a scatterlist since they come
- * in from the iscsi interface.
- */
- ISCSI_DBG_TCP(conn, "mtask deq [itt 0x%x]\n", task->itt);
-
- return conn->session->tt->init_pdu(task, 0, task->data_count);
- }
-
- BUG_ON(kfifo_len(&tcp_task->r2tqueue));
- tcp_task->exp_datasn = 0;
-
- /* Prepare PDU, optionally w/ immediate data */
- ISCSI_DBG_TCP(conn, "task deq [itt 0x%x imm %d unsol %d]\n",
- task->itt, task->imm_count, task->unsol_r2t.data_length);
-
- err = conn->session->tt->init_pdu(task, 0, task->imm_count);
- if (err)
- return err;
- task->imm_count = 0;
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_task_init);
-
-static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
-{
- struct iscsi_session *session = task->conn->session;
- struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct iscsi_r2t_info *r2t = NULL;
-
- if (iscsi_task_has_unsol_data(task))
- r2t = &task->unsol_r2t;
- else {
- spin_lock_bh(&session->lock);
- if (tcp_task->r2t) {
- r2t = tcp_task->r2t;
- /* Continue with this R2T? */
- if (r2t->data_length <= r2t->sent) {
- ISCSI_DBG_TCP(task->conn,
- " done with r2t %p\n", r2t);
- kfifo_in(&tcp_task->r2tpool.queue,
- (void *)&tcp_task->r2t,
- sizeof(void *));
- tcp_task->r2t = r2t = NULL;
- }
- }
-
- if (r2t == NULL) {
- if (kfifo_out(&tcp_task->r2tqueue,
- (void *)&tcp_task->r2t, sizeof(void *)) !=
- sizeof(void *))
- r2t = NULL;
- else
- r2t = tcp_task->r2t;
- }
- spin_unlock_bh(&session->lock);
- }
-
- return r2t;
-}
-
-/**
- * iscsi_tcp_task_xmit - xmit normal PDU task
- * @task: iscsi command task
- *
- * We're expected to return 0 when everything was transmitted successfully,
- * -EAGAIN if there's still data in the queue, or != 0 for any other kind
- * of error.
- */
-int iscsi_tcp_task_xmit(struct iscsi_task *task)
-{
- struct iscsi_conn *conn = task->conn;
- struct iscsi_session *session = conn->session;
- struct iscsi_r2t_info *r2t;
- int rc = 0;
-
-flush:
- /* Flush any pending data first. */
- rc = session->tt->xmit_pdu(task);
- if (rc < 0)
- return rc;
-
- /* mgmt command */
- if (!task->sc) {
- if (task->hdr->itt == RESERVED_ITT)
- iscsi_put_task(task);
- return 0;
- }
-
- /* Are we done already? */
- if (task->sc->sc_data_direction != DMA_TO_DEVICE)
- return 0;
-
- r2t = iscsi_tcp_get_curr_r2t(task);
- if (r2t == NULL) {
- /* Waiting for more R2Ts to arrive. */
- ISCSI_DBG_TCP(conn, "no R2Ts yet\n");
- return 0;
- }
-
- rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_DATA_OUT);
- if (rc)
- return rc;
- iscsi_prep_data_out_pdu(task, r2t, (struct iscsi_data *) task->hdr);
-
- ISCSI_DBG_TCP(conn, "sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n",
- r2t, r2t->datasn - 1, task->hdr->itt,
- r2t->data_offset + r2t->sent, r2t->data_count);
-
- rc = conn->session->tt->init_pdu(task, r2t->data_offset + r2t->sent,
- r2t->data_count);
- if (rc) {
- iscsi_conn_failure(conn, ISCSI_ERR_XMIT_FAILED);
- return rc;
- }
-
- r2t->sent += r2t->data_count;
- goto flush;
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_task_xmit);
-
-struct iscsi_cls_conn *
-iscsi_tcp_conn_setup(struct iscsi_cls_session *cls_session, int dd_data_size,
- uint32_t conn_idx)
-
-{
- struct iscsi_conn *conn;
- struct iscsi_cls_conn *cls_conn;
- struct iscsi_tcp_conn *tcp_conn;
-
- cls_conn = iscsi_conn_setup(cls_session, sizeof(*tcp_conn), conn_idx);
- if (!cls_conn)
- return NULL;
- conn = cls_conn->dd_data;
- /*
- * due to strange issues with iser these are not set
- * in iscsi_conn_setup
- */
- conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
-
- tcp_conn = conn->dd_data;
- tcp_conn->iscsi_conn = conn;
-
- tcp_conn->dd_data = kzalloc(dd_data_size, GFP_KERNEL);
- if (!tcp_conn->dd_data) {
- iscsi_conn_teardown(cls_conn);
- return NULL;
- }
- return cls_conn;
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_conn_setup);
-
-void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-
- kfree(tcp_conn->dd_data);
- iscsi_conn_teardown(cls_conn);
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_conn_teardown);
-
-int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
-{
- int i;
- int cmd_i;
-
- /*
- * initialize per-task: R2T pool and xmit queue
- */
- for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
- struct iscsi_task *task = session->cmds[cmd_i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
- /*
- * pre-allocated x2 as much r2ts to handle race when
- * target acks DataOut faster than we data_xmit() queues
- * could replenish r2tqueue.
- */
-
- /* R2T pool */
- if (iscsi_pool_init(&tcp_task->r2tpool,
- session->max_r2t * 2, NULL,
- sizeof(struct iscsi_r2t_info))) {
- goto r2t_alloc_fail;
- }
-
- /* R2T xmit queue */
- if (kfifo_alloc(&tcp_task->r2tqueue,
- session->max_r2t * 4 * sizeof(void*), GFP_KERNEL)) {
- iscsi_pool_free(&tcp_task->r2tpool);
- goto r2t_alloc_fail;
- }
- }
-
- return 0;
-
-r2t_alloc_fail:
- for (i = 0; i < cmd_i; i++) {
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
- kfifo_free(&tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
- return -ENOMEM;
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_alloc);
-
-void iscsi_tcp_r2tpool_free(struct iscsi_session *session)
-{
- int i;
-
- for (i = 0; i < session->cmds_max; i++) {
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
- kfifo_free(&tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_free);
-
-void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
- struct iscsi_stats *stats)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
-
- stats->txdata_octets = conn->txdata_octets;
- stats->rxdata_octets = conn->rxdata_octets;
- stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
- stats->dataout_pdus = conn->dataout_pdus_cnt;
- stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
- stats->datain_pdus = conn->datain_pdus_cnt;
- stats->r2t_pdus = conn->r2t_pdus_cnt;
- stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
- stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_conn_get_stats);
diff --git a/kernel/libiscsi_tcp.h b/kernel/libiscsi_tcp.h
deleted file mode 100644
index dd5e61f..0000000
--- a/kernel/libiscsi_tcp.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * iSCSI over TCP/IP Data-Path lib
- *
- * Copyright (C) 2008 Mike Christie
- * Copyright (C) 2008 Red Hat, Inc. All rights reserved.
- * maintained by open-iscsi@googlegroups.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * See the file COPYING included with this distribution for more details.
- */
-
-#ifndef LIBISCSI_TCP_H
-#define LIBISCSI_TCP_H
-
-#include "libiscsi.h"
-
-struct iscsi_tcp_conn;
-struct iscsi_segment;
-struct sk_buff;
-struct hash_desc;
-
-typedef int iscsi_segment_done_fn_t(struct iscsi_tcp_conn *,
- struct iscsi_segment *);
-
-struct iscsi_segment {
- unsigned char *data;
- unsigned int size;
- unsigned int copied;
- unsigned int total_size;
- unsigned int total_copied;
-
- struct hash_desc *hash;
- unsigned char padbuf[ISCSI_PAD_LEN];
- unsigned char recv_digest[ISCSI_DIGEST_SIZE];
- unsigned char digest[ISCSI_DIGEST_SIZE];
- unsigned int digest_len;
-
- struct scatterlist *sg;
- void *sg_mapped;
- unsigned int sg_offset;
-
- iscsi_segment_done_fn_t *done;
-};
-
-/* Socket connection receive helper */
-struct iscsi_tcp_recv {
- struct iscsi_hdr *hdr;
- struct iscsi_segment segment;
-
- /* Allocate buffer for BHS + AHS */
- uint32_t hdr_buf[64];
-
- /* copied and flipped values */
- int datalen;
-};
-
-struct iscsi_tcp_conn {
- struct iscsi_conn *iscsi_conn;
- void *dd_data;
- int stop_stage; /* conn_stop() flag: *
- * stop to recover, *
- * stop to terminate */
- /* control data */
- struct iscsi_tcp_recv in; /* TCP receive context */
- /* CRC32C (Rx) LLD should set this is they do not offload */
- struct hash_desc *rx_hash;
-};
-
-struct iscsi_tcp_task {
- uint32_t exp_datasn; /* expected target's R2TSN/DataSN */
- int data_offset;
- struct iscsi_r2t_info *r2t; /* in progress solict R2T */
- struct iscsi_pool r2tpool;
- struct kfifo r2tqueue;
- void *dd_data;
-};
-
-enum {
- ISCSI_TCP_SEGMENT_DONE, /* curr seg has been processed */
- ISCSI_TCP_SKB_DONE, /* skb is out of data */
- ISCSI_TCP_CONN_ERR, /* iscsi layer has fired a conn err */
- ISCSI_TCP_SUSPENDED, /* conn is suspended */
-};
-
-extern void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn);
-extern int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
- unsigned int offset, bool offloaded, int *status);
-extern void iscsi_tcp_cleanup_task(struct iscsi_task *task);
-extern int iscsi_tcp_task_init(struct iscsi_task *task);
-extern int iscsi_tcp_task_xmit(struct iscsi_task *task);
-
-/* segment helpers */
-extern int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn);
-extern int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
- struct iscsi_segment *segment, int recv,
- unsigned copied);
-extern void iscsi_tcp_segment_unmap(struct iscsi_segment *segment);
-
-extern void iscsi_segment_init_linear(struct iscsi_segment *segment,
- void *data, size_t size,
- iscsi_segment_done_fn_t *done,
- struct hash_desc *hash);
-extern int
-iscsi_segment_seek_sg(struct iscsi_segment *segment,
- struct scatterlist *sg_list, unsigned int sg_count,
- unsigned int offset, size_t size,
- iscsi_segment_done_fn_t *done, struct hash_desc *hash);
-
-/* digest helpers */
-extern void iscsi_tcp_dgst_header(struct hash_desc *hash, const void *hdr,
- size_t hdrlen,
- unsigned char digest[ISCSI_DIGEST_SIZE]);
-extern struct iscsi_cls_conn *
-iscsi_tcp_conn_setup(struct iscsi_cls_session *cls_session, int dd_data_size,
- uint32_t conn_idx);
-extern void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn);
-
-/* misc helpers */
-extern int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session);
-extern void iscsi_tcp_r2tpool_free(struct iscsi_session *session);
-
-extern void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
- struct iscsi_stats *stats);
-#endif /* LIBISCSI_TCP_H */
diff --git a/kernel/scsi_transport_iscsi.c b/kernel/scsi_transport_iscsi.c
deleted file mode 100644
index fed8c9e..0000000
--- a/kernel/scsi_transport_iscsi.c
+++ /dev/null
@@ -1,2135 +0,0 @@
-/*
- * iSCSI transport class definitions
- *
- * Copyright (C) IBM Corporation, 2004
- * Copyright (C) Mike Christie, 2004 - 2005
- * Copyright (C) Dmitry Yusupov, 2004 - 2005
- * Copyright (C) Alex Aizman, 2004 - 2005
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <net/tcp.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_transport.h>
-#include "scsi_transport_iscsi.h"
-#include "iscsi_if.h"
-
-#define ISCSI_SESSION_ATTRS 22
-#define ISCSI_CONN_ATTRS 13
-#define ISCSI_HOST_ATTRS 4
-
-#define ISCSI_TRANSPORT_VERSION "2.0-871"
-
-static int dbg_session;
-module_param_named(debug_session, dbg_session, int,
- S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug_session,
- "Turn on debugging for sessions in scsi_transport_iscsi "
- "module. Set to 1 to turn on, and zero to turn off. Default "
- "is off.");
-
-static int dbg_conn;
-module_param_named(debug_conn, dbg_conn, int,
- S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug_conn,
- "Turn on debugging for connections in scsi_transport_iscsi "
- "module. Set to 1 to turn on, and zero to turn off. Default "
- "is off.");
-
-#define ISCSI_DBG_TRANS_SESSION(_session, dbg_fmt, arg...) \
- do { \
- if (dbg_session) \
- iscsi_cls_session_printk(KERN_INFO, _session, \
- "%s: " dbg_fmt, \
- __func__, ##arg); \
- } while (0);
-
-#define ISCSI_DBG_TRANS_CONN(_conn, dbg_fmt, arg...) \
- do { \
- if (dbg_conn) \
- iscsi_cls_conn_printk(KERN_INFO, _conn, \
- "%s: " dbg_fmt, \
- __func__, ##arg); \
- } while (0);
-
-struct iscsi_internal {
- struct scsi_transport_template t;
- struct iscsi_transport *iscsi_transport;
- struct list_head list;
- struct device dev;
-
- struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
- struct transport_container conn_cont;
- struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
- struct transport_container session_cont;
- struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
-};
-
-static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
-static struct workqueue_struct *iscsi_eh_timer_workq;
-
-/*
- * list of registered transports and lock that must
- * be held while accessing list. The iscsi_transport_lock must
- * be acquired after the rx_queue_mutex.
- */
-static LIST_HEAD(iscsi_transports);
-static DEFINE_SPINLOCK(iscsi_transport_lock);
-
-#define to_iscsi_internal(tmpl) \
- container_of(tmpl, struct iscsi_internal, t)
-
-#define dev_to_iscsi_internal(_dev) \
- container_of(_dev, struct iscsi_internal, dev)
-
-static void iscsi_transport_release(struct device *dev)
-{
- struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
- kfree(priv);
-}
-
-/*
- * iscsi_transport_class represents the iscsi_transports that are
- * registered.
- */
-static struct class iscsi_transport_class = {
- .name = "iscsi_transport",
- .dev_release = iscsi_transport_release,
-};
-
-static ssize_t
-show_transport_handle(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
- return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
-}
-static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
-
-#define show_transport_attr(name, format) \
-static ssize_t \
-show_transport_##name(struct device *dev, \
- struct device_attribute *attr,char *buf) \
-{ \
- struct iscsi_internal *priv = dev_to_iscsi_internal(dev); \
- return sprintf(buf, format"\n", priv->iscsi_transport->name); \
-} \
-static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
-
-show_transport_attr(caps, "0x%x");
-
-static struct attribute *iscsi_transport_attrs[] = {
- &dev_attr_handle.attr,
- &dev_attr_caps.attr,
- NULL,
-};
-
-static struct attribute_group iscsi_transport_group = {
- .attrs = iscsi_transport_attrs,
-};
-
-/*
- * iSCSI endpoint attrs
- */
-#define iscsi_dev_to_endpoint(_dev) \
- container_of(_dev, struct iscsi_endpoint, dev)
-
-#define ISCSI_ATTR(_prefix,_name,_mode,_show,_store) \
-struct device_attribute dev_attr_##_prefix##_##_name = \
- __ATTR(_name,_mode,_show,_store)
-
-static void iscsi_endpoint_release(struct device *dev)
-{
- struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
- kfree(ep);
-}
-
-static struct class iscsi_endpoint_class = {
- .name = "iscsi_endpoint",
- .dev_release = iscsi_endpoint_release,
-};
-
-static ssize_t
-show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
- return sprintf(buf, "%llu\n", (unsigned long long) ep->id);
-}
-static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL);
-
-static struct attribute *iscsi_endpoint_attrs[] = {
- &dev_attr_ep_handle.attr,
- NULL,
-};
-
-static struct attribute_group iscsi_endpoint_group = {
- .attrs = iscsi_endpoint_attrs,
-};
-
-#define ISCSI_MAX_EPID -1
-
-static int iscsi_match_epid(struct device *dev, void *data)
-{
- struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
- uint64_t *epid = (uint64_t *) data;
-
- return *epid == ep->id;
-}
-
-struct iscsi_endpoint *
-iscsi_create_endpoint(int dd_size)
-{
- struct device *dev;
- struct iscsi_endpoint *ep;
- uint64_t id;
- int err;
-
- for (id = 1; id < ISCSI_MAX_EPID; id++) {
- dev = class_find_device(&iscsi_endpoint_class, NULL, &id,
- iscsi_match_epid);
- if (!dev)
- break;
- }
- if (id == ISCSI_MAX_EPID) {
- printk(KERN_ERR "Too many connections. Max supported %u\n",
- ISCSI_MAX_EPID - 1);
- return NULL;
- }
-
- ep = kzalloc(sizeof(*ep) + dd_size, GFP_KERNEL);
- if (!ep)
- return NULL;
-
- ep->id = id;
- ep->dev.class = &iscsi_endpoint_class;
- dev_set_name(&ep->dev, "ep-%llu", (unsigned long long) id);
- err = device_register(&ep->dev);
- if (err)
- goto free_ep;
-
- err = sysfs_create_group(&ep->dev.kobj, &iscsi_endpoint_group);
- if (err)
- goto unregister_dev;
-
- if (dd_size)
- ep->dd_data = &ep[1];
- return ep;
-
-unregister_dev:
- device_unregister(&ep->dev);
- return NULL;
-
-free_ep:
- kfree(ep);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(iscsi_create_endpoint);
-
-void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
-{
- sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group);
- device_unregister(&ep->dev);
-}
-EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint);
-
-struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
-{
- struct iscsi_endpoint *ep;
- struct device *dev;
-
- dev = class_find_device(&iscsi_endpoint_class, NULL, &handle,
- iscsi_match_epid);
- if (!dev)
- return NULL;
-
- ep = iscsi_dev_to_endpoint(dev);
- /*
- * we can drop this now because the interface will prevent
- * removals and lookups from racing.
- */
- put_device(dev);
- return ep;
-}
-EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
-
-static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
- struct device *cdev)
-{
- struct Scsi_Host *shost = dev_to_shost(dev);
- struct iscsi_cls_host *ihost = shost->shost_data;
-
- memset(ihost, 0, sizeof(*ihost));
- atomic_set(&ihost->nr_scans, 0);
- mutex_init(&ihost->mutex);
- return 0;
-}
-
-static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
- "iscsi_host",
- iscsi_setup_host,
- NULL,
- NULL);
-
-static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
- "iscsi_session",
- NULL,
- NULL,
- NULL);
-
-static DECLARE_TRANSPORT_CLASS(iscsi_connection_class,
- "iscsi_connection",
- NULL,
- NULL,
- NULL);
-
-static struct sock *nls;
-static DEFINE_MUTEX(rx_queue_mutex);
-
-static LIST_HEAD(sesslist);
-static DEFINE_SPINLOCK(sesslock);
-static LIST_HEAD(connlist);
-static DEFINE_SPINLOCK(connlock);
-
-static uint32_t iscsi_conn_get_sid(struct iscsi_cls_conn *conn)
-{
- struct iscsi_cls_session *sess = iscsi_dev_to_session(conn->dev.parent);
- return sess->sid;
-}
-
-/*
- * Returns the matching session to a given sid
- */
-static struct iscsi_cls_session *iscsi_session_lookup(uint32_t sid)
-{
- unsigned long flags;
- struct iscsi_cls_session *sess;
-
- spin_lock_irqsave(&sesslock, flags);
- list_for_each_entry(sess, &sesslist, sess_list) {
- if (sess->sid == sid) {
- spin_unlock_irqrestore(&sesslock, flags);
- return sess;
- }
- }
- spin_unlock_irqrestore(&sesslock, flags);
- return NULL;
-}
-
-/*
- * Returns the matching connection to a given sid / cid tuple
- */
-static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid)
-{
- unsigned long flags;
- struct iscsi_cls_conn *conn;
-
- spin_lock_irqsave(&connlock, flags);
- list_for_each_entry(conn, &connlist, conn_list) {
- if ((conn->cid == cid) && (iscsi_conn_get_sid(conn) == sid)) {
- spin_unlock_irqrestore(&connlock, flags);
- return conn;
- }
- }
- spin_unlock_irqrestore(&connlock, flags);
- return NULL;
-}
-
-/*
- * The following functions can be used by LLDs that allocate
- * their own scsi_hosts or by software iscsi LLDs
- */
-static struct {
- int value;
- char *name;
-} iscsi_session_state_names[] = {
- { ISCSI_SESSION_LOGGED_IN, "LOGGED_IN" },
- { ISCSI_SESSION_FAILED, "FAILED" },
- { ISCSI_SESSION_FREE, "FREE" },
-};
-
-static const char *iscsi_session_state_name(int state)
-{
- int i;
- char *name = NULL;
-
- for (i = 0; i < ARRAY_SIZE(iscsi_session_state_names); i++) {
- if (iscsi_session_state_names[i].value == state) {
- name = iscsi_session_state_names[i].name;
- break;
- }
- }
- return name;
-}
-
-int iscsi_session_chkready(struct iscsi_cls_session *session)
-{
- unsigned long flags;
- int err;
-
- spin_lock_irqsave(&session->lock, flags);
- switch (session->state) {
- case ISCSI_SESSION_LOGGED_IN:
- err = 0;
- break;
- case ISCSI_SESSION_FAILED:
- err = DID_IMM_RETRY << 16;
- break;
- case ISCSI_SESSION_FREE:
- err = DID_TRANSPORT_FAILFAST << 16;
- break;
- default:
- err = DID_NO_CONNECT << 16;
- break;
- }
- spin_unlock_irqrestore(&session->lock, flags);
- return err;
-}
-EXPORT_SYMBOL_GPL(iscsi_session_chkready);
-
-static void iscsi_session_release(struct device *dev)
-{
- struct iscsi_cls_session *session = iscsi_dev_to_session(dev);
- struct Scsi_Host *shost;
-
- shost = iscsi_session_to_shost(session);
- scsi_host_put(shost);
- ISCSI_DBG_TRANS_SESSION(session, "Completing session release\n");
- kfree(session);
-}
-
-static int iscsi_is_session_dev(const struct device *dev)
-{
- return dev->release == iscsi_session_release;
-}
-
-static int iscsi_iter_session_fn(struct device *dev, void *data)
-{
- void (* fn) (struct iscsi_cls_session *) = data;
-
- if (!iscsi_is_session_dev(dev))
- return 0;
- fn(iscsi_dev_to_session(dev));
- return 0;
-}
-
-void iscsi_host_for_each_session(struct Scsi_Host *shost,
- void (*fn)(struct iscsi_cls_session *))
-{
- device_for_each_child(&shost->shost_gendev, fn,
- iscsi_iter_session_fn);
-}
-EXPORT_SYMBOL_GPL(iscsi_host_for_each_session);
-
-/**
- * iscsi_scan_finished - helper to report when running scans are done
- * @shost: scsi host
- * @time: scan run time
- *
- * This function can be used by drives like qla4xxx to report to the scsi
- * layer when the scans it kicked off at module load time are done.
- */
-int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time)
-{
- struct iscsi_cls_host *ihost = shost->shost_data;
- /*
- * qla4xxx will have kicked off some session unblocks before calling
- * scsi_scan_host, so just wait for them to complete.
- */
- return !atomic_read(&ihost->nr_scans);
-}
-EXPORT_SYMBOL_GPL(iscsi_scan_finished);
-
-struct iscsi_scan_data {
- unsigned int channel;
- unsigned int id;
- unsigned int lun;
-};
-
-static int iscsi_user_scan_session(struct device *dev, void *data)
-{
- struct iscsi_scan_data *scan_data = data;
- struct iscsi_cls_session *session;
- struct Scsi_Host *shost;
- struct iscsi_cls_host *ihost;
- unsigned long flags;
- unsigned int id;
-
- if (!iscsi_is_session_dev(dev))
- return 0;
-
- session = iscsi_dev_to_session(dev);
-
- ISCSI_DBG_TRANS_SESSION(session, "Scanning session\n");
-
- shost = iscsi_session_to_shost(session);
- ihost = shost->shost_data;
-
- mutex_lock(&ihost->mutex);
- spin_lock_irqsave(&session->lock, flags);
- if (session->state != ISCSI_SESSION_LOGGED_IN) {
- spin_unlock_irqrestore(&session->lock, flags);
- goto user_scan_exit;
- }
- id = session->target_id;
- spin_unlock_irqrestore(&session->lock, flags);
-
- if (id != ISCSI_MAX_TARGET) {
- if ((scan_data->channel == SCAN_WILD_CARD ||
- scan_data->channel == 0) &&
- (scan_data->id == SCAN_WILD_CARD ||
- scan_data->id == id))
- scsi_scan_target(&session->dev, 0, id,
- scan_data->lun, 1);
- }
-
-user_scan_exit:
- mutex_unlock(&ihost->mutex);
- ISCSI_DBG_TRANS_SESSION(session, "Completed session scan\n");
- return 0;
-}
-
-static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
- uint id, uint lun)
-{
- struct iscsi_scan_data scan_data;
-
- scan_data.channel = channel;
- scan_data.id = id;
- scan_data.lun = lun;
-
- return device_for_each_child(&shost->shost_gendev, &scan_data,
- iscsi_user_scan_session);
-}
-
-static void iscsi_scan_session(struct work_struct *work)
-{
- struct iscsi_cls_session *session =
- container_of(work, struct iscsi_cls_session, scan_work);
- struct Scsi_Host *shost = iscsi_session_to_shost(session);
- struct iscsi_cls_host *ihost = shost->shost_data;
- struct iscsi_scan_data scan_data;
-
- scan_data.channel = 0;
- scan_data.id = SCAN_WILD_CARD;
- scan_data.lun = SCAN_WILD_CARD;
-
- iscsi_user_scan_session(&session->dev, &scan_data);
- atomic_dec(&ihost->nr_scans);
-}
-
-static void session_recovery_timedout(struct work_struct *work)
-{
- struct iscsi_cls_session *session =
- container_of(work, struct iscsi_cls_session,
- recovery_work.work);
- unsigned long flags;
-
- iscsi_cls_session_printk(KERN_INFO, session,
- "session recovery timed out after %d secs\n",
- session->recovery_tmo);
-
- spin_lock_irqsave(&session->lock, flags);
- switch (session->state) {
- case ISCSI_SESSION_FAILED:
- session->state = ISCSI_SESSION_FREE;
- break;
- case ISCSI_SESSION_LOGGED_IN:
- case ISCSI_SESSION_FREE:
- /* we raced with the unblock's flush */
- spin_unlock_irqrestore(&session->lock, flags);
- return;
- }
- spin_unlock_irqrestore(&session->lock, flags);
-
- if (session->transport->session_recovery_timedout)
- session->transport->session_recovery_timedout(session);
-
- ISCSI_DBG_TRANS_SESSION(session, "Unblocking SCSI target\n");
- scsi_target_unblock(&session->dev);
- ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking SCSI target\n");
-}
-
-static void __iscsi_unblock_session(struct work_struct *work)
-{
- struct iscsi_cls_session *session =
- container_of(work, struct iscsi_cls_session,
- unblock_work);
- struct Scsi_Host *shost = iscsi_session_to_shost(session);
- struct iscsi_cls_host *ihost = shost->shost_data;
- unsigned long flags;
-
- ISCSI_DBG_TRANS_SESSION(session, "Unblocking session\n");
- /*
- * The recovery and unblock work get run from the same workqueue,
- * so try to cancel it if it was going to run after this unblock.
- */
- cancel_delayed_work(&session->recovery_work);
- spin_lock_irqsave(&session->lock, flags);
- session->state = ISCSI_SESSION_LOGGED_IN;
- spin_unlock_irqrestore(&session->lock, flags);
- /* start IO */
- scsi_target_unblock(&session->dev);
- /*
- * Only do kernel scanning if the driver is properly hooked into
- * the async scanning code (drivers like iscsi_tcp do login and
- * scanning from userspace).
- */
- if (shost->hostt->scan_finished) {
- if (scsi_queue_work(shost, &session->scan_work))
- atomic_inc(&ihost->nr_scans);
- }
- ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking session\n");
-}
-
-/**
- * iscsi_unblock_session - set a session as logged in and start IO.
- * @session: iscsi session
- *
- * Mark a session as ready to accept IO.
- */
-void iscsi_unblock_session(struct iscsi_cls_session *session)
-{
- queue_work(iscsi_eh_timer_workq, &session->unblock_work);
- /*
- * make sure all the events have completed before tell the driver
- * it is safe
- */
- flush_workqueue(iscsi_eh_timer_workq);
-}
-EXPORT_SYMBOL_GPL(iscsi_unblock_session);
-
-static void __iscsi_block_session(struct work_struct *work)
-{
- struct iscsi_cls_session *session =
- container_of(work, struct iscsi_cls_session,
- block_work);
- unsigned long flags;
-
- ISCSI_DBG_TRANS_SESSION(session, "Blocking session\n");
- spin_lock_irqsave(&session->lock, flags);
- session->state = ISCSI_SESSION_FAILED;
- spin_unlock_irqrestore(&session->lock, flags);
- scsi_target_block(&session->dev);
- ISCSI_DBG_TRANS_SESSION(session, "Completed SCSI target blocking\n");
- if (session->recovery_tmo >= 0)
- queue_delayed_work(iscsi_eh_timer_workq,
- &session->recovery_work,
- session->recovery_tmo * HZ);
-}
-
-void iscsi_block_session(struct iscsi_cls_session *session)
-{
- queue_work(iscsi_eh_timer_workq, &session->block_work);
-}
-EXPORT_SYMBOL_GPL(iscsi_block_session);
-
-static void __iscsi_unbind_session(struct work_struct *work)
-{
- struct iscsi_cls_session *session =
- container_of(work, struct iscsi_cls_session,
- unbind_work);
- struct Scsi_Host *shost = iscsi_session_to_shost(session);
- struct iscsi_cls_host *ihost = shost->shost_data;
- unsigned long flags;
-
- ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n");
-
- /* Prevent new scans and make sure scanning is not in progress */
- mutex_lock(&ihost->mutex);
- spin_lock_irqsave(&session->lock, flags);
- if (session->target_id == ISCSI_MAX_TARGET) {
- spin_unlock_irqrestore(&session->lock, flags);
- mutex_unlock(&ihost->mutex);
- return;
- }
- session->target_id = ISCSI_MAX_TARGET;
- spin_unlock_irqrestore(&session->lock, flags);
- mutex_unlock(&ihost->mutex);
-
- scsi_remove_target(&session->dev);
- iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
- ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n");
-}
-
-struct iscsi_cls_session *
-iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
- int dd_size)
-{
- struct iscsi_cls_session *session;
-
- session = kzalloc(sizeof(*session) + dd_size,
- GFP_KERNEL);
- if (!session)
- return NULL;
-
- session->transport = transport;
- session->recovery_tmo = 120;
- session->state = ISCSI_SESSION_FREE;
- INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
- INIT_LIST_HEAD(&session->sess_list);
- INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
- INIT_WORK(&session->block_work, __iscsi_block_session);
- INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
- INIT_WORK(&session->scan_work, iscsi_scan_session);
- spin_lock_init(&session->lock);
-
- /* this is released in the dev's release function */
- scsi_host_get(shost);
- session->dev.parent = &shost->shost_gendev;
- session->dev.release = iscsi_session_release;
- device_initialize(&session->dev);
- if (dd_size)
- session->dd_data = &session[1];
-
- ISCSI_DBG_TRANS_SESSION(session, "Completed session allocation\n");
- return session;
-}
-EXPORT_SYMBOL_GPL(iscsi_alloc_session);
-
-static int iscsi_get_next_target_id(struct device *dev, void *data)
-{
- struct iscsi_cls_session *session;
- unsigned long flags;
- int err = 0;
-
- if (!iscsi_is_session_dev(dev))
- return 0;
-
- session = iscsi_dev_to_session(dev);
- spin_lock_irqsave(&session->lock, flags);
- if (*((unsigned int *) data) == session->target_id)
- err = -EEXIST;
- spin_unlock_irqrestore(&session->lock, flags);
- return err;
-}
-
-int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
-{
- struct Scsi_Host *shost = iscsi_session_to_shost(session);
- struct iscsi_cls_host *ihost;
- unsigned long flags;
- unsigned int id = target_id;
- int err;
-
- ihost = shost->shost_data;
- session->sid = atomic_add_return(1, &iscsi_session_nr);
-
- if (id == ISCSI_MAX_TARGET) {
- for (id = 0; id < ISCSI_MAX_TARGET; id++) {
- err = device_for_each_child(&shost->shost_gendev, &id,
- iscsi_get_next_target_id);
- if (!err)
- break;
- }
-
- if (id == ISCSI_MAX_TARGET) {
- iscsi_cls_session_printk(KERN_ERR, session,
- "Too many iscsi targets. Max "
- "number of targets is %d.\n",
- ISCSI_MAX_TARGET - 1);
- err = -EOVERFLOW;
- goto release_host;
- }
- }
- session->target_id = id;
-
- dev_set_name(&session->dev, "session%u", session->sid);
- err = device_add(&session->dev);
- if (err) {
- iscsi_cls_session_printk(KERN_ERR, session,
- "could not register session's dev\n");
- goto release_host;
- }
- transport_register_device(&session->dev);
-
- spin_lock_irqsave(&sesslock, flags);
- list_add(&session->sess_list, &sesslist);
- spin_unlock_irqrestore(&sesslock, flags);
-
- iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
- ISCSI_DBG_TRANS_SESSION(session, "Completed session adding\n");
- return 0;
-
-release_host:
- scsi_host_put(shost);
- return err;
-}
-EXPORT_SYMBOL_GPL(iscsi_add_session);
-
-/**
- * iscsi_create_session - create iscsi class session
- * @shost: scsi host
- * @transport: iscsi transport
- * @dd_size: private driver data size
- * @target_id: which target
- *
- * This can be called from a LLD or iscsi_transport.
- */
-struct iscsi_cls_session *
-iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
- int dd_size, unsigned int target_id)
-{
- struct iscsi_cls_session *session;
-
- session = iscsi_alloc_session(shost, transport, dd_size);
- if (!session)
- return NULL;
-
- if (iscsi_add_session(session, target_id)) {
- iscsi_free_session(session);
- return NULL;
- }
- return session;
-}
-EXPORT_SYMBOL_GPL(iscsi_create_session);
-
-static void iscsi_conn_release(struct device *dev)
-{
- struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
- struct device *parent = conn->dev.parent;
-
- ISCSI_DBG_TRANS_CONN(conn, "Releasing conn\n");
- kfree(conn);
- put_device(parent);
-}
-
-static int iscsi_is_conn_dev(const struct device *dev)
-{
- return dev->release == iscsi_conn_release;
-}
-
-static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
-{
- if (!iscsi_is_conn_dev(dev))
- return 0;
- return iscsi_destroy_conn(iscsi_dev_to_conn(dev));
-}
-
-void iscsi_remove_session(struct iscsi_cls_session *session)
-{
- struct Scsi_Host *shost = iscsi_session_to_shost(session);
- unsigned long flags;
- int err;
-
- ISCSI_DBG_TRANS_SESSION(session, "Removing session\n");
-
- spin_lock_irqsave(&sesslock, flags);
- list_del(&session->sess_list);
- spin_unlock_irqrestore(&sesslock, flags);
-
- /* make sure there are no blocks/unblocks queued */
- flush_workqueue(iscsi_eh_timer_workq);
- /* make sure the timedout callout is not running */
- if (!cancel_delayed_work(&session->recovery_work))
- flush_workqueue(iscsi_eh_timer_workq);
- /*
- * If we are blocked let commands flow again. The lld or iscsi
- * layer should set up the queuecommand to fail commands.
- * We assume that LLD will not be calling block/unblock while
- * removing the session.
- */
- spin_lock_irqsave(&session->lock, flags);
- session->state = ISCSI_SESSION_FREE;
- spin_unlock_irqrestore(&session->lock, flags);
-
- scsi_target_unblock(&session->dev);
- /* flush running scans then delete devices */
- scsi_flush_work(shost);
- __iscsi_unbind_session(&session->unbind_work);
-
- /* hw iscsi may not have removed all connections from session */
- err = device_for_each_child(&session->dev, NULL,
- iscsi_iter_destroy_conn_fn);
- if (err)
- iscsi_cls_session_printk(KERN_ERR, session,
- "Could not delete all connections "
- "for session. Error %d.\n", err);
-
- transport_unregister_device(&session->dev);
-
- ISCSI_DBG_TRANS_SESSION(session, "Completing session removal\n");
- device_del(&session->dev);
-}
-EXPORT_SYMBOL_GPL(iscsi_remove_session);
-
-void iscsi_free_session(struct iscsi_cls_session *session)
-{
- ISCSI_DBG_TRANS_SESSION(session, "Freeing session\n");
- iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION);
- put_device(&session->dev);
-}
-EXPORT_SYMBOL_GPL(iscsi_free_session);
-
-/**
- * iscsi_destroy_session - destroy iscsi session
- * @session: iscsi_session
- *
- * Can be called by a LLD or iscsi_transport. There must not be
- * any running connections.
- */
-int iscsi_destroy_session(struct iscsi_cls_session *session)
-{
- iscsi_remove_session(session);
- ISCSI_DBG_TRANS_SESSION(session, "Completing session destruction\n");
- iscsi_free_session(session);
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_destroy_session);
-
-/**
- * iscsi_create_conn - create iscsi class connection
- * @session: iscsi cls session
- * @dd_size: private driver data size
- * @cid: connection id
- *
- * This can be called from a LLD or iscsi_transport. The connection
- * is child of the session so cid must be unique for all connections
- * on the session.
- *
- * Since we do not support MCS, cid will normally be zero. In some cases
- * for software iscsi we could be trying to preallocate a connection struct
- * in which case there could be two connection structs and cid would be
- * non-zero.
- */
-struct iscsi_cls_conn *
-iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
-{
- struct iscsi_transport *transport = session->transport;
- struct iscsi_cls_conn *conn;
- unsigned long flags;
- int err;
-
- conn = kzalloc(sizeof(*conn) + dd_size, GFP_KERNEL);
- if (!conn)
- return NULL;
- if (dd_size)
- conn->dd_data = &conn[1];
-
- INIT_LIST_HEAD(&conn->conn_list);
- conn->transport = transport;
- conn->cid = cid;
-
- /* this is released in the dev's release function */
- if (!get_device(&session->dev))
- goto free_conn;
-
- dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid);
- conn->dev.parent = &session->dev;
- conn->dev.release = iscsi_conn_release;
- err = device_register(&conn->dev);
- if (err) {
- iscsi_cls_session_printk(KERN_ERR, session, "could not "
- "register connection's dev\n");
- goto release_parent_ref;
- }
- transport_register_device(&conn->dev);
-
- spin_lock_irqsave(&connlock, flags);
- list_add(&conn->conn_list, &connlist);
- conn->active = 1;
- spin_unlock_irqrestore(&connlock, flags);
-
- ISCSI_DBG_TRANS_CONN(conn, "Completed conn creation\n");
- return conn;
-
-release_parent_ref:
- put_device(&session->dev);
-free_conn:
- kfree(conn);
- return NULL;
-}
-
-EXPORT_SYMBOL_GPL(iscsi_create_conn);
-
-/**
- * iscsi_destroy_conn - destroy iscsi class connection
- * @conn: iscsi cls session
- *
- * This can be called from a LLD or iscsi_transport.
- */
-int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&connlock, flags);
- conn->active = 0;
- list_del(&conn->conn_list);
- spin_unlock_irqrestore(&connlock, flags);
-
- transport_unregister_device(&conn->dev);
- ISCSI_DBG_TRANS_CONN(conn, "Completing conn destruction\n");
- device_unregister(&conn->dev);
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
-
-/*
- * iscsi interface functions
- */
-static struct iscsi_internal *
-iscsi_if_transport_lookup(struct iscsi_transport *tt)
-{
- struct iscsi_internal *priv;
- unsigned long flags;
-
- spin_lock_irqsave(&iscsi_transport_lock, flags);
- list_for_each_entry(priv, &iscsi_transports, list) {
- if (tt == priv->iscsi_transport) {
- spin_unlock_irqrestore(&iscsi_transport_lock, flags);
- return priv;
- }
- }
- spin_unlock_irqrestore(&iscsi_transport_lock, flags);
- return NULL;
-}
-
-static int
-iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp)
-{
- return nlmsg_multicast(nls, skb, 0, group, gfp);
-}
-
-int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
- char *data, uint32_t data_size)
-{
- struct nlmsghdr *nlh;
- struct sk_buff *skb;
- struct iscsi_uevent *ev;
- char *pdu;
- struct iscsi_internal *priv;
- int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) +
- data_size);
-
- priv = iscsi_if_transport_lookup(conn->transport);
- if (!priv)
- return -EINVAL;
-
- skb = alloc_skb(len, GFP_ATOMIC);
- if (!skb) {
- iscsi_conn_error_event(conn, ISCSI_ERR_CONN_FAILED);
- iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver "
- "control PDU: OOM\n");
- return -ENOMEM;
- }
-
- nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
- memset(ev, 0, sizeof(*ev));
- ev->transport_handle = iscsi_handle(conn->transport);
- ev->type = ISCSI_KEVENT_RECV_PDU;
- ev->r.recv_req.cid = conn->cid;
- ev->r.recv_req.sid = iscsi_conn_get_sid(conn);
- pdu = (char*)ev + sizeof(*ev);
- memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
- memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
-
- return iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
-}
-EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
-
-int iscsi_offload_mesg(struct Scsi_Host *shost,
- struct iscsi_transport *transport, uint32_t type,
- char *data, uint16_t data_size)
-{
- struct nlmsghdr *nlh;
- struct sk_buff *skb;
- struct iscsi_uevent *ev;
- int len = NLMSG_SPACE(sizeof(*ev) + data_size);
-
- skb = alloc_skb(len, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_ERR "can not deliver iscsi offload message:OOM\n");
- return -ENOMEM;
- }
-
- nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
- memset(ev, 0, sizeof(*ev));
- ev->type = type;
- ev->transport_handle = iscsi_handle(transport);
- switch (type) {
- case ISCSI_KEVENT_PATH_REQ:
- ev->r.req_path.host_no = shost->host_no;
- break;
- case ISCSI_KEVENT_IF_DOWN:
- ev->r.notify_if_down.host_no = shost->host_no;
- break;
- }
-
- memcpy((char *)ev + sizeof(*ev), data, data_size);
-
- return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_ATOMIC);
-}
-EXPORT_SYMBOL_GPL(iscsi_offload_mesg);
-
-void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
-{
- struct nlmsghdr *nlh;
- struct sk_buff *skb;
- struct iscsi_uevent *ev;
- struct iscsi_internal *priv;
- int len = NLMSG_SPACE(sizeof(*ev));
-
- priv = iscsi_if_transport_lookup(conn->transport);
- if (!priv)
- return;
-
- skb = alloc_skb(len, GFP_ATOMIC);
- if (!skb) {
- iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored "
- "conn error (%d)\n", error);
- return;
- }
-
- nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
- ev->transport_handle = iscsi_handle(conn->transport);
- ev->type = ISCSI_KEVENT_CONN_ERROR;
- ev->r.connerror.error = error;
- ev->r.connerror.cid = conn->cid;
- ev->r.connerror.sid = iscsi_conn_get_sid(conn);
-
- iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
-
- iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n",
- error);
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_error_event);
-
-static int
-iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
- void *payload, int size)
-{
- struct sk_buff *skb;
- struct nlmsghdr *nlh;
- int len = NLMSG_SPACE(size);
- int flags = multi ? NLM_F_MULTI : 0;
- int t = done ? NLMSG_DONE : type;
-
- skb = alloc_skb(len, GFP_ATOMIC);
- if (!skb) {
- printk(KERN_ERR "Could not allocate skb to send reply.\n");
- return -ENOMEM;
- }
-
- nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0);
- nlh->nlmsg_flags = flags;
- memcpy(NLMSG_DATA(nlh), payload, size);
- return iscsi_multicast_skb(skb, group, GFP_ATOMIC);
-}
-
-static int
-iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
-{
- struct iscsi_uevent *ev = NLMSG_DATA(nlh);
- struct iscsi_stats *stats;
- struct sk_buff *skbstat;
- struct iscsi_cls_conn *conn;
- struct nlmsghdr *nlhstat;
- struct iscsi_uevent *evstat;
- struct iscsi_internal *priv;
- int len = NLMSG_SPACE(sizeof(*ev) +
- sizeof(struct iscsi_stats) +
- sizeof(struct iscsi_stats_custom) *
- ISCSI_STATS_CUSTOM_MAX);
- int err = 0;
-
- priv = iscsi_if_transport_lookup(transport);
- if (!priv)
- return -EINVAL;
-
- conn = iscsi_conn_lookup(ev->u.get_stats.sid, ev->u.get_stats.cid);
- if (!conn)
- return -EEXIST;
-
- do {
- int actual_size;
-
- skbstat = alloc_skb(len, GFP_ATOMIC);
- if (!skbstat) {
- iscsi_cls_conn_printk(KERN_ERR, conn, "can not "
- "deliver stats: OOM\n");
- return -ENOMEM;
- }
-
- nlhstat = __nlmsg_put(skbstat, 0, 0, 0,
- (len - sizeof(*nlhstat)), 0);
- evstat = NLMSG_DATA(nlhstat);
- memset(evstat, 0, sizeof(*evstat));
- evstat->transport_handle = iscsi_handle(conn->transport);
- evstat->type = nlh->nlmsg_type;
- evstat->u.get_stats.cid =
- ev->u.get_stats.cid;
- evstat->u.get_stats.sid =
- ev->u.get_stats.sid;
- stats = (struct iscsi_stats *)
- ((char*)evstat + sizeof(*evstat));
- memset(stats, 0, sizeof(*stats));
-
- transport->get_stats(conn, stats);
- actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) +
- sizeof(struct iscsi_stats) +
- sizeof(struct iscsi_stats_custom) *
- stats->custom_length);
- actual_size -= sizeof(*nlhstat);
- actual_size = NLMSG_LENGTH(actual_size);
- skb_trim(skbstat, NLMSG_ALIGN(actual_size));
- nlhstat->nlmsg_len = actual_size;
-
- err = iscsi_multicast_skb(skbstat, ISCSI_NL_GRP_ISCSID,
- GFP_ATOMIC);
- } while (err < 0 && err != -ECONNREFUSED);
-
- return err;
-}
-
-/**
- * iscsi_session_event - send session destr. completion event
- * @session: iscsi class session
- * @event: type of event
- */
-int iscsi_session_event(struct iscsi_cls_session *session,
- enum iscsi_uevent_e event)
-{
- struct iscsi_internal *priv;
- struct Scsi_Host *shost;
- struct iscsi_uevent *ev;
- struct sk_buff *skb;
- struct nlmsghdr *nlh;
- int rc, len = NLMSG_SPACE(sizeof(*ev));
-
- priv = iscsi_if_transport_lookup(session->transport);
- if (!priv)
- return -EINVAL;
- shost = iscsi_session_to_shost(session);
-
- skb = alloc_skb(len, GFP_KERNEL);
- if (!skb) {
- iscsi_cls_session_printk(KERN_ERR, session,
- "Cannot notify userspace of session "
- "event %u\n", event);
- return -ENOMEM;
- }
-
- nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
- ev->transport_handle = iscsi_handle(session->transport);
-
- ev->type = event;
- switch (event) {
- case ISCSI_KEVENT_DESTROY_SESSION:
- ev->r.d_session.host_no = shost->host_no;
- ev->r.d_session.sid = session->sid;
- break;
- case ISCSI_KEVENT_CREATE_SESSION:
- ev->r.c_session_ret.host_no = shost->host_no;
- ev->r.c_session_ret.sid = session->sid;
- break;
- case ISCSI_KEVENT_UNBIND_SESSION:
- ev->r.unbind_session.host_no = shost->host_no;
- ev->r.unbind_session.sid = session->sid;
- break;
- default:
- iscsi_cls_session_printk(KERN_ERR, session, "Invalid event "
- "%u.\n", event);
- kfree_skb(skb);
- return -EINVAL;
- }
-
- /*
- * this will occur if the daemon is not up, so we just warn
- * the user and when the daemon is restarted it will handle it
- */
- rc = iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
- if (rc == -ESRCH)
- iscsi_cls_session_printk(KERN_ERR, session,
- "Cannot notify userspace of session "
- "event %u. Check iscsi daemon\n",
- event);
-
- ISCSI_DBG_TRANS_SESSION(session, "Completed handling event %d rc %d\n",
- event, rc);
- return rc;
-}
-EXPORT_SYMBOL_GPL(iscsi_session_event);
-
-static int
-iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep,
- struct iscsi_uevent *ev, uint32_t initial_cmdsn,
- uint16_t cmds_max, uint16_t queue_depth)
-{
- struct iscsi_transport *transport = priv->iscsi_transport;
- struct iscsi_cls_session *session;
- struct Scsi_Host *shost;
-
- session = transport->create_session(ep, cmds_max, queue_depth,
- initial_cmdsn);
- if (!session)
- return -ENOMEM;
-
- shost = iscsi_session_to_shost(session);
- ev->r.c_session_ret.host_no = shost->host_no;
- ev->r.c_session_ret.sid = session->sid;
- ISCSI_DBG_TRANS_SESSION(session,
- "Completed creating transport session\n");
- return 0;
-}
-
-static int
-iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
-{
- struct iscsi_cls_conn *conn;
- struct iscsi_cls_session *session;
-
- session = iscsi_session_lookup(ev->u.c_conn.sid);
- if (!session) {
- printk(KERN_ERR "iscsi: invalid session %d.\n",
- ev->u.c_conn.sid);
- return -EINVAL;
- }
-
- conn = transport->create_conn(session, ev->u.c_conn.cid);
- if (!conn) {
- iscsi_cls_session_printk(KERN_ERR, session,
- "couldn't create a new connection.");
- return -ENOMEM;
- }
-
- ev->r.c_conn_ret.sid = session->sid;
- ev->r.c_conn_ret.cid = conn->cid;
-
- ISCSI_DBG_TRANS_CONN(conn, "Completed creating transport conn\n");
- return 0;
-}
-
-static int
-iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
-{
- struct iscsi_cls_conn *conn;
-
- conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
- if (!conn)
- return -EINVAL;
-
- ISCSI_DBG_TRANS_CONN(conn, "Destroying transport conn\n");
- if (transport->destroy_conn)
- transport->destroy_conn(conn);
-
- return 0;
-}
-
-static int
-iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
-{
- char *data = (char*)ev + sizeof(*ev);
- struct iscsi_cls_conn *conn;
- struct iscsi_cls_session *session;
- int err = 0, value = 0;
-
- session = iscsi_session_lookup(ev->u.set_param.sid);
- conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid);
- if (!conn || !session)
- return -EINVAL;
-
- switch (ev->u.set_param.param) {
- case ISCSI_PARAM_SESS_RECOVERY_TMO:
- sscanf(data, "%d", &value);
- session->recovery_tmo = value;
- break;
- default:
- err = transport->set_param(conn, ev->u.set_param.param,
- data, ev->u.set_param.len);
- }
-
- return err;
-}
-
-static int iscsi_if_ep_connect(struct iscsi_transport *transport,
- struct iscsi_uevent *ev, int msg_type)
-{
- struct iscsi_endpoint *ep;
- struct sockaddr *dst_addr;
- struct Scsi_Host *shost = NULL;
- int non_blocking, err = 0;
-
- if (!transport->ep_connect)
- return -EINVAL;
-
- if (msg_type == ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST) {
- shost = scsi_host_lookup(ev->u.ep_connect_through_host.host_no);
- if (!shost) {
- printk(KERN_ERR "ep connect failed. Could not find "
- "host no %u\n",
- ev->u.ep_connect_through_host.host_no);
- return -ENODEV;
- }
- non_blocking = ev->u.ep_connect_through_host.non_blocking;
- } else
- non_blocking = ev->u.ep_connect.non_blocking;
-
- dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
- ep = transport->ep_connect(shost, dst_addr, non_blocking);
- if (IS_ERR(ep)) {
- err = PTR_ERR(ep);
- goto release_host;
- }
-
- ev->r.ep_connect_ret.handle = ep->id;
-release_host:
- if (shost)
- scsi_host_put(shost);
- return err;
-}
-
-static int
-iscsi_if_transport_ep(struct iscsi_transport *transport,
- struct iscsi_uevent *ev, int msg_type)
-{
- struct iscsi_endpoint *ep;
- int rc = 0;
-
- switch (msg_type) {
- case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
- case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
- rc = iscsi_if_ep_connect(transport, ev, msg_type);
- break;
- case ISCSI_UEVENT_TRANSPORT_EP_POLL:
- if (!transport->ep_poll)
- return -EINVAL;
-
- ep = iscsi_lookup_endpoint(ev->u.ep_poll.ep_handle);
- if (!ep)
- return -EINVAL;
-
- ev->r.retcode = transport->ep_poll(ep,
- ev->u.ep_poll.timeout_ms);
- break;
- case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
- if (!transport->ep_disconnect)
- return -EINVAL;
-
- ep = iscsi_lookup_endpoint(ev->u.ep_disconnect.ep_handle);
- if (!ep)
- return -EINVAL;
-
- transport->ep_disconnect(ep);
- break;
- }
- return rc;
-}
-
-static int
-iscsi_tgt_dscvr(struct iscsi_transport *transport,
- struct iscsi_uevent *ev)
-{
- struct Scsi_Host *shost;
- struct sockaddr *dst_addr;
- int err;
-
- if (!transport->tgt_dscvr)
- return -EINVAL;
-
- shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no);
- if (!shost) {
- printk(KERN_ERR "target discovery could not find host no %u\n",
- ev->u.tgt_dscvr.host_no);
- return -ENODEV;
- }
-
-
- dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
- err = transport->tgt_dscvr(shost, ev->u.tgt_dscvr.type,
- ev->u.tgt_dscvr.enable, dst_addr);
- scsi_host_put(shost);
- return err;
-}
-
-static int
-iscsi_set_host_param(struct iscsi_transport *transport,
- struct iscsi_uevent *ev)
-{
- char *data = (char*)ev + sizeof(*ev);
- struct Scsi_Host *shost;
- int err;
-
- if (!transport->set_host_param)
- return -ENOSYS;
-
- shost = scsi_host_lookup(ev->u.set_host_param.host_no);
- if (!shost) {
- printk(KERN_ERR "set_host_param could not find host no %u\n",
- ev->u.set_host_param.host_no);
- return -ENODEV;
- }
-
- err = transport->set_host_param(shost, ev->u.set_host_param.param,
- data, ev->u.set_host_param.len);
- scsi_host_put(shost);
- return err;
-}
-
-static int
-iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev)
-{
- struct Scsi_Host *shost;
- struct iscsi_path *params;
- int err;
-
- if (!transport->set_path)
- return -ENOSYS;
-
- shost = scsi_host_lookup(ev->u.set_path.host_no);
- if (!shost) {
- printk(KERN_ERR "set path could not find host no %u\n",
- ev->u.set_path.host_no);
- return -ENODEV;
- }
-
- params = (struct iscsi_path *)((char *)ev + sizeof(*ev));
- err = transport->set_path(shost, params);
-
- scsi_host_put(shost);
- return err;
-}
-
-static int
-iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
-{
- int err = 0;
- struct iscsi_uevent *ev = NLMSG_DATA(nlh);
- struct iscsi_transport *transport = NULL;
- struct iscsi_internal *priv;
- struct iscsi_cls_session *session;
- struct iscsi_cls_conn *conn;
- struct iscsi_endpoint *ep = NULL;
-
- if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE)
- *group = ISCSI_NL_GRP_UIP;
- else
- *group = ISCSI_NL_GRP_ISCSID;
-
- priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
- if (!priv)
- return -EINVAL;
- transport = priv->iscsi_transport;
-
- if (!try_module_get(transport->owner))
- return -EINVAL;
-
- switch (nlh->nlmsg_type) {
- case ISCSI_UEVENT_CREATE_SESSION:
- err = iscsi_if_create_session(priv, ep, ev,
- ev->u.c_session.initial_cmdsn,
- ev->u.c_session.cmds_max,
- ev->u.c_session.queue_depth);
- break;
- case ISCSI_UEVENT_CREATE_BOUND_SESSION:
- ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
- if (!ep) {
- err = -EINVAL;
- break;
- }
-
- err = iscsi_if_create_session(priv, ep, ev,
- ev->u.c_bound_session.initial_cmdsn,
- ev->u.c_bound_session.cmds_max,
- ev->u.c_bound_session.queue_depth);
- break;
- case ISCSI_UEVENT_DESTROY_SESSION:
- session = iscsi_session_lookup(ev->u.d_session.sid);
- if (session)
- transport->destroy_session(session);
- else
- err = -EINVAL;
- break;
- case ISCSI_UEVENT_UNBIND_SESSION:
- session = iscsi_session_lookup(ev->u.d_session.sid);
- if (session)
- scsi_queue_work(iscsi_session_to_shost(session),
- &session->unbind_work);
- else
- err = -EINVAL;
- break;
- case ISCSI_UEVENT_CREATE_CONN:
- err = iscsi_if_create_conn(transport, ev);
- break;
- case ISCSI_UEVENT_DESTROY_CONN:
- err = iscsi_if_destroy_conn(transport, ev);
- break;
- case ISCSI_UEVENT_BIND_CONN:
- session = iscsi_session_lookup(ev->u.b_conn.sid);
- conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid);
-
- if (session && conn)
- ev->r.retcode = transport->bind_conn(session, conn,
- ev->u.b_conn.transport_eph,
- ev->u.b_conn.is_leading);
- else
- err = -EINVAL;
- break;
- case ISCSI_UEVENT_SET_PARAM:
- err = iscsi_set_param(transport, ev);
- break;
- case ISCSI_UEVENT_START_CONN:
- conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid);
- if (conn)
- ev->r.retcode = transport->start_conn(conn);
- else
- err = -EINVAL;
- break;
- case ISCSI_UEVENT_STOP_CONN:
- conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid);
- if (conn)
- transport->stop_conn(conn, ev->u.stop_conn.flag);
- else
- err = -EINVAL;
- break;
- case ISCSI_UEVENT_SEND_PDU:
- conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid);
- if (conn)
- ev->r.retcode = transport->send_pdu(conn,
- (struct iscsi_hdr*)((char*)ev + sizeof(*ev)),
- (char*)ev + sizeof(*ev) + ev->u.send_pdu.hdr_size,
- ev->u.send_pdu.data_size);
- else
- err = -EINVAL;
- break;
- case ISCSI_UEVENT_GET_STATS:
- err = iscsi_if_get_stats(transport, nlh);
- break;
- case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
- case ISCSI_UEVENT_TRANSPORT_EP_POLL:
- case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
- case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
- err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
- break;
- case ISCSI_UEVENT_TGT_DSCVR:
- err = iscsi_tgt_dscvr(transport, ev);
- break;
- case ISCSI_UEVENT_SET_HOST_PARAM:
- err = iscsi_set_host_param(transport, ev);
- break;
- case ISCSI_UEVENT_PATH_UPDATE:
- err = iscsi_set_path(transport, ev);
- break;
- default:
- err = -ENOSYS;
- break;
- }
-
- module_put(transport->owner);
- return err;
-}
-
-/*
- * Get message from skb. Each message is processed by iscsi_if_recv_msg.
- * Malformed skbs with wrong lengths or invalid creds are not processed.
- */
-static void
-iscsi_if_rx(struct sk_buff *skb)
-{
- mutex_lock(&rx_queue_mutex);
- while (skb->len >= NLMSG_SPACE(0)) {
- int err;
- uint32_t rlen;
- struct nlmsghdr *nlh;
- struct iscsi_uevent *ev;
- uint32_t group;
-
- nlh = nlmsg_hdr(skb);
- if (nlh->nlmsg_len < sizeof(*nlh) ||
- skb->len < nlh->nlmsg_len) {
- break;
- }
-
- ev = NLMSG_DATA(nlh);
- rlen = NLMSG_ALIGN(nlh->nlmsg_len);
- if (rlen > skb->len)
- rlen = skb->len;
-
- err = iscsi_if_recv_msg(skb, nlh, &group);
- if (err) {
- ev->type = ISCSI_KEVENT_IF_ERROR;
- ev->iferror = err;
- }
- do {
- /*
- * special case for GET_STATS:
- * on success - sending reply and stats from
- * inside of if_recv_msg(),
- * on error - fall through.
- */
- if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
- break;
- err = iscsi_if_send_reply(group, nlh->nlmsg_seq,
- nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
- } while (err < 0 && err != -ECONNREFUSED);
- skb_pull(skb, rlen);
- }
- mutex_unlock(&rx_queue_mutex);
-}
-
-#define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \
-struct device_attribute dev_attr_##_prefix##_##_name = \
- __ATTR(_name,_mode,_show,_store)
-
-/*
- * iSCSI connection attrs
- */
-#define iscsi_conn_attr_show(param) \
-static ssize_t \
-show_conn_param_##param(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
- struct iscsi_transport *t = conn->transport; \
- return t->get_conn_param(conn, param, buf); \
-}
-
-#define iscsi_conn_attr(field, param) \
- iscsi_conn_attr_show(param) \
-static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_param_##param, \
- NULL);
-
-iscsi_conn_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH);
-iscsi_conn_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH);
-iscsi_conn_attr(header_digest, ISCSI_PARAM_HDRDGST_EN);
-iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN);
-iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN);
-iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN);
-iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT);
-iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT);
-iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
-iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
-iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
-iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
-iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
-
-/*
- * iSCSI session attrs
- */
-#define iscsi_session_attr_show(param, perm) \
-static ssize_t \
-show_session_param_##param(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct iscsi_cls_session *session = \
- iscsi_dev_to_session(dev->parent); \
- struct iscsi_transport *t = session->transport; \
- \
- if (perm && !capable(CAP_SYS_ADMIN)) \
- return -EACCES; \
- return t->get_session_param(session, param, buf); \
-}
-
-#define iscsi_session_attr(field, param, perm) \
- iscsi_session_attr_show(param, perm) \
-static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \
- NULL);
-
-iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME, 0);
-iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, 0);
-iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, 0);
-iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, 0);
-iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, 0);
-iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, 0);
-iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, 0);
-iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, 0);
-iscsi_session_attr(erl, ISCSI_PARAM_ERL, 0);
-iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT, 0);
-iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1);
-iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
-iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
-iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
-iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
-iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
-iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
-iscsi_session_attr(tgt_reset_tmo, ISCSI_PARAM_TGT_RESET_TMO, 0);
-iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
-iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0)
-
-static ssize_t
-show_priv_session_state(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
- return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
-}
-static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
- NULL);
-
-#define iscsi_priv_session_attr_show(field, format) \
-static ssize_t \
-show_priv_session_##field(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct iscsi_cls_session *session = \
- iscsi_dev_to_session(dev->parent); \
- return sprintf(buf, format"\n", session->field); \
-}
-
-#define iscsi_priv_session_attr(field, format) \
- iscsi_priv_session_attr_show(field, format) \
-static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \
- NULL)
-iscsi_priv_session_attr(recovery_tmo, "%d");
-
-/*
- * iSCSI host attrs
- */
-#define iscsi_host_attr_show(param) \
-static ssize_t \
-show_host_param_##param(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct Scsi_Host *shost = transport_class_to_shost(dev); \
- struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
- return priv->iscsi_transport->get_host_param(shost, param, buf); \
-}
-
-#define iscsi_host_attr(field, param) \
- iscsi_host_attr_show(param) \
-static ISCSI_CLASS_ATTR(host, field, S_IRUGO, show_host_param_##param, \
- NULL);
-
-iscsi_host_attr(netdev, ISCSI_HOST_PARAM_NETDEV_NAME);
-iscsi_host_attr(hwaddress, ISCSI_HOST_PARAM_HWADDRESS);
-iscsi_host_attr(ipaddress, ISCSI_HOST_PARAM_IPADDRESS);
-iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
-
-#define SETUP_PRIV_SESSION_RD_ATTR(field) \
-do { \
- priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
- count++; \
-} while (0)
-
-
-#define SETUP_SESSION_RD_ATTR(field, param_flag) \
-do { \
- if (tt->param_mask & param_flag) { \
- priv->session_attrs[count] = &dev_attr_sess_##field; \
- count++; \
- } \
-} while (0)
-
-#define SETUP_CONN_RD_ATTR(field, param_flag) \
-do { \
- if (tt->param_mask & param_flag) { \
- priv->conn_attrs[count] = &dev_attr_conn_##field; \
- count++; \
- } \
-} while (0)
-
-#define SETUP_HOST_RD_ATTR(field, param_flag) \
-do { \
- if (tt->host_param_mask & param_flag) { \
- priv->host_attrs[count] = &dev_attr_host_##field; \
- count++; \
- } \
-} while (0)
-
-static int iscsi_session_match(struct attribute_container *cont,
- struct device *dev)
-{
- struct iscsi_cls_session *session;
- struct Scsi_Host *shost;
- struct iscsi_internal *priv;
-
- if (!iscsi_is_session_dev(dev))
- return 0;
-
- session = iscsi_dev_to_session(dev);
- shost = iscsi_session_to_shost(session);
- if (!shost->transportt)
- return 0;
-
- priv = to_iscsi_internal(shost->transportt);
- if (priv->session_cont.ac.class != &iscsi_session_class.class)
- return 0;
-
- return &priv->session_cont.ac == cont;
-}
-
-static int iscsi_conn_match(struct attribute_container *cont,
- struct device *dev)
-{
- struct iscsi_cls_session *session;
- struct iscsi_cls_conn *conn;
- struct Scsi_Host *shost;
- struct iscsi_internal *priv;
-
- if (!iscsi_is_conn_dev(dev))
- return 0;
-
- conn = iscsi_dev_to_conn(dev);
- session = iscsi_dev_to_session(conn->dev.parent);
- shost = iscsi_session_to_shost(session);
-
- if (!shost->transportt)
- return 0;
-
- priv = to_iscsi_internal(shost->transportt);
- if (priv->conn_cont.ac.class != &iscsi_connection_class.class)
- return 0;
-
- return &priv->conn_cont.ac == cont;
-}
-
-static int iscsi_host_match(struct attribute_container *cont,
- struct device *dev)
-{
- struct Scsi_Host *shost;
- struct iscsi_internal *priv;
-
- if (!scsi_is_host_device(dev))
- return 0;
-
- shost = dev_to_shost(dev);
- if (!shost->transportt ||
- shost->transportt->host_attrs.ac.class != &iscsi_host_class.class)
- return 0;
-
- priv = to_iscsi_internal(shost->transportt);
- return &priv->t.host_attrs.ac == cont;
-}
-
-struct scsi_transport_template *
-iscsi_register_transport(struct iscsi_transport *tt)
-{
- struct iscsi_internal *priv;
- unsigned long flags;
- int count = 0, err;
-
- BUG_ON(!tt);
-
- priv = iscsi_if_transport_lookup(tt);
- if (priv)
- return NULL;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return NULL;
- INIT_LIST_HEAD(&priv->list);
- priv->iscsi_transport = tt;
- priv->t.user_scan = iscsi_user_scan;
- priv->t.create_work_queue = 1;
-
- priv->dev.class = &iscsi_transport_class;
- dev_set_name(&priv->dev, "%s", tt->name);
- err = device_register(&priv->dev);
- if (err)
- goto free_priv;
-
- err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
- if (err)
- goto unregister_dev;
-
- /* host parameters */
- priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
- priv->t.host_attrs.ac.class = &iscsi_host_class.class;
- priv->t.host_attrs.ac.match = iscsi_host_match;
- priv->t.host_size = sizeof(struct iscsi_cls_host);
- transport_container_register(&priv->t.host_attrs);
-
- SETUP_HOST_RD_ATTR(netdev, ISCSI_HOST_NETDEV_NAME);
- SETUP_HOST_RD_ATTR(ipaddress, ISCSI_HOST_IPADDRESS);
- SETUP_HOST_RD_ATTR(hwaddress, ISCSI_HOST_HWADDRESS);
- SETUP_HOST_RD_ATTR(initiatorname, ISCSI_HOST_INITIATOR_NAME);
- BUG_ON(count > ISCSI_HOST_ATTRS);
- priv->host_attrs[count] = NULL;
- count = 0;
-
- /* connection parameters */
- priv->conn_cont.ac.attrs = &priv->conn_attrs[0];
- priv->conn_cont.ac.class = &iscsi_connection_class.class;
- priv->conn_cont.ac.match = iscsi_conn_match;
- transport_container_register(&priv->conn_cont);
-
- SETUP_CONN_RD_ATTR(max_recv_dlength, ISCSI_MAX_RECV_DLENGTH);
- SETUP_CONN_RD_ATTR(max_xmit_dlength, ISCSI_MAX_XMIT_DLENGTH);
- SETUP_CONN_RD_ATTR(header_digest, ISCSI_HDRDGST_EN);
- SETUP_CONN_RD_ATTR(data_digest, ISCSI_DATADGST_EN);
- SETUP_CONN_RD_ATTR(ifmarker, ISCSI_IFMARKER_EN);
- SETUP_CONN_RD_ATTR(ofmarker, ISCSI_OFMARKER_EN);
- SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS);
- SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT);
- SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);
- SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
- SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
- SETUP_CONN_RD_ATTR(ping_tmo, ISCSI_PING_TMO);
- SETUP_CONN_RD_ATTR(recv_tmo, ISCSI_RECV_TMO);
-
- BUG_ON(count > ISCSI_CONN_ATTRS);
- priv->conn_attrs[count] = NULL;
- count = 0;
-
- /* session parameters */
- priv->session_cont.ac.attrs = &priv->session_attrs[0];
- priv->session_cont.ac.class = &iscsi_session_class.class;
- priv->session_cont.ac.match = iscsi_session_match;
- transport_container_register(&priv->session_cont);
-
- SETUP_SESSION_RD_ATTR(initial_r2t, ISCSI_INITIAL_R2T_EN);
- SETUP_SESSION_RD_ATTR(max_outstanding_r2t, ISCSI_MAX_R2T);
- SETUP_SESSION_RD_ATTR(immediate_data, ISCSI_IMM_DATA_EN);
- SETUP_SESSION_RD_ATTR(first_burst_len, ISCSI_FIRST_BURST);
- SETUP_SESSION_RD_ATTR(max_burst_len, ISCSI_MAX_BURST);
- SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN);
- SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN);
- SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL);
- SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
- SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT);
- SETUP_SESSION_RD_ATTR(password, ISCSI_USERNAME);
- SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN);
- SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD);
- SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN);
- SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT);
- SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO);
- SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO);
- SETUP_SESSION_RD_ATTR(tgt_reset_tmo,ISCSI_TGT_RESET_TMO);
- SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME);
- SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME);
- SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
- SETUP_PRIV_SESSION_RD_ATTR(state);
-
- BUG_ON(count > ISCSI_SESSION_ATTRS);
- priv->session_attrs[count] = NULL;
-
- spin_lock_irqsave(&iscsi_transport_lock, flags);
- list_add(&priv->list, &iscsi_transports);
- spin_unlock_irqrestore(&iscsi_transport_lock, flags);
-
- printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
- return &priv->t;
-
-unregister_dev:
- device_unregister(&priv->dev);
- return NULL;
-free_priv:
- kfree(priv);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(iscsi_register_transport);
-
-int iscsi_unregister_transport(struct iscsi_transport *tt)
-{
- struct iscsi_internal *priv;
- unsigned long flags;
-
- BUG_ON(!tt);
-
- mutex_lock(&rx_queue_mutex);
-
- priv = iscsi_if_transport_lookup(tt);
- BUG_ON (!priv);
-
- spin_lock_irqsave(&iscsi_transport_lock, flags);
- list_del(&priv->list);
- spin_unlock_irqrestore(&iscsi_transport_lock, flags);
-
- transport_container_unregister(&priv->conn_cont);
- transport_container_unregister(&priv->session_cont);
- transport_container_unregister(&priv->t.host_attrs);
-
- sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
- device_unregister(&priv->dev);
- mutex_unlock(&rx_queue_mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_unregister_transport);
-
-static __init int iscsi_transport_init(void)
-{
- int err;
-
- printk(KERN_INFO "Loading iSCSI transport class v%s.\n",
- ISCSI_TRANSPORT_VERSION);
-
- atomic_set(&iscsi_session_nr, 0);
-
- err = class_register(&iscsi_transport_class);
- if (err)
- return err;
-
- err = class_register(&iscsi_endpoint_class);
- if (err)
- goto unregister_transport_class;
-
- err = transport_class_register(&iscsi_host_class);
- if (err)
- goto unregister_endpoint_class;
-
- err = transport_class_register(&iscsi_connection_class);
- if (err)
- goto unregister_host_class;
-
- err = transport_class_register(&iscsi_session_class);
- if (err)
- goto unregister_conn_class;
-
- nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx,
- NULL, THIS_MODULE);
- if (!nls) {
- err = -ENOBUFS;
- goto unregister_session_class;
- }
-
- iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh");
- if (!iscsi_eh_timer_workq)
- goto release_nls;
-
- return 0;
-
-release_nls:
- netlink_kernel_release(nls);
-unregister_session_class:
- transport_class_unregister(&iscsi_session_class);
-unregister_conn_class:
- transport_class_unregister(&iscsi_connection_class);
-unregister_host_class:
- transport_class_unregister(&iscsi_host_class);
-unregister_endpoint_class:
- class_unregister(&iscsi_endpoint_class);
-unregister_transport_class:
- class_unregister(&iscsi_transport_class);
- return err;
-}
-
-static void __exit iscsi_transport_exit(void)
-{
- destroy_workqueue(iscsi_eh_timer_workq);
- netlink_kernel_release(nls);
- transport_class_unregister(&iscsi_connection_class);
- transport_class_unregister(&iscsi_session_class);
- transport_class_unregister(&iscsi_host_class);
- class_unregister(&iscsi_endpoint_class);
- class_unregister(&iscsi_transport_class);
-}
-
-module_init(iscsi_transport_init);
-module_exit(iscsi_transport_exit);
-
-MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
- "Dmitry Yusupov <dmitry_yus@yahoo.com>, "
- "Alex Aizman <itn780@yahoo.com>");
-MODULE_DESCRIPTION("iSCSI Transport Interface");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(ISCSI_TRANSPORT_VERSION);
diff --git a/kernel/scsi_transport_iscsi.h b/kernel/scsi_transport_iscsi.h
deleted file mode 100644
index e20ad17..0000000
--- a/kernel/scsi_transport_iscsi.h
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * iSCSI transport class definitions
- *
- * Copyright (C) IBM Corporation, 2004
- * Copyright (C) Mike Christie, 2004 - 2006
- * Copyright (C) Dmitry Yusupov, 2004 - 2005
- * Copyright (C) Alex Aizman, 2004 - 2005
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-#ifndef SCSI_TRANSPORT_ISCSI_H
-#define SCSI_TRANSPORT_ISCSI_H
-
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include "iscsi_if.h"
-
-struct scsi_transport_template;
-struct iscsi_transport;
-struct iscsi_endpoint;
-struct Scsi_Host;
-struct iscsi_cls_conn;
-struct iscsi_conn;
-struct iscsi_task;
-struct sockaddr;
-
-/**
- * struct iscsi_transport - iSCSI Transport template
- *
- * @name: transport name
- * @caps: iSCSI Data-Path capabilities
- * @create_session: create new iSCSI session object
- * @destroy_session: destroy existing iSCSI session object
- * @create_conn: create new iSCSI connection
- * @bind_conn: associate this connection with existing iSCSI session
- * and specified transport descriptor
- * @destroy_conn: destroy inactive iSCSI connection
- * @set_param: set iSCSI parameter. Return 0 on success, -ENODATA
- * when param is not supported, and a -Exx value on other
- * error.
- * @get_param get iSCSI parameter. Must return number of bytes
- * copied to buffer on success, -ENODATA when param
- * is not supported, and a -Exx value on other error
- * @start_conn: set connection to be operational
- * @stop_conn: suspend/recover/terminate connection
- * @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text.
- * @session_recovery_timedout: notify LLD a block during recovery timed out
- * @init_task: Initialize an iscsi_task and any internal structs.
- * When offloading the data path, this is called from
- * queuecommand with the session lock, or from the
- * iscsi_conn_send_pdu context with the session lock.
- * When not offloading the data path, this is called
- * from the scsi work queue without the session lock.
- * @xmit_task Requests LLD to transfer cmd task. Returns 0 or the
- * the number of bytes transferred on success, and -Exyz
- * value on error. When offloading the data path, this
- * is called from queuecommand with the session lock, or
- * from the iscsi_conn_send_pdu context with the session
- * lock. When not offloading the data path, this is called
- * from the scsi work queue without the session lock.
- * @cleanup_task: requests LLD to fail task. Called with session lock
- * and after the connection has been suspended and
- * terminated during recovery. If called
- * from abort task then connection is not suspended
- * or terminated but sk_callback_lock is held
- *
- * Template API provided by iSCSI Transport
- */
-struct iscsi_transport {
- struct module *owner;
- char *name;
- unsigned int caps;
- /* LLD sets this to indicate what values it can export to sysfs */
- uint64_t param_mask;
- uint64_t host_param_mask;
- struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep,
- uint16_t cmds_max, uint16_t qdepth,
- uint32_t sn);
- void (*destroy_session) (struct iscsi_cls_session *session);
- struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
- uint32_t cid);
- int (*bind_conn) (struct iscsi_cls_session *session,
- struct iscsi_cls_conn *cls_conn,
- uint64_t transport_eph, int is_leading);
- int (*start_conn) (struct iscsi_cls_conn *conn);
- void (*stop_conn) (struct iscsi_cls_conn *conn, int flag);
- void (*destroy_conn) (struct iscsi_cls_conn *conn);
- int (*set_param) (struct iscsi_cls_conn *conn, enum iscsi_param param,
- char *buf, int buflen);
- int (*get_conn_param) (struct iscsi_cls_conn *conn,
- enum iscsi_param param, char *buf);
- int (*get_session_param) (struct iscsi_cls_session *session,
- enum iscsi_param param, char *buf);
- int (*get_host_param) (struct Scsi_Host *shost,
- enum iscsi_host_param param, char *buf);
- int (*set_host_param) (struct Scsi_Host *shost,
- enum iscsi_host_param param, char *buf,
- int buflen);
- int (*send_pdu) (struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
- char *data, uint32_t data_size);
- void (*get_stats) (struct iscsi_cls_conn *conn,
- struct iscsi_stats *stats);
-
- int (*init_task) (struct iscsi_task *task);
- int (*xmit_task) (struct iscsi_task *task);
- void (*cleanup_task) (struct iscsi_task *task);
-
- int (*alloc_pdu) (struct iscsi_task *task, uint8_t opcode);
- int (*xmit_pdu) (struct iscsi_task *task);
- int (*init_pdu) (struct iscsi_task *task, unsigned int offset,
- unsigned int count);
- void (*parse_pdu_itt) (struct iscsi_conn *conn, itt_t itt,
- int *index, int *age);
-
- void (*session_recovery_timedout) (struct iscsi_cls_session *session);
- struct iscsi_endpoint *(*ep_connect) (struct Scsi_Host *shost,
- struct sockaddr *dst_addr,
- int non_blocking);
- int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms);
- void (*ep_disconnect) (struct iscsi_endpoint *ep);
- int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
- uint32_t enable, struct sockaddr *dst_addr);
- int (*set_path) (struct Scsi_Host *shost, struct iscsi_path *params);
-};
-
-/*
- * transport registration upcalls
- */
-extern struct scsi_transport_template *iscsi_register_transport(struct iscsi_transport *tt);
-extern int iscsi_unregister_transport(struct iscsi_transport *tt);
-
-/*
- * control plane upcalls
- */
-extern void iscsi_conn_error_event(struct iscsi_cls_conn *conn,
- enum iscsi_err error);
-extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
- char *data, uint32_t data_size);
-
-extern int iscsi_offload_mesg(struct Scsi_Host *shost,
- struct iscsi_transport *transport, uint32_t type,
- char *data, uint16_t data_size);
-
-struct iscsi_cls_conn {
- struct list_head conn_list; /* item in connlist */
- void *dd_data; /* LLD private data */
- struct iscsi_transport *transport;
- uint32_t cid; /* connection id */
-
- int active; /* must be accessed with the connlock */
- struct device dev; /* sysfs transport/container device */
-};
-
-#define iscsi_dev_to_conn(_dev) \
- container_of(_dev, struct iscsi_cls_conn, dev)
-
-#define iscsi_conn_to_session(_conn) \
- iscsi_dev_to_session(_conn->dev.parent)
-
-/* iscsi class session state */
-enum {
- ISCSI_SESSION_LOGGED_IN,
- ISCSI_SESSION_FAILED,
- ISCSI_SESSION_FREE,
-};
-
-#define ISCSI_MAX_TARGET -1
-
-struct iscsi_cls_session {
- struct list_head sess_list; /* item in session_list */
- struct iscsi_transport *transport;
- spinlock_t lock;
- struct work_struct block_work;
- struct work_struct unblock_work;
- struct work_struct scan_work;
- struct work_struct unbind_work;
-
- /* recovery fields */
- int recovery_tmo;
- struct delayed_work recovery_work;
-
- unsigned int target_id;
-
- int state;
- int sid; /* session id */
- void *dd_data; /* LLD private data */
- struct device dev; /* sysfs transport/container device */
-};
-
-#define iscsi_dev_to_session(_dev) \
- container_of(_dev, struct iscsi_cls_session, dev)
-
-#define iscsi_session_to_shost(_session) \
- dev_to_shost(_session->dev.parent)
-
-#define starget_to_session(_stgt) \
- iscsi_dev_to_session(_stgt->dev.parent)
-
-struct iscsi_cls_host {
- atomic_t nr_scans;
- struct mutex mutex;
-};
-
-extern void iscsi_host_for_each_session(struct Scsi_Host *shost,
- void (*fn)(struct iscsi_cls_session *));
-
-struct iscsi_endpoint {
- void *dd_data; /* LLD private data */
- struct device dev;
- uint64_t id;
-};
-
-/*
- * session and connection functions that can be used by HW iSCSI LLDs
- */
-#define iscsi_cls_session_printk(prefix, _cls_session, fmt, a...) \
- dev_printk(prefix, &(_cls_session)->dev, fmt, ##a)
-
-#define iscsi_cls_conn_printk(prefix, _cls_conn, fmt, a...) \
- dev_printk(prefix, &(_cls_conn)->dev, fmt, ##a)
-
-extern int iscsi_session_chkready(struct iscsi_cls_session *session);
-extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost,
- struct iscsi_transport *transport, int dd_size);
-extern int iscsi_add_session(struct iscsi_cls_session *session,
- unsigned int target_id);
-extern int iscsi_session_event(struct iscsi_cls_session *session,
- enum iscsi_uevent_e event);
-extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
- struct iscsi_transport *t,
- int dd_size,
- unsigned int target_id);
-extern void iscsi_remove_session(struct iscsi_cls_session *session);
-extern void iscsi_free_session(struct iscsi_cls_session *session);
-extern int iscsi_destroy_session(struct iscsi_cls_session *session);
-extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess,
- int dd_size, uint32_t cid);
-extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn);
-extern void iscsi_unblock_session(struct iscsi_cls_session *session);
-extern void iscsi_block_session(struct iscsi_cls_session *session);
-extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time);
-extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size);
-extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
-extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
-
-#endif