[SCSI] iscsi: seperate iscsi interface from setup functions

This is the second version of the patch to address Christoph's comments.
Instead of doing the lib, I just kept everything in scsi_trnapsort_iscsi.c
like the FC and SPI class. This was becuase the driver model and sysfs
class is tied to the session and connection setup so separating did not
buy very much at this time.

The reason for this patch was becuase HW iscsi LLDs like qla4xxx cannot
use the iscsi class becuase the scsi_host was tied to the interface and
class code. This patch just seperates the session from scsi host so
that LLDs that allocate the host per some resource like pci device
can still use the class.

This is also fixes a couple refcount bugs that can be triggered
when users have a sysfs file open, close the session, then
read or write to the file.

Signed-off-by: Alex Aizman <itn780@yahoo.com>
Signed-off-by: Dmitry Yusupov <dmitry_yus@yahoo.com>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 0acc4b2..e31d350 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -2435,17 +2435,20 @@
 	kfree(items);
 }
 
-static iscsi_connh_t
-iscsi_conn_create(iscsi_sessionh_t sessionh, uint32_t conn_idx)
+static struct iscsi_cls_conn *
+iscsi_conn_create(struct Scsi_Host *shost, uint32_t conn_idx)
 {
-	struct iscsi_session *session = iscsi_ptr(sessionh);
-	struct iscsi_conn *conn = NULL;
+	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+	struct iscsi_conn *conn;
+	struct iscsi_cls_conn *cls_conn;
 
-	conn = kmalloc(sizeof(struct iscsi_conn), GFP_KERNEL);
-	if (conn == NULL)
-		goto conn_alloc_fail;
+	cls_conn = iscsi_create_conn(hostdata_session(shost->hostdata),
+				     conn_idx);
+	if (!cls_conn)
+		return NULL;
+	conn = cls_conn->dd_data;
+
 	memset(conn, 0, sizeof(struct iscsi_conn));
-
 	conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
 	conn->in_progress = IN_PROGRESS_WAIT_HEADER;
 	conn->id = conn_idx;
@@ -2507,7 +2510,7 @@
 	mutex_init(&conn->xmitmutex);
 	init_waitqueue_head(&conn->ehwait);
 
-	return iscsi_handle(conn);
+	return cls_conn;
 
 max_recv_dlenght_alloc_fail:
 	spin_lock_bh(&session->lock);
@@ -2523,15 +2526,14 @@
 writequeue_alloc_fail:
 	kfifo_free(conn->xmitqueue);
 xmitqueue_alloc_fail:
-	kfree(conn);
-conn_alloc_fail:
-	return iscsi_handle(NULL);
+	iscsi_destroy_conn(cls_conn);
+	return NULL;
 }
 
 static void
-iscsi_conn_destroy(iscsi_connh_t connh)
+iscsi_conn_destroy(struct iscsi_cls_conn *cls_conn)
 {
-	struct iscsi_conn *conn = iscsi_ptr(connh);
+	struct iscsi_conn *conn = cls_conn->dd_data;
 	struct iscsi_session *session = conn->session;
 	unsigned long flags;
 
@@ -2626,7 +2628,8 @@
 	kfifo_free(conn->writequeue);
 	kfifo_free(conn->immqueue);
 	kfifo_free(conn->mgmtqueue);
-	kfree(conn);
+
+	iscsi_destroy_conn(cls_conn);
 }
 
 static int
@@ -3257,17 +3260,23 @@
 	.this_id		= -1,
 };
 
-static iscsi_sessionh_t
-iscsi_session_create(uint32_t initial_cmdsn, struct Scsi_Host *host)
+static struct iscsi_transport iscsi_tcp_transport;
+
+static struct Scsi_Host *
+iscsi_session_create(struct scsi_transport_template *scsit,
+		     uint32_t initial_cmdsn)
 {
-	int cmd_i;
+	struct Scsi_Host *shost;
 	struct iscsi_session *session;
+	int cmd_i;
 
-	session = iscsi_hostdata(host->hostdata);
+	shost = iscsi_transport_create_session(scsit, &iscsi_tcp_transport);
+	if (!shost)
+		return NULL; 
+
+	session = iscsi_hostdata(shost->hostdata);
 	memset(session, 0, sizeof(struct iscsi_session));
-
-	session->host = host;
-	session->id = host->host_no;
+	session->host = shost;
 	session->state = ISCSI_STATE_LOGGED_IN;
 	session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
 	session->cmds_max = ISCSI_XMIT_CMDS_MAX;
@@ -3311,7 +3320,7 @@
 	if (iscsi_r2tpool_alloc(session))
 		goto r2tpool_alloc_fail;
 
-	return iscsi_handle(session);
+	return shost;
 
 r2tpool_alloc_fail:
 	for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++)
@@ -3321,15 +3330,15 @@
 mgmtpool_alloc_fail:
 	iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
 cmdpool_alloc_fail:
-	return iscsi_handle(NULL);
+	return NULL;
 }
 
 static void
-iscsi_session_destroy(iscsi_sessionh_t sessionh)
+iscsi_session_destroy(struct Scsi_Host *shost)
 {
+	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
 	int cmd_i;
 	struct iscsi_data_task *dtask, *n;
-	struct iscsi_session *session = iscsi_ptr(sessionh);
 
 	for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
 		struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
@@ -3345,6 +3354,8 @@
 	iscsi_r2tpool_free(session);
 	iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
 	iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
+
+	iscsi_transport_destroy_session(shost);
 }
 
 static int
@@ -3493,25 +3504,12 @@
 }
 
 static int
