[ewg] [PATCH] iscsi backport for OFED1.4

Doron Shoham dorons at voltaire.com
Sun Jun 29 06:34:39 PDT 2008


Hi Vlad,
This is patch will resolve the compilation errors
of sles10 and redhat5

Thanks,
Doron

Signed-off-by: Doron Shoham <dorons at voltaire.com>
---
 ...1_sync_kernel_code_with_release_2.0-869.2.patch |  646 ++++++++
 .../iscsi_02_count_fmr_align_violations.patch      |   24 +
 ...scsi_03_copmat_patch_for_RHEL5_and_SLES10.patch |  151 ++
 ...1_sync_kernel_code_with_release_2.0-869.2.patch |  646 ++++++++
 .../iscsi_02_count_fmr_align_violations.patch      |   24 +
 ...scsi_03_copmat_patch_for_RHEL5_and_SLES10.patch |  151 ++
 ...1_sync_kernel_code_with_release_2.0-869.2.patch |  646 ++++++++
 .../iscsi_02_count_fmr_align_violations.patch      |   24 +
 ...scsi_03_copmat_patch_for_RHEL5_and_SLES10.patch |  151 ++
 ...1_sync_kernel_code_with_release_2.0-869.2.patch |  646 ++++++++
 .../iscsi_02_count_fmr_align_violations.patch      |   24 +
 ...scsi_03_copmat_patch_for_RHEL5_and_SLES10.patch |  151 ++
 ...1_sync_kernel_code_with_release_2.0-869.2.patch |  646 ++++++++
 .../iscsi_02_count_fmr_align_violations.patch      |   24 +
 ...scsi_03_copmat_patch_for_RHEL5_and_SLES10.patch |  151 ++
 ...1_sync_kernel_code_with_release_2.0-869.2.patch |  646 ++++++++
 .../iscsi_02_count_fmr_align_violations.patch      |   24 +
 ...scsi_03_copmat_patch_for_RHEL5_and_SLES10.patch |  151 ++
 20 files changed, 4928 insertions(+), 1786 deletions(-)
 create mode 100644 kernel_patches/backport/2.6.16_sles10/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
 create mode 100644 kernel_patches/backport/2.6.16_sles10/iscsi_02_count_fmr_align_violations.patch
 create mode 100644 kernel_patches/backport/2.6.16_sles10/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
 create mode 100644 kernel_patches/backport/2.6.16_sles10_sp1/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
 create mode 100644 kernel_patches/backport/2.6.16_sles10_sp1/iscsi_02_count_fmr_align_violations.patch
 create mode 100644 kernel_patches/backport/2.6.16_sles10_sp1/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
 create mode 100644 kernel_patches/backport/2.6.16_sles10_sp2/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
 create mode 100644 kernel_patches/backport/2.6.16_sles10_sp2/iscsi_02_count_fmr_align_violations.patch
 create mode 100644 kernel_patches/backport/2.6.16_sles10_sp2/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
 create mode 100644 kernel_patches/backport/2.6.18-EL5.1/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
 create mode 100644 kernel_patches/backport/2.6.18-EL5.1/iscsi_02_count_fmr_align_violations.patch
 create mode 100644 kernel_patches/backport/2.6.18-EL5.1/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
 create mode 100644 kernel_patches/backport/2.6.18-EL5.2/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
 create mode 100644 kernel_patches/backport/2.6.18-EL5.2/iscsi_02_count_fmr_align_violations.patch
 create mode 100644 kernel_patches/backport/2.6.18-EL5.2/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
 create mode 100644 kernel_patches/backport/2.6.18_FC6/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
 create mode 100644 kernel_patches/backport/2.6.18_FC6/iscsi_02_count_fmr_align_violations.patch
 create mode 100644 kernel_patches/backport/2.6.18_FC6/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch

