diff options
author | Chris Leech <cleech@redhat.com> | 2018-01-16 16:41:31 -0800 |
---|---|---|
committer | Chris Leech <cleech@redhat.com> | 2018-01-16 17:02:52 -0800 |
commit | e3750e4a38d6e6a3b3e699dad990dee1103f5a68 (patch) | |
tree | e1ec0ffeefb82ef0c7e419ab9b1f78560d56652f | |
parent | c6ae303c2cdd34157dfc3a6dface0a7179e0d401 (diff) | |
download | open-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-- | Makefile | 15 | ||||
-rw-r--r-- | kernel/.gitignore | 11 | ||||
-rw-r--r-- | kernel/2.6.14-19_compat.patch | 1247 | ||||
-rw-r--r-- | kernel/2.6.14-23_compat.patch | 1468 | ||||
-rw-r--r-- | kernel/2.6.16-suse.patch | 864 | ||||
-rw-r--r-- | kernel/2.6.20-21_compat.patch | 1015 | ||||
-rw-r--r-- | kernel/2.6.24_compat.patch | 1177 | ||||
-rw-r--r-- | kernel/2.6.26_compat.patch | 681 | ||||
-rw-r--r-- | kernel/2.6.27_compat.patch | 591 | ||||
-rw-r--r-- | kernel/2.6.28-32_compat.patch | 569 | ||||
-rw-r--r-- | kernel/2.6.33-34_compat.patch | 297 | ||||
-rw-r--r-- | kernel/Makefile | 229 | ||||
-rw-r--r-- | kernel/iscsi_tcp.c | 980 | ||||
-rw-r--r-- | kernel/iscsi_tcp.h | 64 | ||||
-rw-r--r-- | kernel/libiscsi.c | 3462 | ||||
-rw-r--r-- | kernel/libiscsi.h | 450 | ||||
-rw-r--r-- | kernel/libiscsi_tcp.c | 1184 | ||||
-rw-r--r-- | kernel/libiscsi_tcp.h | 133 | ||||
-rw-r--r-- | kernel/scsi_transport_iscsi.c | 2135 | ||||
-rw-r--r-- | kernel/scsi_transport_iscsi.h | 259 |
20 files changed, 1 insertions, 16830 deletions
@@ -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 |