-iscsi_conn_get_param(iscsi_connh_t connh, enum iscsi_param param,
-		     uint32_t *value)
+iscsi_session_get_param(struct Scsi_Host *shost,
+			enum iscsi_param param, uint32_t *value)
 {
-	struct iscsi_conn *conn = iscsi_ptr(connh);
-	struct iscsi_session *session = conn->session;
+	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
 
 	switch(param) {
-	case ISCSI_PARAM_MAX_RECV_DLENGTH:
-		*value = conn->max_recv_dlength;
-		break;
-	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
-		*value = conn->max_xmit_dlength;
-		break;
-	case ISCSI_PARAM_HDRDGST_EN:
-		*value = conn->hdrdgst_en;
-		break;
-	case ISCSI_PARAM_DATADGST_EN:
-		*value = conn->datadgst_en;
-		break;
 	case ISCSI_PARAM_INITIAL_R2T_EN:
 		*value = session->initial_r2t_en;
 		break;
@@ -3549,6 +3547,31 @@
 	return 0;
 }
 
+static int
+iscsi_conn_get_param(void *data, enum iscsi_param param, uint32_t *value)
+{
+	struct iscsi_conn *conn = data;
+
+	switch(param) {
+	case ISCSI_PARAM_MAX_RECV_DLENGTH:
+		*value = conn->max_recv_dlength;
+		break;
+	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+		*value = conn->max_xmit_dlength;
+		break;
+	case ISCSI_PARAM_HDRDGST_EN:
+		*value = conn->hdrdgst_en;
+		break;
+	case ISCSI_PARAM_DATADGST_EN:
+		*value = conn->datadgst_en;
+		break;
+	default:
+		return ISCSI_ERR_PARAM_NOT_FOUND;
+	}
+
+	return 0;
+}
+
 static void
 iscsi_conn_get_stats(iscsi_connh_t connh, struct iscsi_stats *stats)
 {
@@ -3593,6 +3616,7 @@
 				  | CAP_DATADGST,
 	.host_template		= &iscsi_sht,
 	.hostdata_size		= sizeof(struct iscsi_session),
+	.conndata_size		= sizeof(struct iscsi_conn),
 	.max_conn		= 1,
 	.max_cmd_len		= ISCSI_TCP_MAX_CMD_LEN,
 	.create_session		= iscsi_session_create,
@@ -3601,7 +3625,8 @@
 	.bind_conn		= iscsi_conn_bind,
 	.destroy_conn		= iscsi_conn_destroy,
 	.set_param		= iscsi_conn_set_param,
-	.get_param		= iscsi_conn_get_param,
+	.get_conn_param		= iscsi_conn_get_param,
+	.get_session_param	= iscsi_session_get_param,
 	.start_conn		= iscsi_conn_start,
 	.stop_conn		= iscsi_conn_stop,
 	.send_pdu		= iscsi_conn_send_pdu,
@@ -3611,8 +3636,6 @@
 static int __init
 iscsi_tcp_init(void)
 {
-	int error;
-
 	if (iscsi_max_lun < 1) {
 		printk(KERN_ERR "Invalid max_lun value of %u\n", iscsi_max_lun);
 		return -EINVAL;
@@ -3625,11 +3648,10 @@
 	if (!taskcache)
 		return -ENOMEM;
 
-	error = iscsi_register_transport(&iscsi_tcp_transport);
-	if (error)
+	if (!iscsi_register_transport(&iscsi_tcp_transport))
 		kmem_cache_destroy(taskcache);
 
-	return error;
+	return 0;
 }
 
 static void __exit
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 50ed88f..45e3163 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -21,12 +21,9 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 #include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
 #include <linux/mempool.h>
 #include <linux/mutex.h>
 #include <net/tcp.h>
-
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
@@ -46,11 +43,6 @@
 	 */
 	struct list_head sessions;
 	/*
-	 * lock to serialize access to the sessions list which must
-	 * be taken after the rx_queue_mutex
-	 */
-	spinlock_t session_lock;
-	/*
 	 * based on transport capabilities, at register time we set these
 	 * bits to tell the transport class it wants attributes displayed
 	 * in sysfs or that it can support different iSCSI Data-Path
@@ -157,7 +149,7 @@
 	spinlock_t freelock;
 };
 
-static struct mempool_zone z_reply;
+static struct mempool_zone *z_reply;
 
 /*
  * Z_MAX_* - actual mempool size allocated at the mempool_zone_init() time
@@ -172,50 +164,270 @@
 #define Z_MAX_ERROR	16
 #define Z_HIWAT_ERROR	12
 
-struct iscsi_if_conn {
-	struct list_head conn_list;	/* item in connlist */
-	struct list_head session_list;	/* item in session->connections */
-	iscsi_connh_t connh;
-	int active;			/* must be accessed with the connlock */
-	struct Scsi_Host *host;		/* originated shost */
-	struct device dev;		/* sysfs transport/container device */
-	struct iscsi_transport *transport;
-	struct mempool_zone z_error;
-	struct mempool_zone z_pdu;
-	struct list_head freequeue;
-};
-
-#define iscsi_dev_to_if_conn(_dev) \
-	container_of(_dev, struct iscsi_if_conn, dev)
-
-#define iscsi_cdev_to_if_conn(_cdev) \
-	iscsi_dev_to_if_conn(_cdev->dev)
-
 static LIST_HEAD(connlist);
 static DEFINE_SPINLOCK(connlock);
 
-struct iscsi_if_session {
-	struct list_head list;	/* item in session_list */
-	struct list_head connections;
-	iscsi_sessionh_t sessionh;
-	struct iscsi_transport *transport;
-	struct device dev;	/* sysfs transport/container device */
-};
+/*
+ * The following functions can be used by LLDs that allocate
+ * their own scsi_hosts or by software iscsi LLDs
+ */
+static void iscsi_session_release(struct device *dev)
+{
+	struct iscsi_cls_session *session = iscsi_dev_to_session(dev);
+	struct iscsi_transport *transport = session->transport;
+	struct Scsi_Host *shost;
 
-#define iscsi_dev_to_if_session(_dev) \
-	container_of(_dev, struct iscsi_if_session, dev)
+	shost = iscsi_session_to_shost(session);
+	scsi_host_put(shost);
+	kfree(session);
+	module_put(transport->owner);
+}
 
-#define iscsi_cdev_to_if_session(_cdev) \
-	iscsi_dev_to_if_session(_cdev->dev)
+static int iscsi_is_session_dev(const struct device *dev)
+{
+	return dev->release == iscsi_session_release;
+}
 
-#define iscsi_if_session_to_shost(_session) \
-	dev_to_shost(_session->dev.parent)
+/**
+ * iscsi_create_session - create iscsi class session
+ * @shost: scsi host
+ * @transport: iscsi transport
+ *
+ * This can be called from a LLD or iscsi_transport
+ **/
+struct iscsi_cls_session *
+iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport)
+{
+	struct iscsi_cls_session *session;
+	int err;
 
-static struct iscsi_if_conn*
+	if (!try_module_get(transport->owner))
+		return NULL;
+
+	session = kzalloc(sizeof(*session), GFP_KERNEL);
+	if (!session)
+		goto module_put;
+	session->transport = transport;
+
+	/* this is released in the dev's release function */
+	scsi_host_get(shost);
+	snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", shost->host_no);
+	session->dev.parent = &shost->shost_gendev;
+	session->dev.release = iscsi_session_release;
+	err = device_register(&session->dev);
+	if (err) {
+		dev_printk(KERN_ERR, &session->dev, "iscsi: could not "
+			   "register session's dev\n");
+		goto free_session;
+	}
+	transport_register_device(&session->dev);
+
+	return session;
+
+free_session:
+	kfree(session);
+module_put:
+	module_put(transport->owner);
+	return NULL;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_create_session);
+
+/**
+ * iscsi_destroy_session - destroy iscsi session
+ * @session: iscsi_session
+ *
+ * Can be called by a LLD or iscsi_transport. There must not be
+ * any running connections.
+ **/
+int iscsi_destroy_session(struct iscsi_cls_session *session)
+{
+	transport_unregister_device(&session->dev);
+	device_unregister(&session->dev);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_destroy_session);
+
+static void iscsi_conn_release(struct device *dev)
+{
+	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
+	struct device *parent = conn->dev.parent;
+
+	kfree(conn);
+	put_device(parent);
+}
+
+static int iscsi_is_conn_dev(const struct device *dev)
+{
+	return dev->release == iscsi_conn_release;
+}
+
+/**
+ * iscsi_create_conn - create iscsi class connection
+ * @session: iscsi cls session
+ * @cid: connection id
+ *
+ * This can be called from a LLD or iscsi_transport. The connection
+ * is child of the session so cid must be unique for all connections
+ * on the session.
+ **/
+struct iscsi_cls_conn *
+iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
+{
+	struct iscsi_transport *transport = session->transport;
+	struct Scsi_Host *shost = iscsi_session_to_shost(session);
+	struct iscsi_cls_conn *conn;
+	int err;
+
+	conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL);
+	if (!conn)
+		return NULL;
+
+	if (transport->conndata_size)
+		conn->dd_data = &conn[1];
+
+	INIT_LIST_HEAD(&conn->conn_list);
+	conn->transport = transport;
+
+	/* this is released in the dev's release function */
+	if (!get_device(&session->dev))
+		goto free_conn;
+	snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
+		 shost->host_no, cid);
+	conn->dev.parent = &session->dev;
+	conn->dev.release = iscsi_conn_release;
+	err = device_register(&conn->dev);
+	if (err) {
+		dev_printk(KERN_ERR, &conn->dev, "iscsi: could not register "
+			   "connection's dev\n");
+		goto release_parent_ref;
+	}
+	transport_register_device(&conn->dev);
+	return conn;
+
+release_parent_ref:
+	put_device(&session->dev);
+free_conn:
+	kfree(conn);
+	return NULL;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_create_conn);
+
+/**
+ * iscsi_destroy_conn - destroy iscsi class connection
+ * @session: iscsi cls session
+ *
+ * This can be called from a LLD or iscsi_transport.
+ **/
+int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
+{
+	transport_unregister_device(&conn->dev);
+	device_unregister(&conn->dev);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
+
+/*
+ * These functions are used only by software iscsi_transports
+ * which do not allocate and more their scsi_hosts since this
+ * is initiated from userspace.
+ */
+
+/*
+ * iSCSI Session's hostdata organization:
+ *
+ *    *------------------* <== hostdata_session(host->hostdata)
+ *    | ptr to class sess|
+ *    |------------------| <== iscsi_hostdata(host->hostdata)
+ *    | transport's data |
+ *    *------------------*
+ */
+
+#define hostdata_privsize(_t)	(sizeof(unsigned long) + _t->hostdata_size + \
+				 _t->hostdata_size % sizeof(unsigned long))
+
+#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
+
+/**
+ * iscsi_transport_create_session - create iscsi cls session and host
+ * scsit: scsi transport template
+ * transport: iscsi transport template
+ *
+ * This can be used by software iscsi_transports that allocate
+ * a session per scsi host.
+ **/
+struct Scsi_Host *
+iscsi_transport_create_session(struct scsi_transport_template *scsit,
+			       struct iscsi_transport *transport)
+{
+	struct iscsi_cls_session *session;
+	struct Scsi_Host *shost;
+
+	shost = scsi_host_alloc(transport->host_template,
+				hostdata_privsize(transport));
+	if (!shost) {
+		printk(KERN_ERR "iscsi: can not allocate SCSI host for "
+			"session\n");
+		return NULL;
+	}
+
+	shost->max_id = 1;
+	shost->max_channel = 0;
+	shost->max_lun = transport->max_lun;
+	shost->max_cmd_len = transport->max_cmd_len;
+	shost->transportt = scsit;
+
+	if (scsi_add_host(shost, NULL))
+		goto free_host;
+
+	session = iscsi_create_session(shost, transport);
+	if (!session)
+		goto remove_host;
+
+	*(unsigned long*)shost->hostdata = (unsigned long)session;
+	return shost;
+
+remove_host:
+	scsi_remove_host(shost);
+free_host:
+	scsi_host_put(shost);
+	return NULL;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_transport_create_session);
+
+/**
+ * iscsi_transport_destroy_session - destroy session and scsi host
+ * shost: scsi host
+ *
+ * This can be used by software iscsi_transports that allocate
+ * a session per scsi host.
+ **/
+int iscsi_transport_destroy_session(struct Scsi_Host *shost)
+{
+	struct iscsi_cls_session *session;
+
+	scsi_remove_host(shost);
+	session = hostdata_session(shost->hostdata);
+	iscsi_destroy_session(session);
+	/* ref from host alloc */
+	scsi_host_put(shost);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_transport_destroy_session);
+
+/*
+ * iscsi interface functions
+ */
+static struct iscsi_cls_conn*
 iscsi_if_find_conn(uint64_t key)
 {
 	unsigned long flags;
-	struct iscsi_if_conn *conn;
+	struct iscsi_cls_conn *conn;
 
 	spin_lock_irqsave(&connlock, flags);
 	list_for_each_entry(conn, &connlist, conn_list)
@@ -250,7 +462,7 @@
 }
 
 static void*
-mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data)
+mempool_zone_alloc_skb(unsigned int gfp_mask, void *pool_data)
 {
 	struct mempool_zone *zone = pool_data;
 
@@ -282,14 +494,21 @@
 	spin_unlock_irqrestore(&zone->freelock, flags);
 }
 
-static int
-mempool_zone_init(struct mempool_zone *zp, unsigned max, unsigned size,
-		unsigned hiwat)
+static struct mempool_zone *
+mempool_zone_init(unsigned max, unsigned size, unsigned hiwat)
 {
+	struct mempool_zone *zp;
+
+	zp = kzalloc(sizeof(*zp), GFP_KERNEL);
+	if (!zp)
+		return NULL;
+
 	zp->pool = mempool_create(max, mempool_zone_alloc_skb,
 				  mempool_zone_free_skb, zp);
-	if (!zp->pool)
-		return -ENOMEM;
+	if (!zp->pool) {
+		kfree(zp);
+		return NULL;
+	}
 
 	zp->size = size;
 	zp->hiwat = hiwat;
@@ -298,9 +517,14 @@
 	spin_lock_init(&zp->freelock);
 	atomic_set(&zp->allocated, 0);
 
-	return 0;
+	return zp;
 }
 
+static void mempool_zone_destroy(struct mempool_zone *zp)
+{
+	mempool_destroy(zp->pool);
+	kfree(zp);
+}
 
 static struct sk_buff*
 mempool_zone_get_skb(struct mempool_zone *zone)