diff --git a/kernel_patches/backport/2.6.16_sles10/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch b/kernel_patches/backport/2.6.16_sles10/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
new file mode 100644
index 0000000..80375a9
--- /dev/null
+++ b/kernel_patches/backport/2.6.16_sles10/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
@@ -0,0 +1,646 @@
+From d7020ef2830f00c127770c63ad5d3c11cacd6685 Mon Sep 17 00:00:00 2001
+From: Doron Shoham <dorons at voltaire.com>
+Date: Thu, 19 Jun 2008 11:33:20 +0300
+Subject: [PATCH 1/1] scsi_01_sync_kernel_code_with_release_2.0-869.2.patch
+
+Signed-off-by: Doron Shoham <dorons at voltaire.com>
+---
+ drivers/scsi/iscsi_tcp.c            |   31 ++++----
+ drivers/scsi/libiscsi.c             |  140 +++++------------------------------
+ drivers/scsi/scsi_transport_iscsi.c |  107 +++++++++++++--------------
+ include/scsi/libiscsi.h             |    1 -
+ 4 files changed, 86 insertions(+), 193 deletions(-)
+
+diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
+index 72b9b2a..8a17867 100644
+--- a/drivers/scsi/iscsi_tcp.c
++++ b/drivers/scsi/iscsi_tcp.c
+@@ -528,7 +528,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	struct iscsi_session *session = conn->session;
+ 	struct scsi_cmnd *sc = ctask->sc;
+ 	int datasn = be32_to_cpu(rhdr->datasn);
+-	unsigned total_in_length = scsi_in(sc)->length;
+ 
+ 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
+ 	if (tcp_conn->in.datalen == 0)
+@@ -543,10 +542,10 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	tcp_ctask->exp_datasn++;
+ 
+ 	tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
+-	if (tcp_ctask->data_offset + tcp_conn->in.datalen > total_in_length) {
++	if (tcp_ctask->data_offset + tcp_conn->in.datalen > scsi_bufflen(sc)) {
+ 		debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n",
+ 		          __FUNCTION__, tcp_ctask->data_offset,
+-		          tcp_conn->in.datalen, total_in_length);
++		          tcp_conn->in.datalen, scsi_bufflen(sc));
+ 		return ISCSI_ERR_DATA_OFFSET;
+ 	}
+ 
+@@ -559,8 +558,8 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 
+ 			if (res_count > 0 &&
+ 			    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+-			     res_count <= total_in_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;
+@@ -671,11 +670,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 			    r2t->data_length, session->max_burst);
+ 
+ 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
+-	if (r2t->data_offset + r2t->data_length > scsi_out(ctask->sc)->length) {
++	if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
+ 		iscsi_conn_printk(KERN_ERR, conn,
+ 				  "invalid R2T with data len %u at offset %u "
+ 				  "and total length %d\n", r2t->data_length,
+-				  r2t->data_offset, scsi_out(ctask->sc)->length);
++				  r2t->data_offset, scsi_bufflen(ctask->sc));
+ 		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+ 			    sizeof(void*));
+ 		return ISCSI_ERR_DATALEN;
+@@ -772,7 +771,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 		if (tcp_conn->in.datalen) {
+ 			struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 			struct hash_desc *rx_hash = NULL;
+-			struct scsi_data_buffer *sdb = scsi_in(ctask->sc);
+ 
+ 			/*
+ 			 * Setup copy of Data-In into the Scsi_Cmnd
+@@ -790,8 +788,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 				  tcp_ctask->data_offset,
+ 				  tcp_conn->in.datalen);
+ 			return iscsi_segment_seek_sg(&tcp_conn->in.segment,
+-						     sdb->table.sgl,
+-						     sdb->table.nents,
++						     scsi_sglist(ctask->sc),
++						     scsi_sg_count(ctask->sc),
+ 						     tcp_ctask->data_offset,
+ 						     tcp_conn->in.datalen,
+ 						     iscsi_tcp_process_data_in,
+@@ -1334,8 +1332,7 @@ iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask)
+ 		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, ctask->imm_count);
+ 	if (err)
+ 		return err;
+@@ -1389,7 +1386,6 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ {
+ 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 	struct scsi_cmnd *sc = ctask->sc;
+-	struct scsi_data_buffer *sdb = scsi_out(sc);
+ 	int rc = 0;
+ 
+ flush:
+@@ -1416,8 +1412,9 @@ flush:
+ 				ctask->itt, tcp_ctask->sent, ctask->data_count);
+ 
+ 		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
+-		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
+-					      sdb->table.nents, tcp_ctask->sent,
++		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
++					      scsi_sg_count(sc),
++					      tcp_ctask->sent,
+ 					      ctask->data_count);
+ 		if (rc)
+ 			goto fail;
+@@ -1463,8 +1460,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)
+diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
+index b43bf1d..9975095 100644
+--- a/drivers/scsi/libiscsi.c
++++ b/drivers/scsi/libiscsi.c
+@@ -137,70 +137,6 @@ static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
+ 	return 0;
+ }
+ 
+-/*
+- * make an extended cdb AHS
+- */
+-static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask)
+-{
+-	struct scsi_cmnd *cmd = ctask->sc;
+-	unsigned rlen, pad_len;
+-	unsigned short ahslength;
+-	struct iscsi_ecdb_ahdr *ecdb_ahdr;
+-	int rc;
+-
+-	ecdb_ahdr = iscsi_next_hdr(ctask);
+-	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(ctask, sizeof(ecdb_ahdr->ahslength) +
+-	                   sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len);
+-	if (rc)
+-		return rc;
+-
+-	if (pad_len)
+-		memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
+-
+-	ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
+-	ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
+-	ecdb_ahdr->reserved = 0;
+-	memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
+-
+-	debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
+-		   "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n",
+-		   cmd->cmd_len, rlen, pad_len, ahslength, ctask->hdr_len);
+-
+-	return 0;
+-}
+-
+-static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask)
+-{
+-	struct scsi_cmnd *sc = ctask->sc;
+-	struct iscsi_rlength_ahdr *rlen_ahdr;
+-	int rc;
+-
+-	rlen_ahdr = iscsi_next_hdr(ctask);
+-	rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr));
+-	if (rc)
+-		return rc;
+-
+-	rlen_ahdr->ahslength =
+-		cpu_to_be16(sizeof(rlen_ahdr->read_length) +
+-						  sizeof(rlen_ahdr->reserved));
+-	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
+-	rlen_ahdr->reserved = 0;
+-	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
+-
+-	debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
+-		   "rlen_ahdr->ahslength(%d)\n",
+-		   be32_to_cpu(rlen_ahdr->read_length),
+-		   be16_to_cpu(rlen_ahdr->ahslength));
+-	return 0;
+-}
+-
+ /**
+  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
+  * @ctask: iscsi cmd task
+@@ -214,7 +150,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	struct iscsi_session *session = conn->session;
+ 	struct iscsi_cmd *hdr = ctask->hdr;
+ 	struct scsi_cmnd *sc = ctask->sc;
+-	unsigned hdrlength, cmd_len;
++	unsigned hdrlength;
+ 	int rc;
+ 
+ 	ctask->hdr_len = 0;
+@@ -225,30 +161,17 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	hdr->flags = ISCSI_ATTR_SIMPLE;
+ 	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
+ 	hdr->itt = build_itt(ctask->itt, session->age);
++	hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
+ 	hdr->cmdsn = cpu_to_be32(session->cmdsn);
+ 	session->cmdsn++;
+ 	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
+-	cmd_len = sc->cmd_len;
+-	if (cmd_len < ISCSI_CDB_SIZE)
+-		memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len);
+-	else if (cmd_len > ISCSI_CDB_SIZE) {
+-		rc = iscsi_prep_ecdb_ahs(ctask);
+-		if (rc)
+-			return rc;
+-		cmd_len = ISCSI_CDB_SIZE;
+-	}
+-	memcpy(hdr->cdb, sc->cmnd, cmd_len);
++	memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
++	if (sc->cmd_len < MAX_COMMAND_SIZE)
++		memset(&hdr->cdb[sc->cmd_len], 0,
++			MAX_COMMAND_SIZE - sc->cmd_len);
+ 
+ 	ctask->imm_count = 0;
+-	if (scsi_bidi_cmnd(sc)) {
+-		hdr->flags |= ISCSI_FLAG_CMD_READ;
+-		rc = iscsi_prep_bidi_ahs(ctask);
+-		if (rc)
+-			return rc;
+-	}
+ 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
+-		unsigned out_len = scsi_out(sc)->length;
+-		hdr->data_length = cpu_to_be32(out_len);
+ 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
+ 		/*
+ 		 * Write counters:
+@@ -269,19 +192,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 		ctask->unsol_datasn = 0;
+ 
+ 		if (session->imm_data_en) {
+-			if (out_len >= session->first_burst)
++			if (scsi_bufflen(sc) >= session->first_burst)
+ 				ctask->imm_count = min(session->first_burst,
+ 							conn->max_xmit_dlength);
+ 			else
+-				ctask->imm_count = min(out_len,
++				ctask->imm_count = min(scsi_bufflen(sc),
+ 							conn->max_xmit_dlength);
+ 			hton24(hdr->dlength, ctask->imm_count);
+ 		} else
+ 			zero_data(hdr->dlength);
+ 
+ 		if (!session->initial_r2t_en) {
+-			ctask->unsol_count = min(session->first_burst, out_len)
+-							     - ctask->imm_count;
++			ctask->unsol_count = min((session->first_burst),
++				(scsi_bufflen(sc))) - ctask->imm_count;
+ 			ctask->unsol_offset = ctask->imm_count;
+ 		}
+ 
+@@ -291,7 +214,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	} 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;
+@@ -310,12 +232,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 		return EIO;
+ 
+ 	conn->scsicmd_pdus_cnt++;
+-	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x "
+-		"len %d bidi_len %d cmdsn %d win %d]\n",
+-		scsi_bidi_cmnd(sc) ? "bidirectional" :
+-		     sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+-		conn->id, sc, sc->cmnd[0], ctask->itt,
+-		scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
++	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
++		"cmdsn %d win %d]\n",
++		sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
++		conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
+ 		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+ 	return 0;
+ }
+@@ -378,12 +298,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ 		conn->session->tt->cleanup_cmd_task(conn, ctask);
+ 
+ 	sc->result = err;
+-	if (!scsi_bidi_cmnd(sc))
+-		scsi_set_resid(sc, scsi_bufflen(sc));
+-	else {
+-		scsi_out(sc)->resid = scsi_out(sc)->length;
+-		scsi_in(sc)->resid = scsi_in(sc)->length;
+-	}
++	scsi_set_resid(sc, scsi_bufflen(sc));
+ 	if (conn->ctask == ctask)
+ 		conn->ctask = NULL;
+ 	/* release ref from queuecommand */
+@@ -518,18 +433,6 @@ invalid_datalen:
+ 			   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);
+@@ -537,11 +440,13 @@ invalid_datalen:
+ 		if (res_count > 0 &&
+ 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+ 		     res_count <= scsi_bufflen(sc)))
+-			/* write side for bidi or uni-io set_resid */
+ 			scsi_set_resid(sc, res_count);
+ 		else
+ 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
+-	}
++	} else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
++	                          ISCSI_FLAG_CMD_BIDI_OVERFLOW))
++		sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
++
+ out:
+ 	debug_scsi("done [sc %lx res %d itt 0x%x]\n",
+ 		   (long)sc, sc->result, ctask->itt);
+@@ -1199,12 +1104,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));
+ 	sc->scsi_done(sc);
+ 	spin_lock(host->host_lock);
+ 	return 0;
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index 65d1737..ca7bb6f 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -40,13 +40,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 */
+@@ -63,12 +63,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);
+ }
+ 
+@@ -78,27 +78,25 @@ 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");
+ show_transport_attr(max_lun, "%d");
+@@ -106,11 +104,11 @@ show_transport_attr(max_conn, "%d");
+ show_transport_attr(max_cmd_len, "%d");
+ 
+ static struct attribute *iscsi_transport_attrs[] = {
+-	&dev_attr_handle.attr,
+-	&dev_attr_caps.attr,
+-	&dev_attr_max_lun.attr,
+-	&dev_attr_max_conn.attr,
+-	&dev_attr_max_cmd_len.attr,
++	&class_device_attr_handle.attr,
++	&class_device_attr_caps.attr,
++	&class_device_attr_max_lun.attr,
++	&class_device_attr_max_conn.attr,
++	&class_device_attr_max_cmd_len.attr,
+ 	NULL,
+ };
+ 
+@@ -121,7 +119,7 @@ static struct attribute_group iscsi_transport_group = {
+ 
+ 
+ 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_host *ihost = shost->shost_data;
+@@ -141,7 +139,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_host *ihost = shost->shost_data;
+@@ -1339,8 +1337,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)
+ 
+ /*
+@@ -1348,10 +1349,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);			\
+ }
+@@ -1375,16 +1375,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))				\
+@@ -1416,10 +1417,9 @@ iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
+ iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 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,
+@@ -1427,11 +1427,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);		\
+ }
+ 
+@@ -1446,10 +1444,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); \
+ }
+@@ -1466,7 +1463,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)
+ 
+@@ -1474,7 +1471,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)
+@@ -1482,7 +1479,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)
+@@ -1490,7 +1487,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)
+@@ -1581,15 +1578,15 @@ iscsi_register_transport(struct iscsi_transport *tt)
+ 	priv->iscsi_transport = tt;
+ 	priv->t.user_scan = iscsi_user_scan;
+ 
+-	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];
+@@ -1666,8 +1663,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);
+ free_priv:
+ 	kfree(priv);
+ 	return NULL;
+@@ -1694,8 +1691,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/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index cd3ca63..7b90b63 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -225,7 +225,6 @@ struct iscsi_conn {
+ 
+ 	/* custom statistics */
+ 	uint32_t		eh_abort_cnt;
+-	uint32_t		fmr_unalign_cnt;
+ };
+ 
+ struct iscsi_pool {
+-- 
+1.5.3.8
+
diff --git a/kernel_patches/backport/2.6.16_sles10/iscsi_02_count_fmr_align_violations.patch b/kernel_patches/backport/2.6.16_sles10/iscsi_02_count_fmr_align_violations.patch
new file mode 100644
index 0000000..9bf2d19
--- /dev/null
+++ b/kernel_patches/backport/2.6.16_sles10/iscsi_02_count_fmr_align_violations.patch
@@ -0,0 +1,24 @@
+From 02753dd2caabfe6b1885cb80a8fb8532b416108d Mon Sep 17 00:00:00 2001
+From: Eli Dorfman <elid at voltaire.com>
+Date: Tue, 29 Apr 2008 10:12:39 +0300
+Subject: [PATCH] IB/iSER: Count fmr alignment violations per session
+
+Count fmr alignment violations per session
+as part of the iscsi statistics.
+
+Signed-off-by: Eli Dorfman <elid at voltaire.com>
+diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index 7b90b63..cd3ca63 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -225,6 +225,7 @@ struct iscsi_conn {
+ 
+ 	/* custom statistics */
+ 	uint32_t		eh_abort_cnt;
++	uint32_t		fmr_unalign_cnt;
+ };
+ 
+ struct iscsi_pool {
+-- 
+1.5.5
+
diff --git a/kernel_patches/backport/2.6.16_sles10/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch b/kernel_patches/backport/2.6.16_sles10/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
new file mode 100644
index 0000000..798571f
--- /dev/null
+++ b/kernel_patches/backport/2.6.16_sles10/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
@@ -0,0 +1,151 @@
+From 66ab30f8dadef133bd04bbdcb434a7f742821bed Mon Sep 17 00:00:00 2001
+From: Doron Shoham <dorons at voltaire.com>
+Date: Sun, 29 Jun 2008 15:41:12 +0300
+Subject: [PATCH] copmat patch for RHEL5 and SLES10
+
+Signed-off-by: Doron Shoham <dorons at voltaire.com>
+---
+ drivers/scsi/scsi_transport_iscsi.c |   93 ++++++++++++++++++++---------------
+ 1 files changed, 54 insertions(+), 39 deletions(-)
+
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index ca7bb6f..0ccd7e2 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -20,6 +20,8 @@
+  * 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/version.h>
++#include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <net/tcp.h>
+@@ -397,10 +399,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 (shost->hostt->scan_finished) {
+-		if (queue_work(ihost->scan_workq, &session->scan_work))
+-			atomic_inc(&ihost->nr_scans);
+-	}
++#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
+ }
+ 
+ /**
+@@ -1294,45 +1298,56 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+  * Malformed skbs with wrong lengths or invalid creds are not processed.
+  */
+ static void
+-iscsi_if_rx(struct sk_buff *skb)
++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);
+ }
+@@ -1738,7 +1753,7 @@ static __init int iscsi_transport_init(void)
+ 	return 0;
+ 
+ release_nls:
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ unregister_session_class:
+ 	transport_class_unregister(&iscsi_session_class);
+ unregister_conn_class:
+@@ -1753,7 +1768,7 @@ unregister_transport_class:
+ static void __exit iscsi_transport_exit(void)
+ {
+ 	destroy_workqueue(iscsi_eh_timer_workq);
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ 	transport_class_unregister(&iscsi_connection_class);
+ 	transport_class_unregister(&iscsi_session_class);
+ 	transport_class_unregister(&iscsi_host_class);
+-- 
+1.5.3.8
+
diff --git a/kernel_patches/backport/2.6.16_sles10_sp1/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch b/kernel_patches/backport/2.6.16_sles10_sp1/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
new file mode 100644
index 0000000..80375a9
--- /dev/null
+++ b/kernel_patches/backport/2.6.16_sles10_sp1/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
@@ -0,0 +1,646 @@
+From d7020ef2830f00c127770c63ad5d3c11cacd6685 Mon Sep 17 00:00:00 2001
+From: Doron Shoham <dorons at voltaire.com>
+Date: Thu, 19 Jun 2008 11:33:20 +0300
+Subject: [PATCH 1/1] scsi_01_sync_kernel_code_with_release_2.0-869.2.patch
+
+Signed-off-by: Doron Shoham <dorons at voltaire.com>
+---
+ drivers/scsi/iscsi_tcp.c            |   31 ++++----
+ drivers/scsi/libiscsi.c             |  140 +++++------------------------------
+ drivers/scsi/scsi_transport_iscsi.c |  107 +++++++++++++--------------
+ include/scsi/libiscsi.h             |    1 -
+ 4 files changed, 86 insertions(+), 193 deletions(-)
+
+diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
+index 72b9b2a..8a17867 100644
+--- a/drivers/scsi/iscsi_tcp.c
++++ b/drivers/scsi/iscsi_tcp.c
+@@ -528,7 +528,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	struct iscsi_session *session = conn->session;
+ 	struct scsi_cmnd *sc = ctask->sc;
+ 	int datasn = be32_to_cpu(rhdr->datasn);
+-	unsigned total_in_length = scsi_in(sc)->length;
+ 
+ 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
+ 	if (tcp_conn->in.datalen == 0)
+@@ -543,10 +542,10 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	tcp_ctask->exp_datasn++;
+ 
+ 	tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
+-	if (tcp_ctask->data_offset + tcp_conn->in.datalen > total_in_length) {
++	if (tcp_ctask->data_offset + tcp_conn->in.datalen > scsi_bufflen(sc)) {
+ 		debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n",
+ 		          __FUNCTION__, tcp_ctask->data_offset,
+-		          tcp_conn->in.datalen, total_in_length);
++		          tcp_conn->in.datalen, scsi_bufflen(sc));
+ 		return ISCSI_ERR_DATA_OFFSET;
+ 	}
+ 
+@@ -559,8 +558,8 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 
+ 			if (res_count > 0 &&
+ 			    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+-			     res_count <= total_in_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;
+@@ -671,11 +670,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 			    r2t->data_length, session->max_burst);
+ 
+ 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
+-	if (r2t->data_offset + r2t->data_length > scsi_out(ctask->sc)->length) {
++	if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
+ 		iscsi_conn_printk(KERN_ERR, conn,
+ 				  "invalid R2T with data len %u at offset %u "
+ 				  "and total length %d\n", r2t->data_length,
+-				  r2t->data_offset, scsi_out(ctask->sc)->length);
++				  r2t->data_offset, scsi_bufflen(ctask->sc));
+ 		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+ 			    sizeof(void*));
+ 		return ISCSI_ERR_DATALEN;
+@@ -772,7 +771,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 		if (tcp_conn->in.datalen) {
+ 			struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 			struct hash_desc *rx_hash = NULL;
+-			struct scsi_data_buffer *sdb = scsi_in(ctask->sc);
+ 
+ 			/*
+ 			 * Setup copy of Data-In into the Scsi_Cmnd
+@@ -790,8 +788,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 				  tcp_ctask->data_offset,
+ 				  tcp_conn->in.datalen);
+ 			return iscsi_segment_seek_sg(&tcp_conn->in.segment,
+-						     sdb->table.sgl,
+-						     sdb->table.nents,
++						     scsi_sglist(ctask->sc),
++						     scsi_sg_count(ctask->sc),
+ 						     tcp_ctask->data_offset,
+ 						     tcp_conn->in.datalen,
+ 						     iscsi_tcp_process_data_in,
+@@ -1334,8 +1332,7 @@ iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask)
+ 		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, ctask->imm_count);
+ 	if (err)
+ 		return err;
+@@ -1389,7 +1386,6 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ {
+ 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 	struct scsi_cmnd *sc = ctask->sc;
+-	struct scsi_data_buffer *sdb = scsi_out(sc);
+ 	int rc = 0;
+ 
+ flush:
+@@ -1416,8 +1412,9 @@ flush:
+ 				ctask->itt, tcp_ctask->sent, ctask->data_count);
+ 
+ 		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
+-		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
+-					      sdb->table.nents, tcp_ctask->sent,
++		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
++					      scsi_sg_count(sc),
++					      tcp_ctask->sent,
+ 					      ctask->data_count);
+ 		if (rc)
+ 			goto fail;
+@@ -1463,8 +1460,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)
+diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
+index b43bf1d..9975095 100644
+--- a/drivers/scsi/libiscsi.c
++++ b/drivers/scsi/libiscsi.c
+@@ -137,70 +137,6 @@ static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
+ 	return 0;
+ }
+ 
+-/*
+- * make an extended cdb AHS
+- */
+-static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask)
+-{
+-	struct scsi_cmnd *cmd = ctask->sc;
+-	unsigned rlen, pad_len;
+-	unsigned short ahslength;
+-	struct iscsi_ecdb_ahdr *ecdb_ahdr;
+-	int rc;
+-
+-	ecdb_ahdr = iscsi_next_hdr(ctask);
+-	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(ctask, sizeof(ecdb_ahdr->ahslength) +
+-	                   sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len);
+-	if (rc)
+-		return rc;
+-
+-	if (pad_len)
+-		memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
+-
+-	ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
+-	ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
+-	ecdb_ahdr->reserved = 0;
+-	memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
+-
+-	debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
+-		   "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n",
+-		   cmd->cmd_len, rlen, pad_len, ahslength, ctask->hdr_len);
+-
+-	return 0;
+-}
+-
+-static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask)
+-{
+-	struct scsi_cmnd *sc = ctask->sc;
+-	struct iscsi_rlength_ahdr *rlen_ahdr;
+-	int rc;
+-
+-	rlen_ahdr = iscsi_next_hdr(ctask);
+-	rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr));
+-	if (rc)
+-		return rc;
+-
+-	rlen_ahdr->ahslength =
+-		cpu_to_be16(sizeof(rlen_ahdr->read_length) +
+-						  sizeof(rlen_ahdr->reserved));
+-	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
+-	rlen_ahdr->reserved = 0;
+-	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
+-
+-	debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
+-		   "rlen_ahdr->ahslength(%d)\n",
+-		   be32_to_cpu(rlen_ahdr->read_length),
+-		   be16_to_cpu(rlen_ahdr->ahslength));
+-	return 0;
+-}
+-
+ /**
+  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
+  * @ctask: iscsi cmd task
+@@ -214,7 +150,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	struct iscsi_session *session = conn->session;
+ 	struct iscsi_cmd *hdr = ctask->hdr;
+ 	struct scsi_cmnd *sc = ctask->sc;
+-	unsigned hdrlength, cmd_len;
++	unsigned hdrlength;
+ 	int rc;
+ 
+ 	ctask->hdr_len = 0;
+@@ -225,30 +161,17 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	hdr->flags = ISCSI_ATTR_SIMPLE;
+ 	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
+ 	hdr->itt = build_itt(ctask->itt, session->age);
++	hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
+ 	hdr->cmdsn = cpu_to_be32(session->cmdsn);
+ 	session->cmdsn++;
+ 	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
+-	cmd_len = sc->cmd_len;
+-	if (cmd_len < ISCSI_CDB_SIZE)
+-		memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len);
+-	else if (cmd_len > ISCSI_CDB_SIZE) {
+-		rc = iscsi_prep_ecdb_ahs(ctask);
+-		if (rc)
+-			return rc;
+-		cmd_len = ISCSI_CDB_SIZE;
+-	}
+-	memcpy(hdr->cdb, sc->cmnd, cmd_len);
++	memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
++	if (sc->cmd_len < MAX_COMMAND_SIZE)
++		memset(&hdr->cdb[sc->cmd_len], 0,
++			MAX_COMMAND_SIZE - sc->cmd_len);
+ 
+ 	ctask->imm_count = 0;
+-	if (scsi_bidi_cmnd(sc)) {
+-		hdr->flags |= ISCSI_FLAG_CMD_READ;
+-		rc = iscsi_prep_bidi_ahs(ctask);
+-		if (rc)
+-			return rc;
+-	}
+ 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
+-		unsigned out_len = scsi_out(sc)->length;
+-		hdr->data_length = cpu_to_be32(out_len);
+ 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
+ 		/*
+ 		 * Write counters:
+@@ -269,19 +192,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 		ctask->unsol_datasn = 0;
+ 
+ 		if (session->imm_data_en) {
+-			if (out_len >= session->first_burst)
++			if (scsi_bufflen(sc) >= session->first_burst)
+ 				ctask->imm_count = min(session->first_burst,
+ 							conn->max_xmit_dlength);
+ 			else
+-				ctask->imm_count = min(out_len,
++				ctask->imm_count = min(scsi_bufflen(sc),
+ 							conn->max_xmit_dlength);
+ 			hton24(hdr->dlength, ctask->imm_count);
+ 		} else
+ 			zero_data(hdr->dlength);
+ 
+ 		if (!session->initial_r2t_en) {
+-			ctask->unsol_count = min(session->first_burst, out_len)
+-							     - ctask->imm_count;
++			ctask->unsol_count = min((session->first_burst),
++				(scsi_bufflen(sc))) - ctask->imm_count;
+ 			ctask->unsol_offset = ctask->imm_count;
+ 		}
+ 
+@@ -291,7 +214,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	} 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;
+@@ -310,12 +232,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 		return EIO;
+ 
+ 	conn->scsicmd_pdus_cnt++;
+-	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x "
+-		"len %d bidi_len %d cmdsn %d win %d]\n",
+-		scsi_bidi_cmnd(sc) ? "bidirectional" :
+-		     sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+-		conn->id, sc, sc->cmnd[0], ctask->itt,
+-		scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
++	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
++		"cmdsn %d win %d]\n",
++		sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
++		conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
+ 		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+ 	return 0;
+ }
+@@ -378,12 +298,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ 		conn->session->tt->cleanup_cmd_task(conn, ctask);
+ 
+ 	sc->result = err;
+-	if (!scsi_bidi_cmnd(sc))
+-		scsi_set_resid(sc, scsi_bufflen(sc));
+-	else {
+-		scsi_out(sc)->resid = scsi_out(sc)->length;
+-		scsi_in(sc)->resid = scsi_in(sc)->length;
+-	}
++	scsi_set_resid(sc, scsi_bufflen(sc));
+ 	if (conn->ctask == ctask)
+ 		conn->ctask = NULL;
+ 	/* release ref from queuecommand */
+@@ -518,18 +433,6 @@ invalid_datalen:
+ 			   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);
+@@ -537,11 +440,13 @@ invalid_datalen:
+ 		if (res_count > 0 &&
+ 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+ 		     res_count <= scsi_bufflen(sc)))
+-			/* write side for bidi or uni-io set_resid */
+ 			scsi_set_resid(sc, res_count);
+ 		else
+ 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
+-	}
++	} else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
++	                          ISCSI_FLAG_CMD_BIDI_OVERFLOW))
++		sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
++
+ out:
+ 	debug_scsi("done [sc %lx res %d itt 0x%x]\n",
+ 		   (long)sc, sc->result, ctask->itt);
+@@ -1199,12 +1104,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));
+ 	sc->scsi_done(sc);
+ 	spin_lock(host->host_lock);
+ 	return 0;
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index 65d1737..ca7bb6f 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -40,13 +40,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 */
+@@ -63,12 +63,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);
+ }
+ 
+@@ -78,27 +78,25 @@ 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");
+ show_transport_attr(max_lun, "%d");
+@@ -106,11 +104,11 @@ show_transport_attr(max_conn, "%d");
+ show_transport_attr(max_cmd_len, "%d");
+ 
+ static struct attribute *iscsi_transport_attrs[] = {
+-	&dev_attr_handle.attr,
+-	&dev_attr_caps.attr,
+-	&dev_attr_max_lun.attr,
+-	&dev_attr_max_conn.attr,
+-	&dev_attr_max_cmd_len.attr,
++	&class_device_attr_handle.attr,
++	&class_device_attr_caps.attr,
++	&class_device_attr_max_lun.attr,
++	&class_device_attr_max_conn.attr,
++	&class_device_attr_max_cmd_len.attr,
+ 	NULL,
+ };
+ 
+@@ -121,7 +119,7 @@ static struct attribute_group iscsi_transport_group = {
+ 
+ 
+ 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_host *ihost = shost->shost_data;
+@@ -141,7 +139,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_host *ihost = shost->shost_data;
+@@ -1339,8 +1337,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)
+ 
+ /*
+@@ -1348,10 +1349,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);			\
+ }
+@@ -1375,16 +1375,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))				\
+@@ -1416,10 +1417,9 @@ iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
+ iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 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,
+@@ -1427,11 +1427,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);		\
+ }
+ 
+@@ -1446,10 +1444,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); \
+ }
+@@ -1466,7 +1463,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)
+ 
+@@ -1474,7 +1471,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)
+@@ -1482,7 +1479,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)
+@@ -1490,7 +1487,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)
+@@ -1581,15 +1578,15 @@ iscsi_register_transport(struct iscsi_transport *tt)
+ 	priv->iscsi_transport = tt;
+ 	priv->t.user_scan = iscsi_user_scan;
+ 
+-	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];
+@@ -1666,8 +1663,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);
+ free_priv:
+ 	kfree(priv);
+ 	return NULL;
+@@ -1694,8 +1691,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/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index cd3ca63..7b90b63 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -225,7 +225,6 @@ struct iscsi_conn {
+ 
+ 	/* custom statistics */
+ 	uint32_t		eh_abort_cnt;
+-	uint32_t		fmr_unalign_cnt;
+ };
+ 
+ struct iscsi_pool {
+-- 
+1.5.3.8
+
diff --git a/kernel_patches/backport/2.6.16_sles10_sp1/iscsi_02_count_fmr_align_violations.patch b/kernel_patches/backport/2.6.16_sles10_sp1/iscsi_02_count_fmr_align_violations.patch
new file mode 100644
index 0000000..9bf2d19
--- /dev/null
+++ b/kernel_patches/backport/2.6.16_sles10_sp1/iscsi_02_count_fmr_align_violations.patch
@@ -0,0 +1,24 @@
+From 02753dd2caabfe6b1885cb80a8fb8532b416108d Mon Sep 17 00:00:00 2001
+From: Eli Dorfman <elid at voltaire.com>
+Date: Tue, 29 Apr 2008 10:12:39 +0300
+Subject: [PATCH] IB/iSER: Count fmr alignment violations per session
+
+Count fmr alignment violations per session
+as part of the iscsi statistics.
+
+Signed-off-by: Eli Dorfman <elid at voltaire.com>
+diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index 7b90b63..cd3ca63 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -225,6 +225,7 @@ struct iscsi_conn {
+ 
+ 	/* custom statistics */
+ 	uint32_t		eh_abort_cnt;
++	uint32_t		fmr_unalign_cnt;
+ };
+ 
+ struct iscsi_pool {
+-- 
+1.5.5
+
diff --git a/kernel_patches/backport/2.6.16_sles10_sp1/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch b/kernel_patches/backport/2.6.16_sles10_sp1/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
new file mode 100644
index 0000000..798571f
--- /dev/null
+++ b/kernel_patches/backport/2.6.16_sles10_sp1/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
@@ -0,0 +1,151 @@
+From 66ab30f8dadef133bd04bbdcb434a7f742821bed Mon Sep 17 00:00:00 2001
+From: Doron Shoham <dorons at voltaire.com>
+Date: Sun, 29 Jun 2008 15:41:12 +0300
+Subject: [PATCH] copmat patch for RHEL5 and SLES10
+
+Signed-off-by: Doron Shoham <dorons at voltaire.com>
+---
+ drivers/scsi/scsi_transport_iscsi.c |   93 ++++++++++++++++++++---------------
+ 1 files changed, 54 insertions(+), 39 deletions(-)
+
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index ca7bb6f..0ccd7e2 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -20,6 +20,8 @@
+  * 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/version.h>
++#include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <net/tcp.h>
+@@ -397,10 +399,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 (shost->hostt->scan_finished) {
+-		if (queue_work(ihost->scan_workq, &session->scan_work))
+-			atomic_inc(&ihost->nr_scans);
+-	}
++#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
+ }
+ 
+ /**
+@@ -1294,45 +1298,56 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+  * Malformed skbs with wrong lengths or invalid creds are not processed.
+  */
+ static void
+-iscsi_if_rx(struct sk_buff *skb)
++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);
+ }
+@@ -1738,7 +1753,7 @@ static __init int iscsi_transport_init(void)
+ 	return 0;
+ 
+ release_nls:
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ unregister_session_class:
+ 	transport_class_unregister(&iscsi_session_class);
+ unregister_conn_class:
+@@ -1753,7 +1768,7 @@ unregister_transport_class:
+ static void __exit iscsi_transport_exit(void)
+ {
+ 	destroy_workqueue(iscsi_eh_timer_workq);
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ 	transport_class_unregister(&iscsi_connection_class);
+ 	transport_class_unregister(&iscsi_session_class);
+ 	transport_class_unregister(&iscsi_host_class);
+-- 
+1.5.3.8
+
diff --git a/kernel_patches/backport/2.6.16_sles10_sp2/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch b/kernel_patches/backport/2.6.16_sles10_sp2/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
new file mode 100644
index 0000000..80375a9
--- /dev/null
+++ b/kernel_patches/backport/2.6.16_sles10_sp2/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
@@ -0,0 +1,646 @@
+From d7020ef2830f00c127770c63ad5d3c11cacd6685 Mon Sep 17 00:00:00 2001
+From: Doron Shoham <dorons at voltaire.com>
+Date: Thu, 19 Jun 2008 11:33:20 +0300
+Subject: [PATCH 1/1] scsi_01_sync_kernel_code_with_release_2.0-869.2.patch
+
+Signed-off-by: Doron Shoham <dorons at voltaire.com>
+---
+ drivers/scsi/iscsi_tcp.c            |   31 ++++----
+ drivers/scsi/libiscsi.c             |  140 +++++------------------------------
+ drivers/scsi/scsi_transport_iscsi.c |  107 +++++++++++++--------------
+ include/scsi/libiscsi.h             |    1 -
+ 4 files changed, 86 insertions(+), 193 deletions(-)
+
+diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
+index 72b9b2a..8a17867 100644
+--- a/drivers/scsi/iscsi_tcp.c
++++ b/drivers/scsi/iscsi_tcp.c
+@@ -528,7 +528,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	struct iscsi_session *session = conn->session;
+ 	struct scsi_cmnd *sc = ctask->sc;
+ 	int datasn = be32_to_cpu(rhdr->datasn);
+-	unsigned total_in_length = scsi_in(sc)->length;
+ 
+ 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
+ 	if (tcp_conn->in.datalen == 0)
+@@ -543,10 +542,10 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	tcp_ctask->exp_datasn++;
+ 
+ 	tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
+-	if (tcp_ctask->data_offset + tcp_conn->in.datalen > total_in_length) {
++	if (tcp_ctask->data_offset + tcp_conn->in.datalen > scsi_bufflen(sc)) {
+ 		debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n",
+ 		          __FUNCTION__, tcp_ctask->data_offset,
+-		          tcp_conn->in.datalen, total_in_length);
++		          tcp_conn->in.datalen, scsi_bufflen(sc));
+ 		return ISCSI_ERR_DATA_OFFSET;
+ 	}
+ 
+@@ -559,8 +558,8 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 
+ 			if (res_count > 0 &&
+ 			    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+-			     res_count <= total_in_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;
+@@ -671,11 +670,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 			    r2t->data_length, session->max_burst);
+ 
+ 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
+-	if (r2t->data_offset + r2t->data_length > scsi_out(ctask->sc)->length) {
++	if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
+ 		iscsi_conn_printk(KERN_ERR, conn,
+ 				  "invalid R2T with data len %u at offset %u "
+ 				  "and total length %d\n", r2t->data_length,
+-				  r2t->data_offset, scsi_out(ctask->sc)->length);
++				  r2t->data_offset, scsi_bufflen(ctask->sc));
+ 		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+ 			    sizeof(void*));
+ 		return ISCSI_ERR_DATALEN;
+@@ -772,7 +771,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 		if (tcp_conn->in.datalen) {
+ 			struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 			struct hash_desc *rx_hash = NULL;
+-			struct scsi_data_buffer *sdb = scsi_in(ctask->sc);
+ 
+ 			/*
+ 			 * Setup copy of Data-In into the Scsi_Cmnd
+@@ -790,8 +788,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 				  tcp_ctask->data_offset,
+ 				  tcp_conn->in.datalen);
+ 			return iscsi_segment_seek_sg(&tcp_conn->in.segment,
+-						     sdb->table.sgl,
+-						     sdb->table.nents,
++						     scsi_sglist(ctask->sc),
++						     scsi_sg_count(ctask->sc),
+ 						     tcp_ctask->data_offset,
+ 						     tcp_conn->in.datalen,
+ 						     iscsi_tcp_process_data_in,
+@@ -1334,8 +1332,7 @@ iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask)
+ 		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, ctask->imm_count);
+ 	if (err)
+ 		return err;
+@@ -1389,7 +1386,6 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ {
+ 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 	struct scsi_cmnd *sc = ctask->sc;
+-	struct scsi_data_buffer *sdb = scsi_out(sc);
+ 	int rc = 0;
+ 
+ flush:
+@@ -1416,8 +1412,9 @@ flush:
+ 				ctask->itt, tcp_ctask->sent, ctask->data_count);
+ 
+ 		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
+-		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
+-					      sdb->table.nents, tcp_ctask->sent,
++		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
++					      scsi_sg_count(sc),
++					      tcp_ctask->sent,
+ 					      ctask->data_count);
+ 		if (rc)
+ 			goto fail;
+@@ -1463,8 +1460,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)
+diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
+index b43bf1d..9975095 100644
+--- a/drivers/scsi/libiscsi.c
++++ b/drivers/scsi/libiscsi.c
+@@ -137,70 +137,6 @@ static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
+ 	return 0;
+ }
+ 
+-/*
+- * make an extended cdb AHS
+- */
+-static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask)
+-{
+-	struct scsi_cmnd *cmd = ctask->sc;
+-	unsigned rlen, pad_len;
+-	unsigned short ahslength;
+-	struct iscsi_ecdb_ahdr *ecdb_ahdr;
+-	int rc;
+-
+-	ecdb_ahdr = iscsi_next_hdr(ctask);
+-	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(ctask, sizeof(ecdb_ahdr->ahslength) +
+-	                   sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len);
+-	if (rc)
+-		return rc;
+-
+-	if (pad_len)
+-		memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
+-
+-	ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
+-	ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
+-	ecdb_ahdr->reserved = 0;
+-	memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
+-
+-	debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
+-		   "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n",
+-		   cmd->cmd_len, rlen, pad_len, ahslength, ctask->hdr_len);
+-
+-	return 0;
+-}
+-
+-static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask)
+-{
+-	struct scsi_cmnd *sc = ctask->sc;
+-	struct iscsi_rlength_ahdr *rlen_ahdr;
+-	int rc;
+-
+-	rlen_ahdr = iscsi_next_hdr(ctask);
+-	rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr));
+-	if (rc)
+-		return rc;
+-
+-	rlen_ahdr->ahslength =
+-		cpu_to_be16(sizeof(rlen_ahdr->read_length) +
+-						  sizeof(rlen_ahdr->reserved));
+-	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
+-	rlen_ahdr->reserved = 0;
+-	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
+-
+-	debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
+-		   "rlen_ahdr->ahslength(%d)\n",
+-		   be32_to_cpu(rlen_ahdr->read_length),
+-		   be16_to_cpu(rlen_ahdr->ahslength));
+-	return 0;
+-}
+-
+ /**
+  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
+  * @ctask: iscsi cmd task
+@@ -214,7 +150,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	struct iscsi_session *session = conn->session;
+ 	struct iscsi_cmd *hdr = ctask->hdr;
+ 	struct scsi_cmnd *sc = ctask->sc;
+-	unsigned hdrlength, cmd_len;
++	unsigned hdrlength;
+ 	int rc;
+ 
+ 	ctask->hdr_len = 0;
+@@ -225,30 +161,17 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	hdr->flags = ISCSI_ATTR_SIMPLE;
+ 	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
+ 	hdr->itt = build_itt(ctask->itt, session->age);
++	hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
+ 	hdr->cmdsn = cpu_to_be32(session->cmdsn);
+ 	session->cmdsn++;
+ 	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
+-	cmd_len = sc->cmd_len;
+-	if (cmd_len < ISCSI_CDB_SIZE)
+-		memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len);
+-	else if (cmd_len > ISCSI_CDB_SIZE) {
+-		rc = iscsi_prep_ecdb_ahs(ctask);
+-		if (rc)
+-			return rc;
+-		cmd_len = ISCSI_CDB_SIZE;
+-	}
+-	memcpy(hdr->cdb, sc->cmnd, cmd_len);
++	memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
++	if (sc->cmd_len < MAX_COMMAND_SIZE)
++		memset(&hdr->cdb[sc->cmd_len], 0,
++			MAX_COMMAND_SIZE - sc->cmd_len);
+ 
+ 	ctask->imm_count = 0;
+-	if (scsi_bidi_cmnd(sc)) {
+-		hdr->flags |= ISCSI_FLAG_CMD_READ;
+-		rc = iscsi_prep_bidi_ahs(ctask);
+-		if (rc)
+-			return rc;
+-	}
+ 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
+-		unsigned out_len = scsi_out(sc)->length;
+-		hdr->data_length = cpu_to_be32(out_len);
+ 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
+ 		/*
+ 		 * Write counters:
+@@ -269,19 +192,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 		ctask->unsol_datasn = 0;
+ 
+ 		if (session->imm_data_en) {
+-			if (out_len >= session->first_burst)
++			if (scsi_bufflen(sc) >= session->first_burst)
+ 				ctask->imm_count = min(session->first_burst,
+ 							conn->max_xmit_dlength);
+ 			else
+-				ctask->imm_count = min(out_len,
++				ctask->imm_count = min(scsi_bufflen(sc),
+ 							conn->max_xmit_dlength);
+ 			hton24(hdr->dlength, ctask->imm_count);
+ 		} else
+ 			zero_data(hdr->dlength);
+ 
+ 		if (!session->initial_r2t_en) {
+-			ctask->unsol_count = min(session->first_burst, out_len)
+-							     - ctask->imm_count;
++			ctask->unsol_count = min((session->first_burst),
++				(scsi_bufflen(sc))) - ctask->imm_count;
+ 			ctask->unsol_offset = ctask->imm_count;
+ 		}
+ 
+@@ -291,7 +214,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	} 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;
+@@ -310,12 +232,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 		return EIO;
+ 
+ 	conn->scsicmd_pdus_cnt++;
+-	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x "
+-		"len %d bidi_len %d cmdsn %d win %d]\n",
+-		scsi_bidi_cmnd(sc) ? "bidirectional" :
+-		     sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+-		conn->id, sc, sc->cmnd[0], ctask->itt,
+-		scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
++	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
++		"cmdsn %d win %d]\n",
++		sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
++		conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
+ 		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+ 	return 0;
+ }
+@@ -378,12 +298,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ 		conn->session->tt->cleanup_cmd_task(conn, ctask);
+ 
+ 	sc->result = err;
+-	if (!scsi_bidi_cmnd(sc))
+-		scsi_set_resid(sc, scsi_bufflen(sc));
+-	else {
+-		scsi_out(sc)->resid = scsi_out(sc)->length;
+-		scsi_in(sc)->resid = scsi_in(sc)->length;
+-	}
++	scsi_set_resid(sc, scsi_bufflen(sc));
+ 	if (conn->ctask == ctask)
+ 		conn->ctask = NULL;
+ 	/* release ref from queuecommand */
+@@ -518,18 +433,6 @@ invalid_datalen:
+ 			   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);
+@@ -537,11 +440,13 @@ invalid_datalen:
+ 		if (res_count > 0 &&
+ 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+ 		     res_count <= scsi_bufflen(sc)))
+-			/* write side for bidi or uni-io set_resid */
+ 			scsi_set_resid(sc, res_count);
+ 		else
+ 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
+-	}
++	} else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
++	                          ISCSI_FLAG_CMD_BIDI_OVERFLOW))
++		sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
++
+ out:
+ 	debug_scsi("done [sc %lx res %d itt 0x%x]\n",
+ 		   (long)sc, sc->result, ctask->itt);
+@@ -1199,12 +1104,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));
+ 	sc->scsi_done(sc);
+ 	spin_lock(host->host_lock);
+ 	return 0;
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index 65d1737..ca7bb6f 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -40,13 +40,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 */
+@@ -63,12 +63,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);
+ }
+ 
+@@ -78,27 +78,25 @@ 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");
+ show_transport_attr(max_lun, "%d");
+@@ -106,11 +104,11 @@ show_transport_attr(max_conn, "%d");
+ show_transport_attr(max_cmd_len, "%d");
+ 
+ static struct attribute *iscsi_transport_attrs[] = {
+-	&dev_attr_handle.attr,
+-	&dev_attr_caps.attr,
+-	&dev_attr_max_lun.attr,
+-	&dev_attr_max_conn.attr,
+-	&dev_attr_max_cmd_len.attr,
++	&class_device_attr_handle.attr,
++	&class_device_attr_caps.attr,
++	&class_device_attr_max_lun.attr,
++	&class_device_attr_max_conn.attr,
++	&class_device_attr_max_cmd_len.attr,
+ 	NULL,
+ };
+ 
+@@ -121,7 +119,7 @@ static struct attribute_group iscsi_transport_group = {
+ 
+ 
+ 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_host *ihost = shost->shost_data;
+@@ -141,7 +139,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_host *ihost = shost->shost_data;
+@@ -1339,8 +1337,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)
+ 
+ /*
+@@ -1348,10 +1349,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);			\
+ }
+@@ -1375,16 +1375,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))				\
+@@ -1416,10 +1417,9 @@ iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
+ iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 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,
+@@ -1427,11 +1427,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);		\
+ }
+ 
+@@ -1446,10 +1444,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); \
+ }
+@@ -1466,7 +1463,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)
+ 
+@@ -1474,7 +1471,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)
+@@ -1482,7 +1479,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)
+@@ -1490,7 +1487,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)
+@@ -1581,15 +1578,15 @@ iscsi_register_transport(struct iscsi_transport *tt)
+ 	priv->iscsi_transport = tt;
+ 	priv->t.user_scan = iscsi_user_scan;
+ 
+-	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];
+@@ -1666,8 +1663,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);
+ free_priv:
+ 	kfree(priv);
+ 	return NULL;
+@@ -1694,8 +1691,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/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index cd3ca63..7b90b63 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -225,7 +225,6 @@ struct iscsi_conn {
+ 
+ 	/* custom statistics */
+ 	uint32_t		eh_abort_cnt;
+-	uint32_t		fmr_unalign_cnt;
+ };
+ 
+ struct iscsi_pool {
+-- 
+1.5.3.8
+
diff --git a/kernel_patches/backport/2.6.16_sles10_sp2/iscsi_02_count_fmr_align_violations.patch b/kernel_patches/backport/2.6.16_sles10_sp2/iscsi_02_count_fmr_align_violations.patch
new file mode 100644
index 0000000..9bf2d19
--- /dev/null
+++ b/kernel_patches/backport/2.6.16_sles10_sp2/iscsi_02_count_fmr_align_violations.patch
@@ -0,0 +1,24 @@
+From 02753dd2caabfe6b1885cb80a8fb8532b416108d Mon Sep 17 00:00:00 2001
+From: Eli Dorfman <elid at voltaire.com>
+Date: Tue, 29 Apr 2008 10:12:39 +0300
+Subject: [PATCH] IB/iSER: Count fmr alignment violations per session
+
+Count fmr alignment violations per session
+as part of the iscsi statistics.
+
+Signed-off-by: Eli Dorfman <elid at voltaire.com>
+diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index 7b90b63..cd3ca63 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -225,6 +225,7 @@ struct iscsi_conn {
+ 
+ 	/* custom statistics */
+ 	uint32_t		eh_abort_cnt;
++	uint32_t		fmr_unalign_cnt;
+ };
+ 
+ struct iscsi_pool {
+-- 
+1.5.5
+
diff --git a/kernel_patches/backport/2.6.16_sles10_sp2/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch b/kernel_patches/backport/2.6.16_sles10_sp2/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
new file mode 100644
index 0000000..798571f
--- /dev/null
+++ b/kernel_patches/backport/2.6.16_sles10_sp2/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
@@ -0,0 +1,151 @@
+From 66ab30f8dadef133bd04bbdcb434a7f742821bed Mon Sep 17 00:00:00 2001
+From: Doron Shoham <dorons at voltaire.com>
+Date: Sun, 29 Jun 2008 15:41:12 +0300
+Subject: [PATCH] copmat patch for RHEL5 and SLES10
+
+Signed-off-by: Doron Shoham <dorons at voltaire.com>
+---
+ drivers/scsi/scsi_transport_iscsi.c |   93 ++++++++++++++++++++---------------
+ 1 files changed, 54 insertions(+), 39 deletions(-)
+
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index ca7bb6f..0ccd7e2 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -20,6 +20,8 @@
+  * 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/version.h>
++#include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <net/tcp.h>
+@@ -397,10 +399,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 (shost->hostt->scan_finished) {
+-		if (queue_work(ihost->scan_workq, &session->scan_work))
+-			atomic_inc(&ihost->nr_scans);
+-	}
++#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
+ }
+ 
+ /**
+@@ -1294,45 +1298,56 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+  * Malformed skbs with wrong lengths or invalid creds are not processed.
+  */
+ static void
+-iscsi_if_rx(struct sk_buff *skb)
++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);
+ }
+@@ -1738,7 +1753,7 @@ static __init int iscsi_transport_init(void)
+ 	return 0;
+ 
+ release_nls:
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ unregister_session_class:
+ 	transport_class_unregister(&iscsi_session_class);
+ unregister_conn_class:
+@@ -1753,7 +1768,7 @@ unregister_transport_class:
+ static void __exit iscsi_transport_exit(void)
+ {
+ 	destroy_workqueue(iscsi_eh_timer_workq);
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ 	transport_class_unregister(&iscsi_connection_class);
+ 	transport_class_unregister(&iscsi_session_class);
+ 	transport_class_unregister(&iscsi_host_class);
+-- 
+1.5.3.8
+
diff --git a/kernel_patches/backport/2.6.18-EL5.1/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch b/kernel_patches/backport/2.6.18-EL5.1/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
new file mode 100644
index 0000000..80375a9
--- /dev/null
+++ b/kernel_patches/backport/2.6.18-EL5.1/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
@@ -0,0 +1,646 @@
+From d7020ef2830f00c127770c63ad5d3c11cacd6685 Mon Sep 17 00:00:00 2001
+From: Doron Shoham <dorons at voltaire.com>
+Date: Thu, 19 Jun 2008 11:33:20 +0300
+Subject: [PATCH 1/1] scsi_01_sync_kernel_code_with_release_2.0-869.2.patch
+
+Signed-off-by: Doron Shoham <dorons at voltaire.com>
+---
+ drivers/scsi/iscsi_tcp.c            |   31 ++++----
+ drivers/scsi/libiscsi.c             |  140 +++++------------------------------
+ drivers/scsi/scsi_transport_iscsi.c |  107 +++++++++++++--------------
+ include/scsi/libiscsi.h             |    1 -
+ 4 files changed, 86 insertions(+), 193 deletions(-)
+
+diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
+index 72b9b2a..8a17867 100644
+--- a/drivers/scsi/iscsi_tcp.c
++++ b/drivers/scsi/iscsi_tcp.c
+@@ -528,7 +528,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	struct iscsi_session *session = conn->session;
+ 	struct scsi_cmnd *sc = ctask->sc;
+ 	int datasn = be32_to_cpu(rhdr->datasn);
+-	unsigned total_in_length = scsi_in(sc)->length;
+ 
+ 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
+ 	if (tcp_conn->in.datalen == 0)
+@@ -543,10 +542,10 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	tcp_ctask->exp_datasn++;
+ 
+ 	tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
+-	if (tcp_ctask->data_offset + tcp_conn->in.datalen > total_in_length) {
++	if (tcp_ctask->data_offset + tcp_conn->in.datalen > scsi_bufflen(sc)) {
+ 		debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n",
+ 		          __FUNCTION__, tcp_ctask->data_offset,
+-		          tcp_conn->in.datalen, total_in_length);
++		          tcp_conn->in.datalen, scsi_bufflen(sc));
+ 		return ISCSI_ERR_DATA_OFFSET;
+ 	}
+ 
+@@ -559,8 +558,8 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 
+ 			if (res_count > 0 &&
+ 			    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+-			     res_count <= total_in_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;
+@@ -671,11 +670,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 			    r2t->data_length, session->max_burst);
+ 
+ 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
+-	if (r2t->data_offset + r2t->data_length > scsi_out(ctask->sc)->length) {
++	if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
+ 		iscsi_conn_printk(KERN_ERR, conn,
+ 				  "invalid R2T with data len %u at offset %u "
+ 				  "and total length %d\n", r2t->data_length,
+-				  r2t->data_offset, scsi_out(ctask->sc)->length);
++				  r2t->data_offset, scsi_bufflen(ctask->sc));
+ 		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+ 			    sizeof(void*));
+ 		return ISCSI_ERR_DATALEN;
+@@ -772,7 +771,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 		if (tcp_conn->in.datalen) {
+ 			struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 			struct hash_desc *rx_hash = NULL;
+-			struct scsi_data_buffer *sdb = scsi_in(ctask->sc);
+ 
+ 			/*
+ 			 * Setup copy of Data-In into the Scsi_Cmnd
+@@ -790,8 +788,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 				  tcp_ctask->data_offset,
+ 				  tcp_conn->in.datalen);
+ 			return iscsi_segment_seek_sg(&tcp_conn->in.segment,
+-						     sdb->table.sgl,
+-						     sdb->table.nents,
++						     scsi_sglist(ctask->sc),
++						     scsi_sg_count(ctask->sc),
+ 						     tcp_ctask->data_offset,
+ 						     tcp_conn->in.datalen,
+ 						     iscsi_tcp_process_data_in,
+@@ -1334,8 +1332,7 @@ iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask)
+ 		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, ctask->imm_count);
+ 	if (err)
+ 		return err;
+@@ -1389,7 +1386,6 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ {
+ 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 	struct scsi_cmnd *sc = ctask->sc;
+-	struct scsi_data_buffer *sdb = scsi_out(sc);
+ 	int rc = 0;
+ 
+ flush:
+@@ -1416,8 +1412,9 @@ flush:
+ 				ctask->itt, tcp_ctask->sent, ctask->data_count);
+ 
+ 		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
+-		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
+-					      sdb->table.nents, tcp_ctask->sent,
++		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
++					      scsi_sg_count(sc),
++					      tcp_ctask->sent,
+ 					      ctask->data_count);
+ 		if (rc)
+ 			goto fail;
+@@ -1463,8 +1460,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)
+diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
+index b43bf1d..9975095 100644
+--- a/drivers/scsi/libiscsi.c
++++ b/drivers/scsi/libiscsi.c
+@@ -137,70 +137,6 @@ static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
+ 	return 0;
+ }
+ 
+-/*
+- * make an extended cdb AHS
+- */
+-static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask)
+-{
+-	struct scsi_cmnd *cmd = ctask->sc;
+-	unsigned rlen, pad_len;
+-	unsigned short ahslength;
+-	struct iscsi_ecdb_ahdr *ecdb_ahdr;
+-	int rc;
+-
+-	ecdb_ahdr = iscsi_next_hdr(ctask);
+-	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(ctask, sizeof(ecdb_ahdr->ahslength) +
+-	                   sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len);
+-	if (rc)
+-		return rc;
+-
+-	if (pad_len)
+-		memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
+-
+-	ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
+-	ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
+-	ecdb_ahdr->reserved = 0;
+-	memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
+-
+-	debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
+-		   "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n",
+-		   cmd->cmd_len, rlen, pad_len, ahslength, ctask->hdr_len);
+-
+-	return 0;
+-}
+-
+-static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask)
+-{
+-	struct scsi_cmnd *sc = ctask->sc;
+-	struct iscsi_rlength_ahdr *rlen_ahdr;
+-	int rc;
+-
+-	rlen_ahdr = iscsi_next_hdr(ctask);
+-	rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr));
+-	if (rc)
+-		return rc;
+-
+-	rlen_ahdr->ahslength =
+-		cpu_to_be16(sizeof(rlen_ahdr->read_length) +
+-						  sizeof(rlen_ahdr->reserved));
+-	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
+-	rlen_ahdr->reserved = 0;
+-	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
+-
+-	debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
+-		   "rlen_ahdr->ahslength(%d)\n",
+-		   be32_to_cpu(rlen_ahdr->read_length),
+-		   be16_to_cpu(rlen_ahdr->ahslength));
+-	return 0;
+-}
+-
+ /**
+  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
+  * @ctask: iscsi cmd task
+@@ -214,7 +150,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	struct iscsi_session *session = conn->session;
+ 	struct iscsi_cmd *hdr = ctask->hdr;
+ 	struct scsi_cmnd *sc = ctask->sc;
+-	unsigned hdrlength, cmd_len;
++	unsigned hdrlength;
+ 	int rc;
+ 
+ 	ctask->hdr_len = 0;
+@@ -225,30 +161,17 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	hdr->flags = ISCSI_ATTR_SIMPLE;
+ 	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
+ 	hdr->itt = build_itt(ctask->itt, session->age);
++	hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
+ 	hdr->cmdsn = cpu_to_be32(session->cmdsn);
+ 	session->cmdsn++;
+ 	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
+-	cmd_len = sc->cmd_len;
+-	if (cmd_len < ISCSI_CDB_SIZE)
+-		memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len);
+-	else if (cmd_len > ISCSI_CDB_SIZE) {
+-		rc = iscsi_prep_ecdb_ahs(ctask);
+-		if (rc)
+-			return rc;
+-		cmd_len = ISCSI_CDB_SIZE;
+-	}
+-	memcpy(hdr->cdb, sc->cmnd, cmd_len);
++	memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
++	if (sc->cmd_len < MAX_COMMAND_SIZE)
++		memset(&hdr->cdb[sc->cmd_len], 0,
++			MAX_COMMAND_SIZE - sc->cmd_len);
+ 
+ 	ctask->imm_count = 0;
+-	if (scsi_bidi_cmnd(sc)) {
+-		hdr->flags |= ISCSI_FLAG_CMD_READ;
+-		rc = iscsi_prep_bidi_ahs(ctask);
+-		if (rc)
+-			return rc;
+-	}
+ 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
+-		unsigned out_len = scsi_out(sc)->length;
+-		hdr->data_length = cpu_to_be32(out_len);
+ 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
+ 		/*
+ 		 * Write counters:
+@@ -269,19 +192,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 		ctask->unsol_datasn = 0;
+ 
+ 		if (session->imm_data_en) {
+-			if (out_len >= session->first_burst)
++			if (scsi_bufflen(sc) >= session->first_burst)
+ 				ctask->imm_count = min(session->first_burst,
+ 							conn->max_xmit_dlength);
+ 			else
+-				ctask->imm_count = min(out_len,
++				ctask->imm_count = min(scsi_bufflen(sc),
+ 							conn->max_xmit_dlength);
+ 			hton24(hdr->dlength, ctask->imm_count);
+ 		} else
+ 			zero_data(hdr->dlength);
+ 
+ 		if (!session->initial_r2t_en) {
+-			ctask->unsol_count = min(session->first_burst, out_len)
+-							     - ctask->imm_count;
++			ctask->unsol_count = min((session->first_burst),
++				(scsi_bufflen(sc))) - ctask->imm_count;
+ 			ctask->unsol_offset = ctask->imm_count;
+ 		}
+ 
+@@ -291,7 +214,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	} 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;
+@@ -310,12 +232,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 		return EIO;
+ 
+ 	conn->scsicmd_pdus_cnt++;
+-	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x "
+-		"len %d bidi_len %d cmdsn %d win %d]\n",
+-		scsi_bidi_cmnd(sc) ? "bidirectional" :
+-		     sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+-		conn->id, sc, sc->cmnd[0], ctask->itt,
+-		scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
++	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
++		"cmdsn %d win %d]\n",
++		sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
++		conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
+ 		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+ 	return 0;
+ }
+@@ -378,12 +298,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ 		conn->session->tt->cleanup_cmd_task(conn, ctask);
+ 
+ 	sc->result = err;
+-	if (!scsi_bidi_cmnd(sc))
+-		scsi_set_resid(sc, scsi_bufflen(sc));
+-	else {
+-		scsi_out(sc)->resid = scsi_out(sc)->length;
+-		scsi_in(sc)->resid = scsi_in(sc)->length;
+-	}
++	scsi_set_resid(sc, scsi_bufflen(sc));
+ 	if (conn->ctask == ctask)
+ 		conn->ctask = NULL;
+ 	/* release ref from queuecommand */
+@@ -518,18 +433,6 @@ invalid_datalen:
+ 			   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);
+@@ -537,11 +440,13 @@ invalid_datalen:
+ 		if (res_count > 0 &&
+ 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+ 		     res_count <= scsi_bufflen(sc)))
+-			/* write side for bidi or uni-io set_resid */
+ 			scsi_set_resid(sc, res_count);
+ 		else
+ 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
+-	}
++	} else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
++	                          ISCSI_FLAG_CMD_BIDI_OVERFLOW))
++		sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
++
+ out:
+ 	debug_scsi("done [sc %lx res %d itt 0x%x]\n",
+ 		   (long)sc, sc->result, ctask->itt);
+@@ -1199,12 +1104,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));
+ 	sc->scsi_done(sc);
+ 	spin_lock(host->host_lock);
+ 	return 0;
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index 65d1737..ca7bb6f 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -40,13 +40,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 */
+@@ -63,12 +63,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);
+ }
+ 
+@@ -78,27 +78,25 @@ 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");
+ show_transport_attr(max_lun, "%d");
+@@ -106,11 +104,11 @@ show_transport_attr(max_conn, "%d");
+ show_transport_attr(max_cmd_len, "%d");
+ 
+ static struct attribute *iscsi_transport_attrs[] = {
+-	&dev_attr_handle.attr,
+-	&dev_attr_caps.attr,
+-	&dev_attr_max_lun.attr,
+-	&dev_attr_max_conn.attr,
+-	&dev_attr_max_cmd_len.attr,
++	&class_device_attr_handle.attr,
++	&class_device_attr_caps.attr,
++	&class_device_attr_max_lun.attr,
++	&class_device_attr_max_conn.attr,
++	&class_device_attr_max_cmd_len.attr,
+ 	NULL,
+ };
+ 
+@@ -121,7 +119,7 @@ static struct attribute_group iscsi_transport_group = {
+ 
+ 
+ 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_host *ihost = shost->shost_data;
+@@ -141,7 +139,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_host *ihost = shost->shost_data;
+@@ -1339,8 +1337,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)
+ 
+ /*
+@@ -1348,10 +1349,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);			\
+ }
+@@ -1375,16 +1375,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))				\
+@@ -1416,10 +1417,9 @@ iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
+ iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 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,
+@@ -1427,11 +1427,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);		\
+ }
+ 
+@@ -1446,10 +1444,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); \
+ }
+@@ -1466,7 +1463,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)
+ 
+@@ -1474,7 +1471,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)
+@@ -1482,7 +1479,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)
+@@ -1490,7 +1487,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)
+@@ -1581,15 +1578,15 @@ iscsi_register_transport(struct iscsi_transport *tt)
+ 	priv->iscsi_transport = tt;
+ 	priv->t.user_scan = iscsi_user_scan;
+ 
+-	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];
+@@ -1666,8 +1663,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);
+ free_priv:
+ 	kfree(priv);
+ 	return NULL;
+@@ -1694,8 +1691,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/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index cd3ca63..7b90b63 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -225,7 +225,6 @@ struct iscsi_conn {
+ 
+ 	/* custom statistics */
+ 	uint32_t		eh_abort_cnt;
+-	uint32_t		fmr_unalign_cnt;
+ };
+ 
+ struct iscsi_pool {
+-- 
+1.5.3.8
+
diff --git a/kernel_patches/backport/2.6.18-EL5.1/iscsi_02_count_fmr_align_violations.patch b/kernel_patches/backport/2.6.18-EL5.1/iscsi_02_count_fmr_align_violations.patch
new file mode 100644
index 0000000..9bf2d19
--- /dev/null
+++ b/kernel_patches/backport/2.6.18-EL5.1/iscsi_02_count_fmr_align_violations.patch
@@ -0,0 +1,24 @@
+From 02753dd2caabfe6b1885cb80a8fb8532b416108d Mon Sep 17 00:00:00 2001
+From: Eli Dorfman <elid at voltaire.com>
+Date: Tue, 29 Apr 2008 10:12:39 +0300
+Subject: [PATCH] IB/iSER: Count fmr alignment violations per session
+
+Count fmr alignment violations per session
+as part of the iscsi statistics.
+
+Signed-off-by: Eli Dorfman <elid at voltaire.com>
+diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index 7b90b63..cd3ca63 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -225,6 +225,7 @@ struct iscsi_conn {
+ 
+ 	/* custom statistics */
+ 	uint32_t		eh_abort_cnt;
++	uint32_t		fmr_unalign_cnt;
+ };
+ 
+ struct iscsi_pool {
+-- 
+1.5.5
+
diff --git a/kernel_patches/backport/2.6.18-EL5.1/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch b/kernel_patches/backport/2.6.18-EL5.1/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
new file mode 100644
index 0000000..798571f
--- /dev/null
+++ b/kernel_patches/backport/2.6.18-EL5.1/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
@@ -0,0 +1,151 @@
+From 66ab30f8dadef133bd04bbdcb434a7f742821bed Mon Sep 17 00:00:00 2001
+From: Doron Shoham <dorons at voltaire.com>
+Date: Sun, 29 Jun 2008 15:41:12 +0300
+Subject: [PATCH] copmat patch for RHEL5 and SLES10
+
+Signed-off-by: Doron Shoham <dorons at voltaire.com>
+---
+ drivers/scsi/scsi_transport_iscsi.c |   93 ++++++++++++++++++++---------------
+ 1 files changed, 54 insertions(+), 39 deletions(-)
+
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index ca7bb6f..0ccd7e2 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -20,6 +20,8 @@
+  * 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/version.h>
++#include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <net/tcp.h>
+@@ -397,10 +399,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 (shost->hostt->scan_finished) {
+-		if (queue_work(ihost->scan_workq, &session->scan_work))
+-			atomic_inc(&ihost->nr_scans);
+-	}
++#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
+ }
+ 
+ /**
+@@ -1294,45 +1298,56 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+  * Malformed skbs with wrong lengths or invalid creds are not processed.
+  */
+ static void
+-iscsi_if_rx(struct sk_buff *skb)
++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);
+ }
+@@ -1738,7 +1753,7 @@ static __init int iscsi_transport_init(void)
+ 	return 0;
+ 
+ release_nls:
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ unregister_session_class:
+ 	transport_class_unregister(&iscsi_session_class);
+ unregister_conn_class:
+@@ -1753,7 +1768,7 @@ unregister_transport_class:
+ static void __exit iscsi_transport_exit(void)
+ {
+ 	destroy_workqueue(iscsi_eh_timer_workq);
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ 	transport_class_unregister(&iscsi_connection_class);
+ 	transport_class_unregister(&iscsi_session_class);
+ 	transport_class_unregister(&iscsi_host_class);
+-- 
+1.5.3.8
+
diff --git a/kernel_patches/backport/2.6.18-EL5.2/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch b/kernel_patches/backport/2.6.18-EL5.2/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
new file mode 100644
index 0000000..80375a9
--- /dev/null
+++ b/kernel_patches/backport/2.6.18-EL5.2/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
@@ -0,0 +1,646 @@
+From d7020ef2830f00c127770c63ad5d3c11cacd6685 Mon Sep 17 00:00:00 2001
+From: Doron Shoham <dorons at voltaire.com>
+Date: Thu, 19 Jun 2008 11:33:20 +0300
+Subject: [PATCH 1/1] scsi_01_sync_kernel_code_with_release_2.0-869.2.patch
+
+Signed-off-by: Doron Shoham <dorons at voltaire.com>
+---
+ drivers/scsi/iscsi_tcp.c            |   31 ++++----
+ drivers/scsi/libiscsi.c             |  140 +++++------------------------------
+ drivers/scsi/scsi_transport_iscsi.c |  107 +++++++++++++--------------
+ include/scsi/libiscsi.h             |    1 -
+ 4 files changed, 86 insertions(+), 193 deletions(-)
+
+diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
+index 72b9b2a..8a17867 100644
+--- a/drivers/scsi/iscsi_tcp.c
++++ b/drivers/scsi/iscsi_tcp.c
+@@ -528,7 +528,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	struct iscsi_session *session = conn->session;
+ 	struct scsi_cmnd *sc = ctask->sc;
+ 	int datasn = be32_to_cpu(rhdr->datasn);
+-	unsigned total_in_length = scsi_in(sc)->length;
+ 
+ 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
+ 	if (tcp_conn->in.datalen == 0)
+@@ -543,10 +542,10 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	tcp_ctask->exp_datasn++;
+ 
+ 	tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
+-	if (tcp_ctask->data_offset + tcp_conn->in.datalen > total_in_length) {
++	if (tcp_ctask->data_offset + tcp_conn->in.datalen > scsi_bufflen(sc)) {
+ 		debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n",
+ 		          __FUNCTION__, tcp_ctask->data_offset,
+-		          tcp_conn->in.datalen, total_in_length);
++		          tcp_conn->in.datalen, scsi_bufflen(sc));
+ 		return ISCSI_ERR_DATA_OFFSET;
+ 	}
+ 
+@@ -559,8 +558,8 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 
+ 			if (res_count > 0 &&
+ 			    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+-			     res_count <= total_in_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;
+@@ -671,11 +670,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 			    r2t->data_length, session->max_burst);
+ 
+ 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
+-	if (r2t->data_offset + r2t->data_length > scsi_out(ctask->sc)->length) {
++	if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
+ 		iscsi_conn_printk(KERN_ERR, conn,
+ 				  "invalid R2T with data len %u at offset %u "
+ 				  "and total length %d\n", r2t->data_length,
+-				  r2t->data_offset, scsi_out(ctask->sc)->length);
++				  r2t->data_offset, scsi_bufflen(ctask->sc));
+ 		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+ 			    sizeof(void*));
+ 		return ISCSI_ERR_DATALEN;
+@@ -772,7 +771,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 		if (tcp_conn->in.datalen) {
+ 			struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 			struct hash_desc *rx_hash = NULL;
+-			struct scsi_data_buffer *sdb = scsi_in(ctask->sc);
+ 
+ 			/*
+ 			 * Setup copy of Data-In into the Scsi_Cmnd
+@@ -790,8 +788,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 				  tcp_ctask->data_offset,
+ 				  tcp_conn->in.datalen);
+ 			return iscsi_segment_seek_sg(&tcp_conn->in.segment,
+-						     sdb->table.sgl,
+-						     sdb->table.nents,
++						     scsi_sglist(ctask->sc),
++						     scsi_sg_count(ctask->sc),
+ 						     tcp_ctask->data_offset,
+ 						     tcp_conn->in.datalen,
+ 						     iscsi_tcp_process_data_in,
+@@ -1334,8 +1332,7 @@ iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask)
+ 		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, ctask->imm_count);
+ 	if (err)
+ 		return err;
+@@ -1389,7 +1386,6 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ {
+ 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 	struct scsi_cmnd *sc = ctask->sc;
+-	struct scsi_data_buffer *sdb = scsi_out(sc);
+ 	int rc = 0;
+ 
+ flush:
+@@ -1416,8 +1412,9 @@ flush:
+ 				ctask->itt, tcp_ctask->sent, ctask->data_count);
+ 
+ 		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
+-		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
+-					      sdb->table.nents, tcp_ctask->sent,
++		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
++					      scsi_sg_count(sc),
++					      tcp_ctask->sent,
+ 					      ctask->data_count);
+ 		if (rc)
+ 			goto fail;
+@@ -1463,8 +1460,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)
+diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
+index b43bf1d..9975095 100644
+--- a/drivers/scsi/libiscsi.c
++++ b/drivers/scsi/libiscsi.c
+@@ -137,70 +137,6 @@ static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
+ 	return 0;
+ }
+ 
+-/*
+- * make an extended cdb AHS
+- */
+-static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask)
+-{
+-	struct scsi_cmnd *cmd = ctask->sc;
+-	unsigned rlen, pad_len;
+-	unsigned short ahslength;
+-	struct iscsi_ecdb_ahdr *ecdb_ahdr;
+-	int rc;
+-
+-	ecdb_ahdr = iscsi_next_hdr(ctask);
+-	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(ctask, sizeof(ecdb_ahdr->ahslength) +
+-	                   sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len);
+-	if (rc)
+-		return rc;
+-
+-	if (pad_len)
+-		memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
+-
+-	ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
+-	ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
+-	ecdb_ahdr->reserved = 0;
+-	memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
+-
+-	debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
+-		   "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n",
+-		   cmd->cmd_len, rlen, pad_len, ahslength, ctask->hdr_len);
+-
+-	return 0;
+-}
+-
+-static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask)
+-{
+-	struct scsi_cmnd *sc = ctask->sc;
+-	struct iscsi_rlength_ahdr *rlen_ahdr;
+-	int rc;
+-
+-	rlen_ahdr = iscsi_next_hdr(ctask);
+-	rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr));
+-	if (rc)
+-		return rc;
+-
+-	rlen_ahdr->ahslength =
+-		cpu_to_be16(sizeof(rlen_ahdr->read_length) +
+-						  sizeof(rlen_ahdr->reserved));
+-	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
+-	rlen_ahdr->reserved = 0;
+-	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
+-
+-	debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
+-		   "rlen_ahdr->ahslength(%d)\n",
+-		   be32_to_cpu(rlen_ahdr->read_length),
+-		   be16_to_cpu(rlen_ahdr->ahslength));
+-	return 0;
+-}
+-
+ /**
+  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
+  * @ctask: iscsi cmd task
+@@ -214,7 +150,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	struct iscsi_session *session = conn->session;
+ 	struct iscsi_cmd *hdr = ctask->hdr;
+ 	struct scsi_cmnd *sc = ctask->sc;
+-	unsigned hdrlength, cmd_len;
++	unsigned hdrlength;
+ 	int rc;
+ 
+ 	ctask->hdr_len = 0;
+@@ -225,30 +161,17 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	hdr->flags = ISCSI_ATTR_SIMPLE;
+ 	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
+ 	hdr->itt = build_itt(ctask->itt, session->age);
++	hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
+ 	hdr->cmdsn = cpu_to_be32(session->cmdsn);
+ 	session->cmdsn++;
+ 	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
+-	cmd_len = sc->cmd_len;
+-	if (cmd_len < ISCSI_CDB_SIZE)
+-		memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len);
+-	else if (cmd_len > ISCSI_CDB_SIZE) {
+-		rc = iscsi_prep_ecdb_ahs(ctask);
+-		if (rc)
+-			return rc;
+-		cmd_len = ISCSI_CDB_SIZE;
+-	}
+-	memcpy(hdr->cdb, sc->cmnd, cmd_len);
++	memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
++	if (sc->cmd_len < MAX_COMMAND_SIZE)
++		memset(&hdr->cdb[sc->cmd_len], 0,
++			MAX_COMMAND_SIZE - sc->cmd_len);
+ 
+ 	ctask->imm_count = 0;
+-	if (scsi_bidi_cmnd(sc)) {
+-		hdr->flags |= ISCSI_FLAG_CMD_READ;
+-		rc = iscsi_prep_bidi_ahs(ctask);
+-		if (rc)
+-			return rc;
+-	}
+ 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
+-		unsigned out_len = scsi_out(sc)->length;
+-		hdr->data_length = cpu_to_be32(out_len);
+ 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
+ 		/*
+ 		 * Write counters:
+@@ -269,19 +192,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 		ctask->unsol_datasn = 0;
+ 
+ 		if (session->imm_data_en) {
+-			if (out_len >= session->first_burst)
++			if (scsi_bufflen(sc) >= session->first_burst)
+ 				ctask->imm_count = min(session->first_burst,
+ 							conn->max_xmit_dlength);
+ 			else
+-				ctask->imm_count = min(out_len,
++				ctask->imm_count = min(scsi_bufflen(sc),
+ 							conn->max_xmit_dlength);
+ 			hton24(hdr->dlength, ctask->imm_count);
+ 		} else
+ 			zero_data(hdr->dlength);
+ 
+ 		if (!session->initial_r2t_en) {
+-			ctask->unsol_count = min(session->first_burst, out_len)
+-							     - ctask->imm_count;
++			ctask->unsol_count = min((session->first_burst),
++				(scsi_bufflen(sc))) - ctask->imm_count;
+ 			ctask->unsol_offset = ctask->imm_count;
+ 		}
+ 
+@@ -291,7 +214,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	} 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;
+@@ -310,12 +232,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 		return EIO;
+ 
+ 	conn->scsicmd_pdus_cnt++;
+-	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x "
+-		"len %d bidi_len %d cmdsn %d win %d]\n",
+-		scsi_bidi_cmnd(sc) ? "bidirectional" :
+-		     sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+-		conn->id, sc, sc->cmnd[0], ctask->itt,
+-		scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
++	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
++		"cmdsn %d win %d]\n",
++		sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
++		conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
+ 		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+ 	return 0;
+ }
+@@ -378,12 +298,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ 		conn->session->tt->cleanup_cmd_task(conn, ctask);
+ 
+ 	sc->result = err;
+-	if (!scsi_bidi_cmnd(sc))
+-		scsi_set_resid(sc, scsi_bufflen(sc));
+-	else {
+-		scsi_out(sc)->resid = scsi_out(sc)->length;
+-		scsi_in(sc)->resid = scsi_in(sc)->length;
+-	}
++	scsi_set_resid(sc, scsi_bufflen(sc));
+ 	if (conn->ctask == ctask)
+ 		conn->ctask = NULL;
+ 	/* release ref from queuecommand */
+@@ -518,18 +433,6 @@ invalid_datalen:
+ 			   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);
+@@ -537,11 +440,13 @@ invalid_datalen:
+ 		if (res_count > 0 &&
+ 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+ 		     res_count <= scsi_bufflen(sc)))
+-			/* write side for bidi or uni-io set_resid */
+ 			scsi_set_resid(sc, res_count);
+ 		else
+ 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
+-	}
++	} else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
++	                          ISCSI_FLAG_CMD_BIDI_OVERFLOW))
++		sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
++
+ out:
+ 	debug_scsi("done [sc %lx res %d itt 0x%x]\n",
+ 		   (long)sc, sc->result, ctask->itt);
+@@ -1199,12 +1104,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));
+ 	sc->scsi_done(sc);
+ 	spin_lock(host->host_lock);
+ 	return 0;
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index 65d1737..ca7bb6f 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -40,13 +40,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 */
+@@ -63,12 +63,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);
+ }
+ 
+@@ -78,27 +78,25 @@ 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");
+ show_transport_attr(max_lun, "%d");
+@@ -106,11 +104,11 @@ show_transport_attr(max_conn, "%d");
+ show_transport_attr(max_cmd_len, "%d");
+ 
+ static struct attribute *iscsi_transport_attrs[] = {
+-	&dev_attr_handle.attr,
+-	&dev_attr_caps.attr,
+-	&dev_attr_max_lun.attr,
+-	&dev_attr_max_conn.attr,
+-	&dev_attr_max_cmd_len.attr,
++	&class_device_attr_handle.attr,
++	&class_device_attr_caps.attr,
++	&class_device_attr_max_lun.attr,
++	&class_device_attr_max_conn.attr,
++	&class_device_attr_max_cmd_len.attr,
+ 	NULL,
+ };
+ 
+@@ -121,7 +119,7 @@ static struct attribute_group iscsi_transport_group = {
+ 
+ 
+ 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_host *ihost = shost->shost_data;
+@@ -141,7 +139,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_host *ihost = shost->shost_data;
+@@ -1339,8 +1337,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)
+ 
+ /*
+@@ -1348,10 +1349,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);			\
+ }
+@@ -1375,16 +1375,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))				\
+@@ -1416,10 +1417,9 @@ iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
+ iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 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,
+@@ -1427,11 +1427,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);		\
+ }
+ 
+@@ -1446,10 +1444,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); \
+ }
+@@ -1466,7 +1463,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)
+ 
+@@ -1474,7 +1471,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)
+@@ -1482,7 +1479,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)
+@@ -1490,7 +1487,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)
+@@ -1581,15 +1578,15 @@ iscsi_register_transport(struct iscsi_transport *tt)
+ 	priv->iscsi_transport = tt;
+ 	priv->t.user_scan = iscsi_user_scan;
+ 
+-	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];
+@@ -1666,8 +1663,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);
+ free_priv:
+ 	kfree(priv);
+ 	return NULL;
+@@ -1694,8 +1691,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/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index cd3ca63..7b90b63 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -225,7 +225,6 @@ struct iscsi_conn {
+ 
+ 	/* custom statistics */
+ 	uint32_t		eh_abort_cnt;
+-	uint32_t		fmr_unalign_cnt;
+ };
+ 
+ struct iscsi_pool {
+-- 
+1.5.3.8
+
diff --git a/kernel_patches/backport/2.6.18-EL5.2/iscsi_02_count_fmr_align_violations.patch b/kernel_patches/backport/2.6.18-EL5.2/iscsi_02_count_fmr_align_violations.patch
new file mode 100644
index 0000000..9bf2d19
--- /dev/null
+++ b/kernel_patches/backport/2.6.18-EL5.2/iscsi_02_count_fmr_align_violations.patch
@@ -0,0 +1,24 @@
+From 02753dd2caabfe6b1885cb80a8fb8532b416108d Mon Sep 17 00:00:00 2001
+From: Eli Dorfman <elid at voltaire.com>
+Date: Tue, 29 Apr 2008 10:12:39 +0300
+Subject: [PATCH] IB/iSER: Count fmr alignment violations per session
+
+Count fmr alignment violations per session
+as part of the iscsi statistics.
+
+Signed-off-by: Eli Dorfman <elid at voltaire.com>
+diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index 7b90b63..cd3ca63 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -225,6 +225,7 @@ struct iscsi_conn {
+ 
+ 	/* custom statistics */
+ 	uint32_t		eh_abort_cnt;
++	uint32_t		fmr_unalign_cnt;
+ };
+ 
+ struct iscsi_pool {
+-- 
+1.5.5
+
diff --git a/kernel_patches/backport/2.6.18-EL5.2/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch b/kernel_patches/backport/2.6.18-EL5.2/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
new file mode 100644
index 0000000..798571f
--- /dev/null
+++ b/kernel_patches/backport/2.6.18-EL5.2/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
@@ -0,0 +1,151 @@
+From 66ab30f8dadef133bd04bbdcb434a7f742821bed Mon Sep 17 00:00:00 2001
+From: Doron Shoham <dorons at voltaire.com>
+Date: Sun, 29 Jun 2008 15:41:12 +0300
+Subject: [PATCH] copmat patch for RHEL5 and SLES10
+
+Signed-off-by: Doron Shoham <dorons at voltaire.com>
+---
+ drivers/scsi/scsi_transport_iscsi.c |   93 ++++++++++++++++++++---------------
+ 1 files changed, 54 insertions(+), 39 deletions(-)
+
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index ca7bb6f..0ccd7e2 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -20,6 +20,8 @@
+  * 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/version.h>
++#include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <net/tcp.h>
+@@ -397,10 +399,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 (shost->hostt->scan_finished) {
+-		if (queue_work(ihost->scan_workq, &session->scan_work))
+-			atomic_inc(&ihost->nr_scans);
+-	}
++#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
+ }
+ 
+ /**
+@@ -1294,45 +1298,56 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+  * Malformed skbs with wrong lengths or invalid creds are not processed.
+  */
+ static void
+-iscsi_if_rx(struct sk_buff *skb)
++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);
+ }
+@@ -1738,7 +1753,7 @@ static __init int iscsi_transport_init(void)
+ 	return 0;
+ 
+ release_nls:
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ unregister_session_class:
+ 	transport_class_unregister(&iscsi_session_class);
+ unregister_conn_class:
+@@ -1753,7 +1768,7 @@ unregister_transport_class:
+ static void __exit iscsi_transport_exit(void)
+ {
+ 	destroy_workqueue(iscsi_eh_timer_workq);
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ 	transport_class_unregister(&iscsi_connection_class);
+ 	transport_class_unregister(&iscsi_session_class);
+ 	transport_class_unregister(&iscsi_host_class);
+-- 
+1.5.3.8
+
diff --git a/kernel_patches/backport/2.6.18_FC6/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch b/kernel_patches/backport/2.6.18_FC6/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
new file mode 100644
index 0000000..80375a9
--- /dev/null
+++ b/kernel_patches/backport/2.6.18_FC6/iscsi_01_sync_kernel_code_with_release_2.0-869.2.patch
@@ -0,0 +1,646 @@
+From d7020ef2830f00c127770c63ad5d3c11cacd6685 Mon Sep 17 00:00:00 2001
+From: Doron Shoham <dorons at voltaire.com>
+Date: Thu, 19 Jun 2008 11:33:20 +0300
+Subject: [PATCH 1/1] scsi_01_sync_kernel_code_with_release_2.0-869.2.patch
+
+Signed-off-by: Doron Shoham <dorons at voltaire.com>
+---
+ drivers/scsi/iscsi_tcp.c            |   31 ++++----
+ drivers/scsi/libiscsi.c             |  140 +++++------------------------------
+ drivers/scsi/scsi_transport_iscsi.c |  107 +++++++++++++--------------
+ include/scsi/libiscsi.h             |    1 -
+ 4 files changed, 86 insertions(+), 193 deletions(-)
+
+diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
+index 72b9b2a..8a17867 100644
+--- a/drivers/scsi/iscsi_tcp.c
++++ b/drivers/scsi/iscsi_tcp.c
+@@ -528,7 +528,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	struct iscsi_session *session = conn->session;
+ 	struct scsi_cmnd *sc = ctask->sc;
+ 	int datasn = be32_to_cpu(rhdr->datasn);
+-	unsigned total_in_length = scsi_in(sc)->length;
+ 
+ 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
+ 	if (tcp_conn->in.datalen == 0)
+@@ -543,10 +542,10 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 	tcp_ctask->exp_datasn++;
+ 
+ 	tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
+-	if (tcp_ctask->data_offset + tcp_conn->in.datalen > total_in_length) {
++	if (tcp_ctask->data_offset + tcp_conn->in.datalen > scsi_bufflen(sc)) {
+ 		debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n",
+ 		          __FUNCTION__, tcp_ctask->data_offset,
+-		          tcp_conn->in.datalen, total_in_length);
++		          tcp_conn->in.datalen, scsi_bufflen(sc));
+ 		return ISCSI_ERR_DATA_OFFSET;
+ 	}
+ 
+@@ -559,8 +558,8 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 
+ 			if (res_count > 0 &&
+ 			    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+-			     res_count <= total_in_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;
+@@ -671,11 +670,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ 			    r2t->data_length, session->max_burst);
+ 
+ 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
+-	if (r2t->data_offset + r2t->data_length > scsi_out(ctask->sc)->length) {
++	if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
+ 		iscsi_conn_printk(KERN_ERR, conn,
+ 				  "invalid R2T with data len %u at offset %u "
+ 				  "and total length %d\n", r2t->data_length,
+-				  r2t->data_offset, scsi_out(ctask->sc)->length);
++				  r2t->data_offset, scsi_bufflen(ctask->sc));
+ 		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+ 			    sizeof(void*));
+ 		return ISCSI_ERR_DATALEN;
+@@ -772,7 +771,6 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 		if (tcp_conn->in.datalen) {
+ 			struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 			struct hash_desc *rx_hash = NULL;
+-			struct scsi_data_buffer *sdb = scsi_in(ctask->sc);
+ 
+ 			/*
+ 			 * Setup copy of Data-In into the Scsi_Cmnd
+@@ -790,8 +788,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+ 				  tcp_ctask->data_offset,
+ 				  tcp_conn->in.datalen);
+ 			return iscsi_segment_seek_sg(&tcp_conn->in.segment,
+-						     sdb->table.sgl,
+-						     sdb->table.nents,
++						     scsi_sglist(ctask->sc),
++						     scsi_sg_count(ctask->sc),
+ 						     tcp_ctask->data_offset,
+ 						     tcp_conn->in.datalen,
+ 						     iscsi_tcp_process_data_in,
+@@ -1334,8 +1332,7 @@ iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask)
+ 		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, ctask->imm_count);
+ 	if (err)
+ 		return err;
+@@ -1389,7 +1386,6 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ {
+ 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ 	struct scsi_cmnd *sc = ctask->sc;
+-	struct scsi_data_buffer *sdb = scsi_out(sc);
+ 	int rc = 0;
+ 
+ flush:
+@@ -1416,8 +1412,9 @@ flush:
+ 				ctask->itt, tcp_ctask->sent, ctask->data_count);
+ 
+ 		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
+-		rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl,
+-					      sdb->table.nents, tcp_ctask->sent,
++		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
++					      scsi_sg_count(sc),
++					      tcp_ctask->sent,
+ 					      ctask->data_count);
+ 		if (rc)
+ 			goto fail;
+@@ -1463,8 +1460,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)
+diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
+index b43bf1d..9975095 100644
+--- a/drivers/scsi/libiscsi.c
++++ b/drivers/scsi/libiscsi.c
+@@ -137,70 +137,6 @@ static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
+ 	return 0;
+ }
+ 
+-/*
+- * make an extended cdb AHS
+- */
+-static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask)
+-{
+-	struct scsi_cmnd *cmd = ctask->sc;
+-	unsigned rlen, pad_len;
+-	unsigned short ahslength;
+-	struct iscsi_ecdb_ahdr *ecdb_ahdr;
+-	int rc;
+-
+-	ecdb_ahdr = iscsi_next_hdr(ctask);
+-	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(ctask, sizeof(ecdb_ahdr->ahslength) +
+-	                   sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len);
+-	if (rc)
+-		return rc;
+-
+-	if (pad_len)
+-		memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
+-
+-	ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
+-	ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
+-	ecdb_ahdr->reserved = 0;
+-	memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
+-
+-	debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
+-		   "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n",
+-		   cmd->cmd_len, rlen, pad_len, ahslength, ctask->hdr_len);
+-
+-	return 0;
+-}
+-
+-static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask)
+-{
+-	struct scsi_cmnd *sc = ctask->sc;
+-	struct iscsi_rlength_ahdr *rlen_ahdr;
+-	int rc;
+-
+-	rlen_ahdr = iscsi_next_hdr(ctask);
+-	rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr));
+-	if (rc)
+-		return rc;
+-
+-	rlen_ahdr->ahslength =
+-		cpu_to_be16(sizeof(rlen_ahdr->read_length) +
+-						  sizeof(rlen_ahdr->reserved));
+-	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
+-	rlen_ahdr->reserved = 0;
+-	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
+-
+-	debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
+-		   "rlen_ahdr->ahslength(%d)\n",
+-		   be32_to_cpu(rlen_ahdr->read_length),
+-		   be16_to_cpu(rlen_ahdr->ahslength));
+-	return 0;
+-}
+-
+ /**
+  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
+  * @ctask: iscsi cmd task
+@@ -214,7 +150,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	struct iscsi_session *session = conn->session;
+ 	struct iscsi_cmd *hdr = ctask->hdr;
+ 	struct scsi_cmnd *sc = ctask->sc;
+-	unsigned hdrlength, cmd_len;
++	unsigned hdrlength;
+ 	int rc;
+ 
+ 	ctask->hdr_len = 0;
+@@ -225,30 +161,17 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	hdr->flags = ISCSI_ATTR_SIMPLE;
+ 	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
+ 	hdr->itt = build_itt(ctask->itt, session->age);
++	hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
+ 	hdr->cmdsn = cpu_to_be32(session->cmdsn);
+ 	session->cmdsn++;
+ 	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
+-	cmd_len = sc->cmd_len;
+-	if (cmd_len < ISCSI_CDB_SIZE)
+-		memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len);
+-	else if (cmd_len > ISCSI_CDB_SIZE) {
+-		rc = iscsi_prep_ecdb_ahs(ctask);
+-		if (rc)
+-			return rc;
+-		cmd_len = ISCSI_CDB_SIZE;
+-	}
+-	memcpy(hdr->cdb, sc->cmnd, cmd_len);
++	memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
++	if (sc->cmd_len < MAX_COMMAND_SIZE)
++		memset(&hdr->cdb[sc->cmd_len], 0,
++			MAX_COMMAND_SIZE - sc->cmd_len);
+ 
+ 	ctask->imm_count = 0;
+-	if (scsi_bidi_cmnd(sc)) {
+-		hdr->flags |= ISCSI_FLAG_CMD_READ;
+-		rc = iscsi_prep_bidi_ahs(ctask);
+-		if (rc)
+-			return rc;
+-	}
+ 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
+-		unsigned out_len = scsi_out(sc)->length;
+-		hdr->data_length = cpu_to_be32(out_len);
+ 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
+ 		/*
+ 		 * Write counters:
+@@ -269,19 +192,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 		ctask->unsol_datasn = 0;
+ 
+ 		if (session->imm_data_en) {
+-			if (out_len >= session->first_burst)
++			if (scsi_bufflen(sc) >= session->first_burst)
+ 				ctask->imm_count = min(session->first_burst,
+ 							conn->max_xmit_dlength);
+ 			else
+-				ctask->imm_count = min(out_len,
++				ctask->imm_count = min(scsi_bufflen(sc),
+ 							conn->max_xmit_dlength);
+ 			hton24(hdr->dlength, ctask->imm_count);
+ 		} else
+ 			zero_data(hdr->dlength);
+ 
+ 		if (!session->initial_r2t_en) {
+-			ctask->unsol_count = min(session->first_burst, out_len)
+-							     - ctask->imm_count;
++			ctask->unsol_count = min((session->first_burst),
++				(scsi_bufflen(sc))) - ctask->imm_count;
+ 			ctask->unsol_offset = ctask->imm_count;
+ 		}
+ 
+@@ -291,7 +214,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 	} 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;
+@@ -310,12 +232,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+ 		return EIO;
+ 
+ 	conn->scsicmd_pdus_cnt++;
+-	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x "
+-		"len %d bidi_len %d cmdsn %d win %d]\n",
+-		scsi_bidi_cmnd(sc) ? "bidirectional" :
+-		     sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+-		conn->id, sc, sc->cmnd[0], ctask->itt,
+-		scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
++	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
++		"cmdsn %d win %d]\n",
++		sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
++		conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
+ 		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+ 	return 0;
+ }
+@@ -378,12 +298,7 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ 		conn->session->tt->cleanup_cmd_task(conn, ctask);
+ 
+ 	sc->result = err;
+-	if (!scsi_bidi_cmnd(sc))
+-		scsi_set_resid(sc, scsi_bufflen(sc));
+-	else {
+-		scsi_out(sc)->resid = scsi_out(sc)->length;
+-		scsi_in(sc)->resid = scsi_in(sc)->length;
+-	}
++	scsi_set_resid(sc, scsi_bufflen(sc));
+ 	if (conn->ctask == ctask)
+ 		conn->ctask = NULL;
+ 	/* release ref from queuecommand */
+@@ -518,18 +433,6 @@ invalid_datalen:
+ 			   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);
+@@ -537,11 +440,13 @@ invalid_datalen:
+ 		if (res_count > 0 &&
+ 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+ 		     res_count <= scsi_bufflen(sc)))
+-			/* write side for bidi or uni-io set_resid */
+ 			scsi_set_resid(sc, res_count);
+ 		else
+ 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
+-	}
++	} else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
++	                          ISCSI_FLAG_CMD_BIDI_OVERFLOW))
++		sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
++
+ out:
+ 	debug_scsi("done [sc %lx res %d itt 0x%x]\n",
+ 		   (long)sc, sc->result, ctask->itt);
+@@ -1199,12 +1104,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));
+ 	sc->scsi_done(sc);
+ 	spin_lock(host->host_lock);
+ 	return 0;
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index 65d1737..ca7bb6f 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -40,13 +40,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 */
+@@ -63,12 +63,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);
+ }
+ 
+@@ -78,27 +78,25 @@ 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");
+ show_transport_attr(max_lun, "%d");
+@@ -106,11 +104,11 @@ show_transport_attr(max_conn, "%d");
+ show_transport_attr(max_cmd_len, "%d");
+ 
+ static struct attribute *iscsi_transport_attrs[] = {
+-	&dev_attr_handle.attr,
+-	&dev_attr_caps.attr,
+-	&dev_attr_max_lun.attr,
+-	&dev_attr_max_conn.attr,
+-	&dev_attr_max_cmd_len.attr,
++	&class_device_attr_handle.attr,
++	&class_device_attr_caps.attr,
++	&class_device_attr_max_lun.attr,
++	&class_device_attr_max_conn.attr,
++	&class_device_attr_max_cmd_len.attr,
+ 	NULL,
+ };
+ 
+@@ -121,7 +119,7 @@ static struct attribute_group iscsi_transport_group = {
+ 
+ 
+ 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_host *ihost = shost->shost_data;
+@@ -141,7 +139,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_host *ihost = shost->shost_data;
+@@ -1339,8 +1337,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)
+ 
+ /*
+@@ -1348,10 +1349,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);			\
+ }
+@@ -1375,16 +1375,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))				\
+@@ -1416,10 +1417,9 @@ iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
+ iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 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,
+@@ -1427,11 +1427,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);		\
+ }
+ 
+@@ -1446,10 +1444,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); \
+ }
+@@ -1466,7 +1463,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)
+ 
+@@ -1474,7 +1471,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)
+@@ -1482,7 +1479,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)
+@@ -1490,7 +1487,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)
+@@ -1581,15 +1578,15 @@ iscsi_register_transport(struct iscsi_transport *tt)
+ 	priv->iscsi_transport = tt;
+ 	priv->t.user_scan = iscsi_user_scan;
+ 
+-	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];
+@@ -1666,8 +1663,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);
+ free_priv:
+ 	kfree(priv);
+ 	return NULL;
+@@ -1694,8 +1691,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/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index cd3ca63..7b90b63 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -225,7 +225,6 @@ struct iscsi_conn {
+ 
+ 	/* custom statistics */
+ 	uint32_t		eh_abort_cnt;
+-	uint32_t		fmr_unalign_cnt;
+ };
+ 
+ struct iscsi_pool {
+-- 
+1.5.3.8
+
diff --git a/kernel_patches/backport/2.6.18_FC6/iscsi_02_count_fmr_align_violations.patch b/kernel_patches/backport/2.6.18_FC6/iscsi_02_count_fmr_align_violations.patch
new file mode 100644
index 0000000..9bf2d19
--- /dev/null
+++ b/kernel_patches/backport/2.6.18_FC6/iscsi_02_count_fmr_align_violations.patch
@@ -0,0 +1,24 @@
+From 02753dd2caabfe6b1885cb80a8fb8532b416108d Mon Sep 17 00:00:00 2001
+From: Eli Dorfman <elid at voltaire.com>
+Date: Tue, 29 Apr 2008 10:12:39 +0300
+Subject: [PATCH] IB/iSER: Count fmr alignment violations per session
+
+Count fmr alignment violations per session
+as part of the iscsi statistics.
+
+Signed-off-by: Eli Dorfman <elid at voltaire.com>
+diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
+index 7b90b63..cd3ca63 100644
+--- a/include/scsi/libiscsi.h
++++ b/include/scsi/libiscsi.h
+@@ -225,6 +225,7 @@ struct iscsi_conn {
+ 
+ 	/* custom statistics */
+ 	uint32_t		eh_abort_cnt;
++	uint32_t		fmr_unalign_cnt;
+ };
+ 
+ struct iscsi_pool {
+-- 
+1.5.5
+
diff --git a/kernel_patches/backport/2.6.18_FC6/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch b/kernel_patches/backport/2.6.18_FC6/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
new file mode 100644
index 0000000..798571f
--- /dev/null
+++ b/kernel_patches/backport/2.6.18_FC6/iscsi_03_copmat_patch_for_RHEL5_and_SLES10.patch
@@ -0,0 +1,151 @@
+From 66ab30f8dadef133bd04bbdcb434a7f742821bed Mon Sep 17 00:00:00 2001
+From: Doron Shoham <dorons at voltaire.com>
+Date: Sun, 29 Jun 2008 15:41:12 +0300
+Subject: [PATCH] copmat patch for RHEL5 and SLES10
+
+Signed-off-by: Doron Shoham <dorons at voltaire.com>
+---
+ drivers/scsi/scsi_transport_iscsi.c |   93 ++++++++++++++++++++---------------
+ 1 files changed, 54 insertions(+), 39 deletions(-)
+
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index ca7bb6f..0ccd7e2 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -20,6 +20,8 @@
+  * 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/version.h>
++#include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <net/tcp.h>
+@@ -397,10 +399,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 (shost->hostt->scan_finished) {
+-		if (queue_work(ihost->scan_workq, &session->scan_work))
+-			atomic_inc(&ihost->nr_scans);
+-	}
++#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
+ }
+ 
+ /**
+@@ -1294,45 +1298,56 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+  * Malformed skbs with wrong lengths or invalid creds are not processed.
+  */
+ static void
+-iscsi_if_rx(struct sk_buff *skb)
++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);
+ }
+@@ -1738,7 +1753,7 @@ static __init int iscsi_transport_init(void)
+ 	return 0;
+ 
+ release_nls:
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ unregister_session_class:
+ 	transport_class_unregister(&iscsi_session_class);
+ unregister_conn_class:
+@@ -1753,7 +1768,7 @@ unregister_transport_class:
+ static void __exit iscsi_transport_exit(void)
+ {
+ 	destroy_workqueue(iscsi_eh_timer_workq);
+-	netlink_kernel_release(nls);
++	sock_release(nls->sk_socket);
+ 	transport_class_unregister(&iscsi_connection_class);
+ 	transport_class_unregister(&iscsi_session_class);
+ 	transport_class_unregister(&iscsi_host_class);
+-- 
+1.5.3.8
+
-- 
1.5.3.8





More information about the ewg mailing list