@@ -340,7 +564,7 @@
 	struct nlmsghdr	*nlh;
 	struct sk_buff *skb;
 	struct iscsi_uevent *ev;
-	struct iscsi_if_conn *conn;
+	struct iscsi_cls_conn *conn;
 	char *pdu;
 	int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) +
 			      data_size);
@@ -348,13 +572,13 @@
 	conn = iscsi_if_find_conn(connh);
 	BUG_ON(!conn);
 
-	mempool_zone_complete(&conn->z_pdu);
+	mempool_zone_complete(conn->z_pdu);
 
-	skb = mempool_zone_get_skb(&conn->z_pdu);
+	skb = mempool_zone_get_skb(conn->z_pdu);
 	if (!skb) {
 		iscsi_conn_error(connh, ISCSI_ERR_CONN_FAILED);
-		printk(KERN_ERR "iscsi%d: can not deliver control PDU: OOM\n",
-		       conn->host->host_no);
+		dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver "
+			   "control PDU: OOM\n");
 		return -ENOMEM;
 	}
 
@@ -363,14 +587,14 @@
 	memset(ev, 0, sizeof(*ev));
 	ev->transport_handle = iscsi_handle(conn->transport);
 	ev->type = ISCSI_KEVENT_RECV_PDU;
-	if (atomic_read(&conn->z_pdu.allocated) >= conn->z_pdu.hiwat)
+	if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat)
 		ev->iferror = -ENOMEM;
 	ev->r.recv_req.conn_handle = connh;
 	pdu = (char*)ev + sizeof(*ev);
 	memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
 	memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
 
-	return iscsi_unicast_skb(&conn->z_pdu, skb);
+	return iscsi_unicast_skb(conn->z_pdu, skb);
 }
 EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
 
@@ -379,18 +603,18 @@
 	struct nlmsghdr	*nlh;
 	struct sk_buff	*skb;
 	struct iscsi_uevent *ev;
-	struct iscsi_if_conn *conn;
+	struct iscsi_cls_conn *conn;
 	int len = NLMSG_SPACE(sizeof(*ev));
 
 	conn = iscsi_if_find_conn(connh);
 	BUG_ON(!conn);
 
-	mempool_zone_complete(&conn->z_error);
+	mempool_zone_complete(conn->z_error);
 
-	skb = mempool_zone_get_skb(&conn->z_error);
+	skb = mempool_zone_get_skb(conn->z_error);
 	if (!skb) {
-		printk(KERN_ERR "iscsi%d: gracefully ignored conn error (%d)\n",
-		       conn->host->host_no, error);
+		dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored "
+			  "conn error (%d)\n", error);
 		return;
 	}
 
@@ -398,15 +622,15 @@
 	ev = NLMSG_DATA(nlh);
 	ev->transport_handle = iscsi_handle(conn->transport);
 	ev->type = ISCSI_KEVENT_CONN_ERROR;
-	if (atomic_read(&conn->z_error.allocated) >= conn->z_error.hiwat)
+	if (atomic_read(&conn->z_error->allocated) >= conn->z_error->hiwat)
 		ev->iferror = -ENOMEM;
 	ev->r.connerror.error = error;
 	ev->r.connerror.conn_handle = connh;
 
-	iscsi_unicast_skb(&conn->z_error, skb);
+	iscsi_unicast_skb(conn->z_error, skb);
 
-	printk(KERN_INFO "iscsi%d: detected conn error (%d)\n",
-	       conn->host->host_no, error);
+	dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n",
+		   error);
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_error);
 
@@ -420,9 +644,9 @@
 	int flags = multi ? NLM_F_MULTI : 0;
 	int t = done ? NLMSG_DONE : type;
 
-	mempool_zone_complete(&z_reply);
+	mempool_zone_complete(z_reply);
 
-	skb = mempool_zone_get_skb(&z_reply);
+	skb = mempool_zone_get_skb(z_reply);
 	/*
 	 * FIXME:
 	 * user is supposed to react on iferror == -ENOMEM;
@@ -433,304 +657,7 @@
 	nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0);
 	nlh->nlmsg_flags = flags;
 	memcpy(NLMSG_DATA(nlh), payload, size);
-	return iscsi_unicast_skb(&z_reply, skb);
-}
-
-/*
- * iSCSI Session's hostdata organization:
- *
- *    *------------------* <== host->hostdata
- *    | transport        |
- *    |------------------| <== iscsi_hostdata(host->hostdata)
- *    | transport's data |
- *    |------------------| <== hostdata_session(host->hostdata)
- *    | interface's data |
- *    *------------------*
- */
-
-#define hostdata_privsize(_t)	(sizeof(unsigned long) + _t->hostdata_size + \
-				 _t->hostdata_size % sizeof(unsigned long) + \
-				 sizeof(struct iscsi_if_session))
-
-#define hostdata_session(_hostdata) ((void*)_hostdata + sizeof(unsigned long) + \
-			((struct iscsi_transport *) \
-			 iscsi_ptr(*(uint64_t *)_hostdata))->hostdata_size)
-
-static void iscsi_if_session_dev_release(struct device *dev)
-{
-	struct iscsi_if_session *session = iscsi_dev_to_if_session(dev);
-	struct iscsi_transport *transport = session->transport;
-	struct Scsi_Host *shost = iscsi_if_session_to_shost(session);
-	struct iscsi_if_conn *conn, *tmp;
-	unsigned long flags;
-
-	/* now free connections */
-	spin_lock_irqsave(&connlock, flags);
-	list_for_each_entry_safe(conn, tmp, &session->connections,
-				 session_list) {
-		list_del(&conn->session_list);
-		mempool_destroy(conn->z_pdu.pool);
-		mempool_destroy(conn->z_error.pool);
-		kfree(conn);
-	}
-	spin_unlock_irqrestore(&connlock, flags);
-	scsi_host_put(shost);
-	module_put(transport->owner);
-}
-
-static int
-iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
-{
-	struct iscsi_transport *transport = priv->iscsi_transport;
-	struct iscsi_if_session *session;
-	struct Scsi_Host *shost;
-	unsigned long flags;
-	int error;
-
-	if (!try_module_get(transport->owner))
-		return -EPERM;
-
-	shost = scsi_host_alloc(transport->host_template,
-				hostdata_privsize(transport));
-	if (!shost) {
-		ev->r.c_session_ret.session_handle = iscsi_handle(NULL);
-		printk(KERN_ERR "iscsi: can not allocate SCSI host for "
-		       "session\n");
-		error = -ENOMEM;
-		goto out_module_put;
-	}
-	shost->max_id = 1;
-	shost->max_channel = 0;
-	shost->max_lun = transport->max_lun;
-	shost->max_cmd_len = transport->max_cmd_len;
-	shost->transportt = &priv->t;
-
-	/* store struct iscsi_transport in hostdata */
-	*(uint64_t*)shost->hostdata = ev->transport_handle;
-
-	ev->r.c_session_ret.session_handle = transport->create_session(
-					ev->u.c_session.initial_cmdsn, shost);
-	if (ev->r.c_session_ret.session_handle == iscsi_handle(NULL)) {
-		error = 0;
-		goto out_host_put;
-	}
-
-	/* host_no becomes assigned SID */
-	ev->r.c_session_ret.sid = shost->host_no;
-	/* initialize session */
-	session = hostdata_session(shost->hostdata);
-	INIT_LIST_HEAD(&session->connections);
-	INIT_LIST_HEAD(&session->list);
-	session->sessionh = ev->r.c_session_ret.session_handle;
-	session->transport = transport;
-
-	error = scsi_add_host(shost, NULL);
-	if (error)
-		goto out_destroy_session;
-
-	/*
-	 * this is released in the dev's release function)
-	 */
-	scsi_host_get(shost);
-	snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", shost->host_no);
-	session->dev.parent = &shost->shost_gendev;
-	session->dev.release = iscsi_if_session_dev_release;
-	error = device_register(&session->dev);
-	if (error) {
-		printk(KERN_ERR "iscsi: could not register session%d's dev\n",
-		       shost->host_no);
-		goto out_remove_host;
-	}
-	transport_register_device(&session->dev);
-
-	/* add this session to the list of active sessions */
-	spin_lock_irqsave(&priv->session_lock, flags);
-	list_add(&session->list, &priv->sessions);
-	spin_unlock_irqrestore(&priv->session_lock, flags);
-
-	return 0;
-
-out_remove_host:
-	scsi_remove_host(shost);
-out_destroy_session:
-	transport->destroy_session(ev->r.c_session_ret.session_handle);
-	ev->r.c_session_ret.session_handle = iscsi_handle(NULL);
-out_host_put:
-	scsi_host_put(shost);
-out_module_put:
-	module_put(transport->owner);
-	return error;
-}
-
-static int
-iscsi_if_destroy_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
-{
-	struct iscsi_transport *transport = priv->iscsi_transport;
-	struct Scsi_Host *shost;
-	struct iscsi_if_session *session;
-	unsigned long flags;
-	struct iscsi_if_conn *conn;
-	int error = 0;
-
-	shost = scsi_host_lookup(ev->u.d_session.sid);
-	if (shost == ERR_PTR(-ENXIO))
-		return -EEXIST;
-	session = hostdata_session(shost->hostdata);
-
-	/* check if we have active connections */
-	spin_lock_irqsave(&connlock, flags);
-	list_for_each_entry(conn, &session->connections, session_list) {
-		if (conn->active) {
-			printk(KERN_ERR "iscsi%d: can not destroy session: "
-			       "has active connection (%p)\n",
-			       shost->host_no, iscsi_ptr(conn->connh));
-			spin_unlock_irqrestore(&connlock, flags);
-			error = EIO;
-			goto out_release_ref;
-		}
-	}
-	spin_unlock_irqrestore(&connlock, flags);
-
-	scsi_remove_host(shost);
-	transport->destroy_session(ev->u.d_session.session_handle);
-	transport_unregister_device(&session->dev);
-	device_unregister(&session->dev);
-
-	/* remove this session from the list of active sessions */
-	spin_lock_irqsave(&priv->session_lock, flags);
-	list_del(&session->list);
-	spin_unlock_irqrestore(&priv->session_lock, flags);
-
-	/* ref from host alloc */
-	scsi_host_put(shost);
-out_release_ref:
-	/* ref from host lookup */
-	scsi_host_put(shost);
-	return error;
-}
-
-static void iscsi_if_conn_dev_release(struct device *dev)
-{
-	struct iscsi_if_conn *conn = iscsi_dev_to_if_conn(dev);
-	struct Scsi_Host *shost = conn->host;
-
-	scsi_host_put(shost);
-}
-
-static int
-iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
-{
-	struct iscsi_if_session *session;
-	struct Scsi_Host *shost;
-	struct iscsi_if_conn *conn;
-	unsigned long flags;
-	int error;
-
-	shost = scsi_host_lookup(ev->u.c_conn.sid);
-	if (shost == ERR_PTR(-ENXIO))
-		return -EEXIST;
-	session = hostdata_session(shost->hostdata);
-
-	conn = kmalloc(sizeof(struct iscsi_if_conn), GFP_KERNEL);
-	if (!conn) {
-		error = -ENOMEM;
-		goto out_release_ref;
-	}
-	memset(conn, 0, sizeof(struct iscsi_if_conn));
-	INIT_LIST_HEAD(&conn->session_list);
-	INIT_LIST_HEAD(&conn->conn_list);
-	conn->host = shost;
-	conn->transport = transport;
-
-	error = mempool_zone_init(&conn->z_pdu, Z_MAX_PDU,
-			NLMSG_SPACE(sizeof(struct iscsi_uevent) +
-				    sizeof(struct iscsi_hdr) +
-				    DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH),
-			Z_HIWAT_PDU);
-	if (error) {
-		printk(KERN_ERR "iscsi%d: can not allocate pdu zone for new "
-		       "conn\n", shost->host_no);
-		goto out_free_conn;
-	}
-	error = mempool_zone_init(&conn->z_error, Z_MAX_ERROR,
-			NLMSG_SPACE(sizeof(struct iscsi_uevent)),
-			Z_HIWAT_ERROR);
-	if (error) {
-		printk(KERN_ERR "iscsi%d: can not allocate error zone for "
-		       "new conn\n", shost->host_no);
-		goto out_free_pdu_pool;
-	}
-
-	ev->r.handle = transport->create_conn(ev->u.c_conn.session_handle,
-					ev->u.c_conn.cid);
-	if (!ev->r.handle) {
-		error = -ENODEV;
-		goto out_free_error_pool;
-	}
-
-	conn->connh = ev->r.handle;
-
-	/*
-	 * this is released in the dev's release function
-	 */
-	if (!scsi_host_get(shost))
-		goto out_destroy_conn;
-	snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
-		 shost->host_no, ev->u.c_conn.cid);
-	conn->dev.parent = &session->dev;
-	conn->dev.release = iscsi_if_conn_dev_release;
-	error = device_register(&conn->dev);
-	if (error) {
-		printk(KERN_ERR "iscsi%d: could not register connections%u "
-		       "dev\n", shost->host_no, ev->u.c_conn.cid);
-		goto out_release_parent_ref;
-	}
-	transport_register_device(&conn->dev);
-
-	spin_lock_irqsave(&connlock, flags);
-	list_add(&conn->conn_list, &connlist);
-	list_add(&conn->session_list, &session->connections);
-	conn->active = 1;
-	spin_unlock_irqrestore(&connlock, flags);
-
-	scsi_host_put(shost);
-	return 0;
-
-out_release_parent_ref:
-	scsi_host_put(shost);
-out_destroy_conn:
-	transport->destroy_conn(ev->r.handle);
-out_free_error_pool:
-	mempool_destroy(conn->z_error.pool);
-out_free_pdu_pool:
-	mempool_destroy(conn->z_pdu.pool);
-out_free_conn:
-	kfree(conn);
-out_release_ref:
-	scsi_host_put(shost);
-	return error;
-}
-
-static int
-iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
-{
-	unsigned long flags;
-	struct iscsi_if_conn *conn;
-
-	conn = iscsi_if_find_conn(ev->u.d_conn.conn_handle);
-	if (!conn)
-		return -EEXIST;
-
-	transport->destroy_conn(ev->u.d_conn.conn_handle);
-
-	spin_lock_irqsave(&connlock, flags);
-	conn->active = 0;
-	list_del(&conn->conn_list);
-	spin_unlock_irqrestore(&connlock, flags);
-
-	transport_unregister_device(&conn->dev);
-	device_unregister(&conn->dev);
-	return 0;
+	return iscsi_unicast_skb(z_reply, skb);
 }
 
 static int
@@ -740,7 +667,7 @@
 	struct iscsi_uevent *ev = NLMSG_DATA(nlh);
 	struct iscsi_stats *stats;
 	struct sk_buff *skbstat;
-	struct iscsi_if_conn *conn;
+	struct iscsi_cls_conn *conn;
 	struct nlmsghdr	*nlhstat;
 	struct iscsi_uevent *evstat;
 	int len = NLMSG_SPACE(sizeof(*ev) +
@@ -756,12 +683,12 @@
 	do {
 		int actual_size;
 
-		mempool_zone_complete(&conn->z_pdu);
+		mempool_zone_complete(conn->z_pdu);
 
-		skbstat = mempool_zone_get_skb(&conn->z_pdu);
+		skbstat = mempool_zone_get_skb(conn->z_pdu);
 		if (!skbstat) {
-			printk(KERN_ERR "iscsi%d: can not deliver stats: OOM\n",
-			       conn->host->host_no);
+			dev_printk(KERN_ERR, &conn->dev, "iscsi: can not "
+				   "deliver stats: OOM\n");
 			return -ENOMEM;
 		}
 
@@ -771,7 +698,7 @@
 		memset(evstat, 0, sizeof(*evstat));
 		evstat->transport_handle = iscsi_handle(conn->transport);
 		evstat->type = nlh->nlmsg_type;
-		if (atomic_read(&conn->z_pdu.allocated) >= conn->z_pdu.hiwat)
+		if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat)
 			evstat->iferror = -ENOMEM;
 		evstat->u.get_stats.conn_handle =
 			ev->u.get_stats.conn_handle;
@@ -789,13 +716,141 @@
 		skb_trim(skb, NLMSG_ALIGN(actual_size));
 		nlhstat->nlmsg_len = actual_size;
 
-		err = iscsi_unicast_skb(&conn->z_pdu, skbstat);
+		err = iscsi_unicast_skb(conn->z_pdu, skbstat);
 	} while (err < 0 && err != -ECONNREFUSED);
 
 	return err;
 }
 
 static int
+iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
+{
+	struct iscsi_transport *transport = priv->iscsi_transport;
+	struct Scsi_Host *shost;
+
+	if (!transport->create_session)
+		return -EINVAL;
+
+	shost = transport->create_session(&priv->t,
+					  ev->u.c_session.initial_cmdsn);
+	if (!shost)
+		return -ENOMEM;
+
+	ev->r.c_session_ret.session_handle = iscsi_handle(iscsi_hostdata(shost->hostdata));
+	ev->r.c_session_ret.sid = shost->host_no;
+	return 0;
+}
+
+static int
+iscsi_if_destroy_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
+{
+	struct iscsi_transport *transport = priv->iscsi_transport;
+
+	struct Scsi_Host *shost;
+
+	if (!transport->destroy_session)
+		return -EINVAL;
+
+	shost = scsi_host_lookup(ev->u.d_session.sid);
+	if (shost == ERR_PTR(-ENXIO))
+		return -EEXIST;
+
+	if (transport->destroy_session)
+		transport->destroy_session(shost);
+        /* ref from host lookup */
+        scsi_host_put(shost);
+	return 0;
+}
+
+static int
+iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev){
+	struct Scsi_Host *shost;
+	struct iscsi_cls_conn *conn;
+	unsigned long flags;
+
+	if (!transport->create_conn)
+		return -EINVAL;
+
+	shost = scsi_host_lookup(ev->u.c_conn.sid);
+	if (shost == ERR_PTR(-ENXIO))
+		return -EEXIST;
+
+	conn = transport->create_conn(shost, ev->u.c_conn.cid);
+	if (!conn)
+		goto release_ref;
+
+	conn->z_pdu = mempool_zone_init(Z_MAX_PDU,
+			NLMSG_SPACE(sizeof(struct iscsi_uevent) +
+				    sizeof(struct iscsi_hdr) +
+				    DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH),
+			Z_HIWAT_PDU);
+	if (!conn->z_pdu) {
+		dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
+			   "pdu zone for new conn\n");
+		goto destroy_conn;
+	}
+
+	conn->z_error = mempool_zone_init(Z_MAX_ERROR,
+			NLMSG_SPACE(sizeof(struct iscsi_uevent)),
+			Z_HIWAT_ERROR);
+	if (!conn->z_error) {
+		dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
+			   "error zone for new conn\n");
+		goto free_pdu_pool;
+	}
+
+	ev->r.handle = conn->connh = iscsi_handle(conn->dd_data);
+
+	spin_lock_irqsave(&connlock, flags);
+	list_add(&conn->conn_list, &connlist);
+	conn->active = 1;
+	spin_unlock_irqrestore(&connlock, flags);
+
+	scsi_host_put(shost);
+	return 0;
+
+free_pdu_pool:
+	mempool_zone_destroy(conn->z_pdu);
+destroy_conn:
+	if (transport->destroy_conn)
+		transport->destroy_conn(conn->dd_data);
+release_ref:
+	scsi_host_put(shost);
+	return -ENOMEM;
+}
+
+static int
+iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
+{
+	unsigned long flags;
+	struct iscsi_cls_conn *conn;
+	struct mempool_zone *z_error, *z_pdu;
+
+	conn = iscsi_if_find_conn(ev->u.d_conn.conn_handle);
+	if (!conn)
+		return -EEXIST;
+
+	if (!transport->destroy_conn)
+		return -EINVAL;
+
+	spin_lock_irqsave(&connlock, flags);
+	conn->active = 0;
+	list_del(&conn->conn_list);
+	spin_unlock_irqrestore(&connlock, flags);
+
+	z_pdu = conn->z_pdu;
+	z_error = conn->z_error;
+
+	if (transport->destroy_conn)
+		transport->destroy_conn(conn);
+
+	mempool_zone_destroy(z_pdu);
+	mempool_zone_destroy(z_error);
+
+	return 0;
+}
+
+static int
 iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
 	int err = 0;
@@ -916,8 +971,8 @@
 				err = iscsi_if_send_reply(
 					NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
 					nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-				if (atomic_read(&z_reply.allocated) >=
-						z_reply.hiwat)
+				if (atomic_read(&z_reply->allocated) >=
+						z_reply->hiwat)
 					ev->iferror = -ENOMEM;
 			} while (err < 0 && err != -ECONNREFUSED);
 			skb_pull(skb, rlen);
@@ -927,6 +982,9 @@
 	mutex_unlock(&rx_queue_mutex);
 }
 
+#define iscsi_cdev_to_conn(_cdev) \
+	iscsi_dev_to_conn(_cdev->dev)
+
 /*
  * iSCSI connection attrs
  */
@@ -935,12 +993,10 @@
 show_conn_int_param_##param(struct class_device *cdev, char *buf)	\
 {									\
 	uint32_t value = 0;						\
-	struct iscsi_if_conn *conn = iscsi_cdev_to_if_conn(cdev);	\
-	struct iscsi_internal *priv;					\
+	struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev);		\
+	struct iscsi_transport *t = conn->transport;			\
 									\
-	priv = to_iscsi_internal(conn->host->transportt);		\
-	if (priv->param_mask & (1 << param))				\
-		priv->iscsi_transport->get_param(conn->connh, param, &value); \
+	t->get_conn_param(conn->dd_data, param, &value);		\
 	return snprintf(buf, 20, format"\n", value);			\
 }
 
@@ -955,6 +1011,9 @@
 iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d");
 iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d");
 
+#define iscsi_cdev_to_session(_cdev) \
+	iscsi_dev_to_session(_cdev->dev)
+
 /*
  * iSCSI session attrs
  */
@@ -963,20 +1022,11 @@
 show_session_int_param_##param(struct class_device *cdev, char *buf)	\
 {									\
 	uint32_t value = 0;						\
-	struct iscsi_if_session *session = iscsi_cdev_to_if_session(cdev); \
-	struct Scsi_Host *shost = iscsi_if_session_to_shost(session);	\
-	struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
-	struct iscsi_if_conn *conn = NULL;				\
-	unsigned long  flags;						\
+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);	\
+	struct Scsi_Host *shost = iscsi_session_to_shost(session);	\
+	struct iscsi_transport *t = session->transport;			\
 									\
-	spin_lock_irqsave(&connlock, flags);				\
-	if (!list_empty(&session->connections))				\
-		conn = list_entry(session->connections.next,		\
-				  struct iscsi_if_conn, session_list);	\
-	spin_unlock_irqrestore(&connlock, flags);			\
-									\
-	if (conn && (priv->param_mask & (1 << param)))			\
-		priv->iscsi_transport->get_param(conn->connh, param, &value);\
+	t->get_session_param(shost, param, &value);			\
 	return snprintf(buf, 20, format"\n", value);			\
 }
 
@@ -1005,23 +1055,18 @@
 		count++;						\
 	}
 
-static int iscsi_is_session_dev(const struct device *dev)
-{
-	return dev->release == iscsi_if_session_dev_release;
-}
-
 static int iscsi_session_match(struct attribute_container *cont,
 			   struct device *dev)
 {
-	struct iscsi_if_session *session;
+	struct iscsi_cls_session *session;
 	struct Scsi_Host *shost;
 	struct iscsi_internal *priv;
 
 	if (!iscsi_is_session_dev(dev))
 		return 0;
 
-	session = iscsi_dev_to_if_session(dev);
-	shost = iscsi_if_session_to_shost(session);
+	session = iscsi_dev_to_session(dev);
+	shost = iscsi_session_to_shost(session);
 	if (!shost->transportt)
 		return 0;
 
@@ -1032,23 +1077,21 @@
 	return &priv->session_cont.ac == cont;
 }
 
-static int iscsi_is_conn_dev(const struct device *dev)
-{
-	return dev->release == iscsi_if_conn_dev_release;
-}
-
 static int iscsi_conn_match(struct attribute_container *cont,
 			   struct device *dev)
 {
-	struct iscsi_if_conn *conn;
+	struct iscsi_cls_session *session;
+	struct iscsi_cls_conn *conn;
 	struct Scsi_Host *shost;
 	struct iscsi_internal *priv;
 
 	if (!iscsi_is_conn_dev(dev))
 		return 0;
 
-	conn = iscsi_dev_to_if_conn(dev);
-	shost = conn->host;
+	conn = iscsi_dev_to_conn(dev);
+	session = iscsi_dev_to_session(conn->dev.parent);
+	shost = iscsi_session_to_shost(session);
+
 	if (!shost->transportt)
 		return 0;
 
@@ -1059,7 +1102,8 @@
 	return &priv->conn_cont.ac == cont;
 }
 
-int iscsi_register_transport(struct iscsi_transport *tt)
+struct scsi_transport_template *
+iscsi_register_transport(struct iscsi_transport *tt)
 {
 	struct iscsi_internal *priv;
 	unsigned long flags;
@@ -1069,15 +1113,14 @@
 
 	priv = iscsi_if_transport_lookup(tt);
 	if (priv)
-		return -EEXIST;
+		return NULL;
 
 	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
-		return -ENOMEM;
+		return NULL;
 	memset(priv, 0, sizeof(*priv));
 	INIT_LIST_HEAD(&priv->list);
 	INIT_LIST_HEAD(&priv->sessions);
-	spin_lock_init(&priv->session_lock);
 	priv->iscsi_transport = tt;
 
 	priv->cdev.class = &iscsi_transport_class;
@@ -1143,13 +1186,13 @@
 	spin_unlock_irqrestore(&iscsi_transport_lock, flags);
 
 	printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
-	return 0;
+	return &priv->t;
 
 unregister_cdev:
 	class_device_unregister(&priv->cdev);
 free_priv:
 	kfree(priv);
-	return err;
+	return NULL;
 }
 EXPORT_SYMBOL_GPL(iscsi_register_transport);
 
@@ -1165,14 +1208,6 @@
 	priv = iscsi_if_transport_lookup(tt);
 	BUG_ON (!priv);
 
-	spin_lock_irqsave(&priv->session_lock, flags);
-	if (!list_empty(&priv->sessions)) {
-		spin_unlock_irqrestore(&priv->session_lock, flags);
-		mutex_unlock(&rx_queue_mutex);
-		return -EPERM;
-	}
-	spin_unlock_irqrestore(&priv->session_lock, flags);
-
 	spin_lock_irqsave(&iscsi_transport_lock, flags);
 	list_del(&priv->list);
 	spin_unlock_irqrestore(&iscsi_transport_lock, flags);
@@ -1195,14 +1230,14 @@
 
 	if (event == NETLINK_URELEASE &&
 	    n->protocol == NETLINK_ISCSI && n->pid) {
-		struct iscsi_if_conn *conn;
+		struct iscsi_cls_conn *conn;
 		unsigned long flags;
 
-		mempool_zone_complete(&z_reply);
+		mempool_zone_complete(z_reply);
 		spin_lock_irqsave(&connlock, flags);
 		list_for_each_entry(conn, &connlist, conn_list) {
-			mempool_zone_complete(&conn->z_error);
-			mempool_zone_complete(&conn->z_pdu);
+			mempool_zone_complete(conn->z_error);
+			mempool_zone_complete(conn->z_pdu);
 		}
 		spin_unlock_irqrestore(&connlock, flags);
 	}
@@ -1235,15 +1270,15 @@
 		goto unregister_session_class;
 
 	nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx,
-				    THIS_MODULE);
+			THIS_MODULE);
 	if (!nls) {
 		err = -ENOBUFS;
 		goto unregister_notifier;
 	}
 
-	err = mempool_zone_init(&z_reply, Z_MAX_REPLY,
+	z_reply = mempool_zone_init(Z_MAX_REPLY,
 		NLMSG_SPACE(sizeof(struct iscsi_uevent)), Z_HIWAT_REPLY);
-	if (!err)
+	if (z_reply)
 		return 0;
 
 	sock_release(nls->sk_socket);
@@ -1260,7 +1295,7 @@
 
 static void __exit iscsi_transport_exit(void)
 {
-	mempool_destroy(z_reply.pool);
+	mempool_zone_destroy(z_reply);
 	sock_release(nls->sk_socket);
 	netlink_unregister_notifier(&iscsi_nl_notifier);
 	transport_class_unregister(&iscsi_connection_class);