[ofa-general] [PATCH 2/2] IB/iser: add backport & kernel addons for open-iscsi over iSER support for RHAS4 up3 and up4

Erez Zilber erezz at voltaire.com
Wed May 9 06:58:34 PDT 2007


Add the required backport patches & kernel addons for open-iscsi
over iSER in RHAS4 up3 and up4.

Signed-off-by: Erez Zilber <erezz at voltaire.com>
---
 .../2.6.9_U3/include/linux/attribute_container.h   |   71 +++
 .../backport/2.6.9_U3/include/linux/klist.h        |   61 ++
 .../backport/2.6.9_U3/include/scsi/scsi_device.h   |   19 +
 .../2.6.9_U3/include/scsi/scsi_transport.h         |    8 
 .../2.6.9_U3/include/src/attribute_container.c     |  438 +++++++++++++++++
 kernel_addons/backport/2.6.9_U3/include/src/base.h |    1 
 kernel_addons/backport/2.6.9_U3/include/src/init.c |   26 +
 .../backport/2.6.9_U3/include/src/klist.c          |  287 +++++++++++
 .../backport/2.6.9_U3/include/src/kref_new.c       |   29 +
 kernel_addons/backport/2.6.9_U3/include/src/scsi.c |   50 ++
 .../backport/2.6.9_U3/include/src/scsi_lib.c       |  164 ++++++
 .../backport/2.6.9_U3/include/src/scsi_scan.c      |   48 ++
 .../2.6.9_U3/include/src/transport_class.c         |  280 +++++++++++
 .../2.6.9_U4/include/linux/attribute_container.h   |   71 +++
 .../backport/2.6.9_U4/include/linux/klist.h        |   61 ++
 .../backport/2.6.9_U4/include/scsi/scsi_device.h   |   19 +
 .../2.6.9_U4/include/scsi/scsi_transport.h         |    8 
 .../2.6.9_U4/include/src/attribute_container.c     |  438 +++++++++++++++++
 kernel_addons/backport/2.6.9_U4/include/src/base.h |    1 
 kernel_addons/backport/2.6.9_U4/include/src/init.c |   26 +
 .../backport/2.6.9_U4/include/src/klist.c          |  287 +++++++++++
 .../backport/2.6.9_U4/include/src/kref_new.c       |   29 +
 kernel_addons/backport/2.6.9_U4/include/src/scsi.c |   50 ++
 .../backport/2.6.9_U4/include/src/scsi_lib.c       |  164 ++++++
 .../backport/2.6.9_U4/include/src/scsi_scan.c      |   48 ++
 .../2.6.9_U4/include/src/transport_class.c         |  280 +++++++++++
 .../backport/2.6.9_U3/add_iscsi_proto_h.patch      |  591 +++++++++++++++++++++++
 kernel_patches/backport/2.6.9_U3/add_iser.patch    |   13 
 .../backport/2.6.9_U3/add_memory_h.patch           |   93 ++++
 .../backport/2.6.9_U3/add_open_iscsi.patch         |  504 ++++++++++++++++++++
 .../backport/2.6.9_U3/add_open_iscsi_h.patch       |   60 ++
 .../backport/2.6.9_U3/add_transport_class_h.patch  |  104 ++++
 .../2.6.9_U3/fix_inclusion_order_iscsi_iser.patch  |   13 +
 .../backport/2.6.9_U3/linux_stuff_to_2_6_17.patch  |   58 ++
 .../2.6.9_U3/netlink-01-add_netlink_h.patch        |  247 ++++++++++
 .../2.6.9_U3/netlink-02-netlink_h_for_rh4.patch    |  200 ++++++++
 .../backport/2.6.9_U4/add_iscsi_proto_h.patch      |  591 +++++++++++++++++++++++
 kernel_patches/backport/2.6.9_U4/add_iser.patch    |   13 
 .../backport/2.6.9_U4/add_memory_h.patch           |   93 ++++
 .../backport/2.6.9_U4/add_open_iscsi.patch         |  504 ++++++++++++++++++++
 .../backport/2.6.9_U4/add_open_iscsi_h.patch       |   60 ++
 .../backport/2.6.9_U4/add_transport_class_h.patch  |  104 ++++
 .../2.6.9_U4/fix_inclusion_order_iscsi_iser.patch  |   13 +
 .../backport/2.6.9_U4/linux_stuff_to_2_6_17.patch  |   58 ++
 .../2.6.9_U4/netlink-01-add_netlink_h.patch        |  247 ++++++++++
 .../2.6.9_U4/netlink-02-netlink_h_for_rh4.patch    |  200 ++++++++
 46 files changed, 6728 insertions(+), 2 deletions(-)

diff --git a/kernel_addons/backport/2.6.9_U3/include/linux/attribute_container.h b/kernel_addons/backport/2.6.9_U3/include/linux/attribute_container.h
new file mode 100644
index 0000000..93bfb0b
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/linux/attribute_container.h
@@ -0,0 +1,71 @@
+/*
+ * class_container.h - a generic container for all classes
+ *
+ * Copyright (c) 2005 - James Bottomley <James.Bottomley at steeleye.com>
+ *
+ * This file is licensed under GPLv2
+ */
+
+#ifndef _ATTRIBUTE_CONTAINER_H_
+#define _ATTRIBUTE_CONTAINER_H_
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/klist.h>
+#include <linux/spinlock.h>
+
+struct attribute_container {
+	struct list_head	node;
+	struct klist		containers;
+	struct class		*class;
+	struct class_device_attribute **attrs;
+	int (*match)(struct attribute_container *, struct device *);
+#define	ATTRIBUTE_CONTAINER_NO_CLASSDEVS	0x01
+	unsigned long		flags;
+};
+
+static inline int
+attribute_container_no_classdevs(struct attribute_container *atc)
+{
+	return atc->flags & ATTRIBUTE_CONTAINER_NO_CLASSDEVS;
+}
+
+static inline void
+attribute_container_set_no_classdevs(struct attribute_container *atc)
+{
+	atc->flags |= ATTRIBUTE_CONTAINER_NO_CLASSDEVS;
+}
+
+int attribute_container_register(struct attribute_container *cont);
+int attribute_container_unregister(struct attribute_container *cont);
+void attribute_container_create_device(struct device *dev,
+				       int (*fn)(struct attribute_container *,
+						 struct device *,
+						 struct class_device *));
+void attribute_container_add_device(struct device *dev,
+				    int (*fn)(struct attribute_container *,
+					      struct device *,
+					      struct class_device *));
+void attribute_container_remove_device(struct device *dev,
+				       void (*fn)(struct attribute_container *,
+						  struct device *,
+						  struct class_device *));
+void attribute_container_device_trigger(struct device *dev, 
+					int (*fn)(struct attribute_container *,
+						  struct device *,
+						  struct class_device *));
+void attribute_container_trigger(struct device *dev, 
+				 int (*fn)(struct attribute_container *,
+					   struct device *));
+int attribute_container_add_attrs(struct class_device *classdev);
+int attribute_container_add_class_device(struct class_device *classdev);
+int attribute_container_add_class_device_adapter(struct attribute_container *cont,
+						 struct device *dev,
+						 struct class_device *classdev);
+void attribute_container_remove_attrs(struct class_device *classdev);
+void attribute_container_class_device_del(struct class_device *classdev);
+struct attribute_container *attribute_container_classdev_to_container(struct class_device *);
+struct class_device *attribute_container_find_class_device(struct attribute_container *, struct device *);
+struct class_device_attribute **attribute_container_classdev_to_attrs(const struct class_device *classdev);
+
+#endif
diff --git a/kernel_addons/backport/2.6.9_U3/include/linux/klist.h b/kernel_addons/backport/2.6.9_U3/include/linux/klist.h
new file mode 100644
index 0000000..7407125
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/linux/klist.h
@@ -0,0 +1,61 @@
+/*
+ *	klist.h - Some generic list helpers, extending struct list_head a bit.
+ *
+ *	Implementations are found in lib/klist.c
+ *
+ *
+ *	Copyright (C) 2005 Patrick Mochel
+ *
+ *	This file is rleased under the GPL v2.
+ */
+
+#ifndef _LINUX_KLIST_H
+#define _LINUX_KLIST_H
+
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+
+struct klist_node;
+struct klist {
+	spinlock_t		k_lock;
+	struct list_head	k_list;
+	void			(*get)(struct klist_node *);
+	void			(*put)(struct klist_node *);
+};
+
+
+extern void klist_init(struct klist * k, void (*get)(struct klist_node *),
+		       void (*put)(struct klist_node *));
+
+struct klist_node {
+	struct klist		* n_klist;
+	struct list_head	n_node;
+	struct kref		n_ref;
+	struct completion	n_removed;
+};
+
+extern void klist_add_tail(struct klist_node * n, struct klist * k);
+extern void klist_add_head(struct klist_node * n, struct klist * k);
+
+extern void klist_del(struct klist_node * n);
+extern void klist_remove(struct klist_node * n);
+
+extern int klist_node_attached(struct klist_node * n);
+
+
+struct klist_iter {
+	struct klist		* i_klist;
+	struct list_head	* i_head;
+	struct klist_node	* i_cur;
+};
+
+
+extern void klist_iter_init(struct klist * k, struct klist_iter * i);
+extern void klist_iter_init_node(struct klist * k, struct klist_iter * i, 
+				 struct klist_node * n);
+extern void klist_iter_exit(struct klist_iter * i);
+extern struct klist_node * klist_next(struct klist_iter * i);
+
+#endif
diff --git a/kernel_addons/backport/2.6.9_U3/include/scsi/scsi_device.h b/kernel_addons/backport/2.6.9_U3/include/scsi/scsi_device.h
new file mode 100644
index 0000000..f353e0b
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/scsi/scsi_device.h
@@ -0,0 +1,19 @@
+#ifndef _SCSI_SCSI_DEVICE_H_BACKPORT
+#define _SCSI_SCSI_DEVICE_H_BACKPORT
+
+#include_next <scsi/scsi_device.h>
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <asm/atomic.h>
+
+struct scsi_lun;
+
+extern void int_to_scsilun(unsigned int, struct scsi_lun *);
+extern void scsi_target_block(struct device *);
+extern void scsi_target_unblock(struct device *);
+extern void starget_for_each_device(struct scsi_target *, void *,
+		     void (*fn)(struct scsi_device *, void *));
+#endif /* _SCSI_SCSI_DEVICE_H_BACKPORT */
diff --git a/kernel_addons/backport/2.6.9_U3/include/scsi/scsi_transport.h b/kernel_addons/backport/2.6.9_U3/include/scsi/scsi_transport.h
new file mode 100644
index 0000000..99c2b12
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/scsi/scsi_transport.h
@@ -0,0 +1,8 @@
+#ifndef _SCSI_SCSI_TRANSPORT_H_BACKPORT
+#define _SCSI_SCSI_TRANSPORT_H_BACKPORT
+
+#include_next <scsi/scsi_transport.h>
+
+#include <linux/transport_class.h>
+
+#endif /* _SCSI_SCSI_TRANSPORT_H_BACKPORT */
diff --git a/kernel_addons/backport/2.6.9_U3/include/src/attribute_container.c b/kernel_addons/backport/2.6.9_U3/include/src/attribute_container.c
new file mode 100644
index 0000000..44948d1
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/src/attribute_container.c
@@ -0,0 +1,438 @@
+/*
+ * attribute_container.c - implementation of a simple container for classes
+ *
+ * Copyright (c) 2005 - James Bottomley <James.Bottomley at steeleye.com>
+ *
+ * This file is licensed under GPLv2
+ *
+ * The basic idea here is to enable a device to be attached to an
+ * aritrary numer of classes without having to allocate storage for them.
+ * Instead, the contained classes select the devices they need to attach
+ * to via a matching function.
+ */
+
+#include <linux/attribute_container.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+
+#include "base.h"
+
+/* This is a private structure used to tie the classdev and the
+ * container .. it should never be visible outside this file */
+struct internal_container {
+	struct klist_node node;
+	struct attribute_container *cont;
+	struct class_device classdev;
+};
+
+static void internal_container_klist_get(struct klist_node *n)
+{
+	struct internal_container *ic =
+		container_of(n, struct internal_container, node);
+	class_device_get(&ic->classdev);
+}
+
+static void internal_container_klist_put(struct klist_node *n)
+{
+	struct internal_container *ic =
+		container_of(n, struct internal_container, node);
+	class_device_put(&ic->classdev);
+}
+
+
+/**
+ * attribute_container_classdev_to_container - given a classdev, return the container
+ *
+ * @classdev: the class device created by attribute_container_add_device.
+ *
+ * Returns the container associated with this classdev.
+ */
+struct attribute_container *
+attribute_container_classdev_to_container(struct class_device *classdev)
+{
+	struct internal_container *ic =
+		container_of(classdev, struct internal_container, classdev);
+	return ic->cont;
+}
+EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container);
+
+static struct list_head attribute_container_list;
+
+static DECLARE_MUTEX(attribute_container_mutex);
+
+/**
+ * attribute_container_register - register an attribute container
+ *
+ * @cont: The container to register.  This must be allocated by the
+ *        callee and should also be zeroed by it.
+ */
+int
+attribute_container_register(struct attribute_container *cont)
+{
+	INIT_LIST_HEAD(&cont->node);
+	klist_init(&cont->containers,internal_container_klist_get,
+		   internal_container_klist_put);
+		
+	down(&attribute_container_mutex);
+	list_add_tail(&cont->node, &attribute_container_list);
+	up(&attribute_container_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(attribute_container_register);
+
+/**
+ * attribute_container_unregister - remove a container registration
+ *
+ * @cont: previously registered container to remove
+ */
+int
+attribute_container_unregister(struct attribute_container *cont)
+{
+	int retval = -EBUSY;
+	down(&attribute_container_mutex);
+	spin_lock(&cont->containers.k_lock);
+	if (!list_empty(&cont->containers.k_list))
+		goto out;
+	retval = 0;
+	list_del(&cont->node);
+ out:
+	spin_unlock(&cont->containers.k_lock);
+	up(&attribute_container_mutex);
+	return retval;
+		
+}
+EXPORT_SYMBOL_GPL(attribute_container_unregister);
+
+/* private function used as class release */
+static void attribute_container_release(struct class_device *classdev)
+{
+	struct internal_container *ic 
+		= container_of(classdev, struct internal_container, classdev);
+	struct device *dev = classdev->dev;
+
+	kfree(ic);
+	put_device(dev);
+}
+
+/**
+ * attribute_container_add_device - see if any container is interested in dev
+ *
+ * @dev: device to add attributes to
+ * @fn:	 function to trigger addition of class device.
+ *
+ * This function allocates storage for the class device(s) to be
+ * attached to dev (one for each matching attribute_container).  If no
+ * fn is provided, the code will simply register the class device via
+ * class_device_add.  If a function is provided, it is expected to add
+ * the class device at the appropriate time.  One of the things that
+ * might be necessary is to allocate and initialise the classdev and
+ * then add it a later time.  To do this, call this routine for
+ * allocation and initialisation and then use
+ * attribute_container_device_trigger() to call class_device_add() on
+ * it.  Note: after this, the class device contains a reference to dev
+ * which is not relinquished until the release of the classdev.
+ */
+void
+attribute_container_add_device(struct device *dev,
+			       int (*fn)(struct attribute_container *,
+					 struct device *,
+					 struct class_device *))
+{
+	struct attribute_container *cont;
+
+	down(&attribute_container_mutex);
+	list_for_each_entry(cont, &attribute_container_list, node) {
+		struct internal_container *ic;
+
+		if (attribute_container_no_classdevs(cont))
+			continue;
+
+		if (!cont->match(cont, dev))
+			continue;
+
+		ic = kzalloc(sizeof(*ic), GFP_KERNEL);
+		if (!ic) {
+			dev_printk(KERN_ERR, dev, "failed to allocate class container\n");
+			continue;
+		}
+
+		ic->cont = cont;
+		class_device_initialize(&ic->classdev);
+		ic->classdev.dev = get_device(dev);
+		ic->classdev.class = cont->class;
+		cont->class->release = attribute_container_release;
+		strcpy(ic->classdev.class_id, dev->bus_id);
+		if (fn)
+			fn(cont, dev, &ic->classdev);
+		else
+			attribute_container_add_class_device(&ic->classdev);
+		klist_add_tail(&ic->node, &cont->containers);
+	}
+	up(&attribute_container_mutex);
+}
+
+/* FIXME: can't break out of this unless klist_iter_exit is also
+ * called before doing the break
+ */
+#define klist_for_each_entry(pos, head, member, iter) \
+	for (klist_iter_init(head, iter); (pos = ({ \
+		struct klist_node *n = klist_next(iter); \
+		n ? container_of(n, typeof(*pos), member) : \
+			({ klist_iter_exit(iter) ; NULL; }); \
+	}) ) != NULL; )
+			
+
+/**
+ * attribute_container_remove_device - make device eligible for removal.
+ *
+ * @dev:  The generic device
+ * @fn:	  A function to call to remove the device
+ *
+ * This routine triggers device removal.  If fn is NULL, then it is
+ * simply done via class_device_unregister (note that if something
+ * still has a reference to the classdev, then the memory occupied
+ * will not be freed until the classdev is released).  If you want a
+ * two phase release: remove from visibility and then delete the
+ * device, then you should use this routine with a fn that calls
+ * class_device_del() and then use
+ * attribute_container_device_trigger() to do the final put on the
+ * classdev.
+ */
+void
+attribute_container_remove_device(struct device *dev,
+				  void (*fn)(struct attribute_container *,
+					     struct device *,
+					     struct class_device *))
+{
+	struct attribute_container *cont;
+
+	down(&attribute_container_mutex);
+	list_for_each_entry(cont, &attribute_container_list, node) {
+		struct internal_container *ic;
+		struct klist_iter iter;
+
+		if (attribute_container_no_classdevs(cont))
+			continue;
+
+		if (!cont->match(cont, dev))
+			continue;
+
+		klist_for_each_entry(ic, &cont->containers, node, &iter) {
+			if (dev != ic->classdev.dev)
+				continue;
+			klist_del(&ic->node);
+			if (fn)
+				fn(cont, dev, &ic->classdev);
+			else {
+				attribute_container_remove_attrs(&ic->classdev);
+				class_device_unregister(&ic->classdev);
+			}
+		}
+	}
+	up(&attribute_container_mutex);
+}
+
+/**
+ * attribute_container_device_trigger - execute a trigger for each matching classdev
+ *
+ * @dev:  The generic device to run the trigger for
+ * @fn	  the function to execute for each classdev.
+ *
+ * This funcion is for executing a trigger when you need to know both
+ * the container and the classdev.  If you only care about the
+ * container, then use attribute_container_trigger() instead.
+ */
+void
+attribute_container_device_trigger(struct device *dev, 
+				   int (*fn)(struct attribute_container *,
+					     struct device *,
+					     struct class_device *))
+{
+	struct attribute_container *cont;
+
+	down(&attribute_container_mutex);
+	list_for_each_entry(cont, &attribute_container_list, node) {
+		struct internal_container *ic;
+		struct klist_iter iter;
+
+		if (!cont->match(cont, dev))
+			continue;
+
+		if (attribute_container_no_classdevs(cont)) {
+			fn(cont, dev, NULL);
+			continue;
+		}
+
+		klist_for_each_entry(ic, &cont->containers, node, &iter) {
+			if (dev == ic->classdev.dev)
+				fn(cont, dev, &ic->classdev);
+		}
+	}
+	up(&attribute_container_mutex);
+}
+
+/**
+ * attribute_container_trigger - trigger a function for each matching container
+ *
+ * @dev:  The generic device to activate the trigger for
+ * @fn:	  the function to trigger
+ *
+ * This routine triggers a function that only needs to know the
+ * matching containers (not the classdev) associated with a device.
+ * It is more lightweight than attribute_container_device_trigger, so
+ * should be used in preference unless the triggering function
+ * actually needs to know the classdev.
+ */
+void
+attribute_container_trigger(struct device *dev,
+			    int (*fn)(struct attribute_container *,
+				      struct device *))
+{
+	struct attribute_container *cont;
+
+	down(&attribute_container_mutex);
+	list_for_each_entry(cont, &attribute_container_list, node) {
+		if (cont->match(cont, dev))
+			fn(cont, dev);
+	}
+	up(&attribute_container_mutex);
+}
+
+/**
+ * attribute_container_add_attrs - add attributes
+ *
+ * @classdev: The class device
+ *
+ * This simply creates all the class device sysfs files from the
+ * attributes listed in the container
+ */
+int
+attribute_container_add_attrs(struct class_device *classdev)
+{
+	struct attribute_container *cont =
+		attribute_container_classdev_to_container(classdev);
+	struct class_device_attribute **attrs =	cont->attrs;
+	int i, error;
+
+	if (!attrs)
+		return 0;
+
+	for (i = 0; attrs[i]; i++) {
+		error = class_device_create_file(classdev, attrs[i]);
+		if (error)
+			return error;
+	}
+
+	return 0;
+}
+
+/**
+ * attribute_container_add_class_device - same function as class_device_add
+ *
+ * @classdev:	the class device to add
+ *
+ * This performs essentially the same function as class_device_add except for
+ * attribute containers, namely add the classdev to the system and then
+ * create the attribute files
+ */
+int
+attribute_container_add_class_device(struct class_device *classdev)
+{
+	int error = class_device_add(classdev);
+	if (error)
+		return error;
+	return attribute_container_add_attrs(classdev);
+}
+
+/**
+ * attribute_container_add_class_device_adapter - simple adapter for triggers
+ *
+ * This function is identical to attribute_container_add_class_device except
+ * that it is designed to be called from the triggers
+ */
+int
+attribute_container_add_class_device_adapter(struct attribute_container *cont,
+					     struct device *dev,
+					     struct class_device *classdev)
+{
+	return attribute_container_add_class_device(classdev);
+}
+
+/**
+ * attribute_container_remove_attrs - remove any attribute files
+ *
+ * @classdev: The class device to remove the files from
+ *
+ */
+void
+attribute_container_remove_attrs(struct class_device *classdev)
+{
+	struct attribute_container *cont =
+		attribute_container_classdev_to_container(classdev);
+	struct class_device_attribute **attrs =	cont->attrs;
+	int i;
+
+	if (!attrs)
+		return;
+
+	for (i = 0; attrs[i]; i++)
+		class_device_remove_file(classdev, attrs[i]);
+}
+
+/**
+ * attribute_container_class_device_del - equivalent of class_device_del
+ *
+ * @classdev: the class device
+ *
+ * This function simply removes all the attribute files and then calls
+ * class_device_del.
+ */
+void
+attribute_container_class_device_del(struct class_device *classdev)
+{
+	attribute_container_remove_attrs(classdev);
+	class_device_del(classdev);
+}
+
+/**
+ * attribute_container_find_class_device - find the corresponding class_device
+ *
+ * @cont:	the container
+ * @dev:	the generic device
+ *
+ * Looks up the device in the container's list of class devices and returns
+ * the corresponding class_device.
+ */
+struct class_device *
+attribute_container_find_class_device(struct attribute_container *cont,
+				      struct device *dev)
+{
+	struct class_device *cdev = NULL;
+	struct internal_container *ic;
+	struct klist_iter iter;
+
+	klist_for_each_entry(ic, &cont->containers, node, &iter) {
+		if (ic->classdev.dev == dev) {
+			cdev = &ic->classdev;
+			/* FIXME: must exit iterator then break */
+			klist_iter_exit(&iter);
+			break;
+		}
+	}
+
+	return cdev;
+}
+EXPORT_SYMBOL_GPL(attribute_container_find_class_device);
+
+int
+attribute_container_init(void)
+{
+	INIT_LIST_HEAD(&attribute_container_list);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(attribute_container_init);
diff --git a/kernel_addons/backport/2.6.9_U3/include/src/base.h b/kernel_addons/backport/2.6.9_U3/include/src/base.h
new file mode 100644
index 0000000..a5f8936
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/src/base.h
@@ -0,0 +1 @@
+extern int attribute_container_init(void);
diff --git a/kernel_addons/backport/2.6.9_U3/include/src/init.c b/kernel_addons/backport/2.6.9_U3/include/src/init.c
new file mode 100644
index 0000000..15f0bc6
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/src/init.c
@@ -0,0 +1,26 @@
+/*
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/memory.h>
+
+#include "base.h"
+
+/**
+ *	driver_init - initialize driver model.
+ *
+ *	Call the driver model init functions to initialize their
+ *	subsystems. Called early from init/main.c.
+ */
+
+void __init driver_init(void)
+{
+	attribute_container_init();
+}
diff --git a/kernel_addons/backport/2.6.9_U3/include/src/klist.c b/kernel_addons/backport/2.6.9_U3/include/src/klist.c
new file mode 100644
index 0000000..3b29ebc
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/src/klist.c
@@ -0,0 +1,287 @@
+/*
+ *	klist.c - Routines for manipulating klists.
+ *
+ *
+ *	This klist interface provides a couple of structures that wrap around 
+ *	struct list_head to provide explicit list "head" (struct klist) and 
+ *	list "node" (struct klist_node) objects. For struct klist, a spinlock
+ *	is included that protects access to the actual list itself. struct 
+ *	klist_node provides a pointer to the klist that owns it and a kref
+ *	reference count that indicates the number of current users of that node
+ *	in the list.
+ *
+ *	The entire point is to provide an interface for iterating over a list
+ *	that is safe and allows for modification of the list during the
+ *	iteration (e.g. insertion and removal), including modification of the
+ *	current node on the list.
+ *
+ *	It works using a 3rd object type - struct klist_iter - that is declared
+ *	and initialized before an iteration. klist_next() is used to acquire the
+ *	next element in the list. It returns NULL if there are no more items.
+ *	Internally, that routine takes the klist's lock, decrements the reference
+ *	count of the previous klist_node and increments the count of the next
+ *	klist_node. It then drops the lock and returns.
+ *
+ *	There are primitives for adding and removing nodes to/from a klist. 
+ *	When deleting, klist_del() will simply decrement the reference count. 
+ *	Only when the count goes to 0 is the node removed from the list. 
+ *	klist_remove() will try to delete the node from the list and block
+ *	until it is actually removed. This is useful for objects (like devices)
+ *	that have been removed from the system and must be freed (but must wait
+ *	until all accessors have finished).
+ *
+ *	Copyright (C) 2005 Patrick Mochel
+ *
+ *	This file is released under the GPL v2.
+ */
+
+#include <linux/klist.h>
+#include <linux/module.h>
+
+
+/**
+ *	klist_init - Initialize a klist structure. 
+ *	@k:	The klist we're initializing.
+ *	@get:	The get function for the embedding object (NULL if none)
+ *	@put:	The put function for the embedding object (NULL if none)
+ *
+ * Initialises the klist structure.  If the klist_node structures are
+ * going to be embedded in refcounted objects (necessary for safe
+ * deletion) then the get/put arguments are used to initialise
+ * functions that take and release references on the embedding
+ * objects.
+ */
+
+void klist_init(struct klist * k, void (*get)(struct klist_node *),
+		void (*put)(struct klist_node *))
+{
+	INIT_LIST_HEAD(&k->k_list);
+	spin_lock_init(&k->k_lock);
+	k->get = get;
+	k->put = put;
+}
+
+EXPORT_SYMBOL_GPL(klist_init);
+
+
+static void add_head(struct klist * k, struct klist_node * n)
+{
+	spin_lock(&k->k_lock);
+	list_add(&n->n_node, &k->k_list);
+	spin_unlock(&k->k_lock);
+}
+
+static void add_tail(struct klist * k, struct klist_node * n)
+{
+	spin_lock(&k->k_lock);
+	list_add_tail(&n->n_node, &k->k_list);
+	spin_unlock(&k->k_lock);
+}
+
+
+static void klist_node_init(struct klist * k, struct klist_node * n)
+{
+	INIT_LIST_HEAD(&n->n_node);
+	init_completion(&n->n_removed);
+	kref_init(&n->n_ref);
+	n->n_klist = k;
+	if (k->get)
+		k->get(n);
+}
+
+
+/**
+ *	klist_add_head - Initialize a klist_node and add it to front.
+ *	@n:	node we're adding.
+ *	@k:	klist it's going on.
+ */
+
+void klist_add_head(struct klist_node * n, struct klist * k)
+{
+	klist_node_init(k, n);
+	add_head(k, n);
+}
+
+EXPORT_SYMBOL_GPL(klist_add_head);
+
+
+/**
+ *	klist_add_tail - Initialize a klist_node and add it to back.
+ *	@n:	node we're adding.
+ *	@k:	klist it's going on.
+ */
+
+void klist_add_tail(struct klist_node * n, struct klist * k)
+{
+	klist_node_init(k, n);
+	add_tail(k, n);
+}
+
+EXPORT_SYMBOL_GPL(klist_add_tail);
+
+
+static void klist_release(struct kref * kref)
+{
+	struct klist_node * n = container_of(kref, struct klist_node, n_ref);
+
+	list_del(&n->n_node);
+	complete(&n->n_removed);
+	n->n_klist = NULL;
+}
+
+static int klist_dec_and_del(struct klist_node * n)
+{
+	return kref_put_new(&n->n_ref, klist_release);
+}
+
+
+/**
+ *	klist_del - Decrement the reference count of node and try to remove.
+ *	@n:	node we're deleting.
+ */
+
+void klist_del(struct klist_node * n)
+{
+	struct klist * k = n->n_klist;
+	void (*put)(struct klist_node *) = k->put;
+
+	spin_lock(&k->k_lock);
+	if (!klist_dec_and_del(n))
+		put = NULL;
+	spin_unlock(&k->k_lock);
+	if (put)
+		put(n);
+}
+
+EXPORT_SYMBOL_GPL(klist_del);
+
+
+/**
+ *	klist_remove - Decrement the refcount of node and wait for it to go away.
+ *	@n:	node we're removing.
+ */
+
+void klist_remove(struct klist_node * n)
+{
+	klist_del(n);
+	wait_for_completion(&n->n_removed);
+}
+
+EXPORT_SYMBOL_GPL(klist_remove);
+
+
+/**
+ *	klist_node_attached - Say whether a node is bound to a list or not.
+ *	@n:	Node that we're testing.
+ */
+
+int klist_node_attached(struct klist_node * n)
+{
+	return (n->n_klist != NULL);
+}
+
+EXPORT_SYMBOL_GPL(klist_node_attached);
+
+
+/**
+ *	klist_iter_init_node - Initialize a klist_iter structure.
+ *	@k:	klist we're iterating.
+ *	@i:	klist_iter we're filling.
+ *	@n:	node to start with.
+ *
+ *	Similar to klist_iter_init(), but starts the action off with @n, 
+ *	instead of with the list head.
+ */
+
+void klist_iter_init_node(struct klist * k, struct klist_iter * i, struct klist_node * n)
+{
+	i->i_klist = k;
+	i->i_head = &k->k_list;
+	i->i_cur = n;
+	if (n)
+		kref_get(&n->n_ref);
+}
+
+EXPORT_SYMBOL_GPL(klist_iter_init_node);
+
+
+/**
+ *	klist_iter_init - Iniitalize a klist_iter structure.
+ *	@k:	klist we're iterating.
+ *	@i:	klist_iter structure we're filling.
+ *
+ *	Similar to klist_iter_init_node(), but start with the list head.
+ */
+
+void klist_iter_init(struct klist * k, struct klist_iter * i)
+{
+	klist_iter_init_node(k, i, NULL);
+}
+
+EXPORT_SYMBOL_GPL(klist_iter_init);
+
+
+/**
+ *	klist_iter_exit - Finish a list iteration.
+ *	@i:	Iterator structure.
+ *
+ *	Must be called when done iterating over list, as it decrements the 
+ *	refcount of the current node. Necessary in case iteration exited before
+ *	the end of the list was reached, and always good form.
+ */
+
+void klist_iter_exit(struct klist_iter * i)
+{
+	if (i->i_cur) {
+		klist_del(i->i_cur);
+		i->i_cur = NULL;
+	}
+}
+
+EXPORT_SYMBOL_GPL(klist_iter_exit);
+
+
+static struct klist_node * to_klist_node(struct list_head * n)
+{
+	return container_of(n, struct klist_node, n_node);
+}
+
+
+/**
+ *	klist_next - Ante up next node in list.
+ *	@i:	Iterator structure.
+ *
+ *	First grab list lock. Decrement the reference count of the previous
+ *	node, if there was one. Grab the next node, increment its reference 
+ *	count, drop the lock, and return that next node.
+ */
+
+struct klist_node * klist_next(struct klist_iter * i)
+{
+	struct list_head * next;
+	struct klist_node * lnode = i->i_cur;
+	struct klist_node * knode = NULL;
+	void (*put)(struct klist_node *) = i->i_klist->put;
+
+	spin_lock(&i->i_klist->k_lock);
+	if (lnode) {
+		next = lnode->n_node.next;
+		if (!klist_dec_and_del(lnode))
+			put = NULL;
+	} else
+		next = i->i_head->next;
+
+	if (next != i->i_head) {
+		knode = to_klist_node(next);
+		kref_get(&knode->n_ref);
+	}
+	i->i_cur = knode;
+	spin_unlock(&i->i_klist->k_lock);
+	if (put && lnode)
+		put(lnode);
+	return knode;
+}
+
+EXPORT_SYMBOL_GPL(klist_next);
+
+
diff --git a/kernel_addons/backport/2.6.9_U3/include/src/kref_new.c b/kernel_addons/backport/2.6.9_U3/include/src/kref_new.c
new file mode 100644
index 0000000..d45bb3f
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/src/kref_new.c
@@ -0,0 +1,29 @@
+#include <linux/kref.h>
+#include <linux/module.h>
+
+/**
+ * kref_put - decrement refcount for object.
+ * @kref: object.
+ * @release: pointer to the function that will clean up the object when the
+ *           last reference to the object is released.
+ *           This pointer is required, and it is not acceptable to pass kfree
+ *           in as this function.
+ *
+ * Decrement the refcount, and if 0, call release().
+ * Return 1 if the object was removed, otherwise return 0.  Beware, if this
+ * function returns 0, you still can not count on the kref from remaining in
+ * memory.  Only use the return value if you want to see if the kref is now
+ * gone, not present.
+ */
+int kref_put_new(struct kref *kref, void (*release)(struct kref *kref))
+{
+        WARN_ON(release == NULL);
+        WARN_ON(release == (void (*)(struct kref *))kfree);
+
+        if (atomic_dec_and_test(&kref->refcount)) {
+                release(kref);
+                return 1;
+        }
+        return 0;
+}
+EXPORT_SYMBOL(kref_put_new);
diff --git a/kernel_addons/backport/2.6.9_U3/include/src/scsi.c b/kernel_addons/backport/2.6.9_U3/include/src/scsi.c
new file mode 100644
index 0000000..8c833c0
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/src/scsi.c
@@ -0,0 +1,50 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/unistd.h>
+#include <linux/spinlock.h>
+#include <linux/kmod.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+
+/**
+ * starget_for_each_device  -  helper to walk all devices of a target
+ * @starget:	target whose devices we want to iterate over.
+ *
+ * This traverses over each devices of @shost.  The devices have
+ * a reference that must be released by scsi_host_put when breaking
+ * out of the loop.
+ */
+void starget_for_each_device(struct scsi_target *starget, void * data,
+		     void (*fn)(struct scsi_device *, void *))
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct scsi_device *sdev;
+
+	printk("%s: entry\n", __FUNCTION__);
+	shost_for_each_device(sdev, shost) {
+		if ((sdev->channel == starget->channel) &&
+		    (sdev->id == starget->id))
+			fn(sdev, data);
+	}
+	printk("%s: exit\n", __FUNCTION__);
+}
+EXPORT_SYMBOL(starget_for_each_device);
diff --git a/kernel_addons/backport/2.6.9_U3/include/src/scsi_lib.c b/kernel_addons/backport/2.6.9_U3/include/src/scsi_lib.c
new file mode 100644
index 0000000..327b53f
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/src/scsi_lib.c
@@ -0,0 +1,164 @@
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/kernel.h>
+#include <linux/mempool.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hardirq.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+
+int scsi_is_target_device(const struct device *dev)
+{
+        char *str = dev->bus_id;
+
+	if (strncmp(str, "target", 6) == 0) {
+		return 1;
+	}
+
+        return 0;
+}
+
+/**
+ * scsi_internal_device_block - internal function to put a device
+ *                              temporarily into the SDEV_BLOCK state
+ * @sdev:       device to block
+ *
+ * Block request made by scsi lld's to temporarily stop all
+ * scsi commands on the specified device.  Called from interrupt
+ * or normal process context.
+ *
+ * Returns zero if successful or error if not
+ *
+ * Notes:
+ *      This routine transitions the device to the SDEV_BLOCK state
+ *      (which must be a legal transition).  When the device is in this
+ *      state, all commands are deferred until the scsi lld reenables
+ *      the device with scsi_device_unblock or device_block_tmo fires.
+ *      This routine assumes the host_lock is held on entry.
+ **/
+int
+scsi_internal_device_block(struct scsi_device *sdev)
+{
+        request_queue_t *q = sdev->request_queue;
+        unsigned long flags;
+        int err = 0;
+
+        err = scsi_device_set_state(sdev, SDEV_BLOCK);
+        if (err)
+		return err;
+                
+        /*
+         * The device has transitioned to SDEV_BLOCK.  Stop the
+         * block layer from calling the midlayer with this device's
+         * request queue.
+         */
+        spin_lock_irqsave(q->queue_lock, flags);
+        blk_stop_queue(q);
+        spin_unlock_irqrestore(q->queue_lock, flags);
+
+        return 0;
+}
+EXPORT_SYMBOL_GPL(scsi_internal_device_block);
+
+/**
+ * scsi_internal_device_unblock - resume a device after a block request
+ * @sdev:       device to resume
+ *
+ * Called by scsi lld's or the midlayer to restart the device queue
+ * for the previously suspended scsi device.  Called from interrupt or
+ * normal process context.
+ *
+ * Returns zero if successful or error if not.
+ *
+ * Notes:
+ *      This routine transitions the device to the SDEV_RUNNING state
+ *      (which must be a legal transition) allowing the midlayer to
+ *      goose the queue for this device.  This routine assumes the
+ *      host_lock is held upon entry.
+ **/
+int
+scsi_internal_device_unblock(struct scsi_device *sdev)
+{
+        request_queue_t *q = sdev->request_queue;
+        int err;
+        unsigned long flags;
+
+
+        /*
+         * Try to transition the scsi device to SDEV_RUNNING
+         * and goose the device queue if successful.
+         */
+        err = scsi_device_set_state(sdev, SDEV_RUNNING);
+        if (err)
+		return err;
+                
+        spin_lock_irqsave(q->queue_lock, flags);
+        blk_start_queue(q);
+        spin_unlock_irqrestore(q->queue_lock, flags);
+
+        return 0;
+}
+EXPORT_SYMBOL_GPL(scsi_internal_device_unblock);
+
+static void
+device_block(struct scsi_device *sdev, void *data)
+{
+        scsi_internal_device_block(sdev);
+}
+
+static int
+target_block(struct device *dev, void *data)
+{
+        if (scsi_is_target_device(dev))
+                starget_for_each_device(to_scsi_target(dev), NULL,
+                                        device_block);
+
+        return 0;
+}
+
+void
+scsi_target_block(struct device *dev)
+{
+        if (scsi_is_target_device(dev))
+                starget_for_each_device(to_scsi_target(dev), NULL,
+                                        device_block);
+        else
+                device_for_each_child(dev, NULL, target_block);
+}
+EXPORT_SYMBOL_GPL(scsi_target_block);
+
+static void
+device_unblock(struct scsi_device *sdev, void *data)
+{
+        scsi_internal_device_unblock(sdev);
+}
+
+static int
+target_unblock(struct device *dev, void *data)
+{
+        if (scsi_is_target_device(dev))
+                starget_for_each_device(to_scsi_target(dev), NULL,
+                                        device_unblock);
+        return 0;
+}
+
+void
+scsi_target_unblock(struct device *dev)
+{
+        if (scsi_is_target_device(dev))
+                starget_for_each_device(to_scsi_target(dev), NULL,
+                                        device_unblock);
+        else
+                device_for_each_child(dev, NULL, target_unblock);
+}
+EXPORT_SYMBOL_GPL(scsi_target_unblock);
diff --git a/kernel_addons/backport/2.6.9_U3/include/src/scsi_scan.c b/kernel_addons/backport/2.6.9_U3/include/src/scsi_scan.c
new file mode 100644
index 0000000..b7b7674
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/src/scsi_scan.c
@@ -0,0 +1,48 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/spinlock.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_devinfo.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_eh.h>
+
+/**
+ * int_to_scsilun: reverts an int into a scsi_lun
+ * @int:        integer to be reverted
+ * @scsilun:    struct scsi_lun to be set.
+ *
+ * Description:
+ *     Reverts the functionality of the scsilun_to_int, which packed
+ *     an 8-byte lun value into an int. This routine unpacks the int
+ *     back into the lun value.
+ *     Note: the scsilun_to_int() routine does not truly handle all
+ *     8bytes of the lun value. This functions restores only as much
+ *     as was set by the routine.
+ *
+ * Notes:
+ *     Given an integer : 0x0b030a04,  this function returns a
+ *     scsi_lun of : struct scsi_lun of: 0a 04 0b 03 00 00 00 00
+ *
+ **/
+void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun)
+{
+        int i;
+
+        memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
+
+        for (i = 0; i < sizeof(lun); i += 2) {
+                scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
+                scsilun->scsi_lun[i+1] = lun & 0xFF;
+                lun = lun >> 16;
+        }
+}
+EXPORT_SYMBOL(int_to_scsilun);
diff --git a/kernel_addons/backport/2.6.9_U3/include/src/transport_class.c b/kernel_addons/backport/2.6.9_U3/include/src/transport_class.c
new file mode 100644
index 0000000..f25e7c6
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U3/include/src/transport_class.c
@@ -0,0 +1,280 @@
+/*
+ * transport_class.c - implementation of generic transport classes
+ *                     using attribute_containers
+ *
+ * Copyright (c) 2005 - James Bottomley <James.Bottomley at steeleye.com>
+ *
+ * This file is licensed under GPLv2
+ *
+ * The basic idea here is to allow any "device controller" (which
+ * would most often be a Host Bus Adapter to use the services of one
+ * or more tranport classes for performing transport specific
+ * services.  Transport specific services are things that the generic
+ * command layer doesn't want to know about (speed settings, line
+ * condidtioning, etc), but which the user might be interested in.
+ * Thus, the HBA's use the routines exported by the transport classes
+ * to perform these functions.  The transport classes export certain
+ * values to the user via sysfs using attribute containers.
+ *
+ * Note: because not every HBA will care about every transport
+ * attribute, there's a many to one relationship that goes like this:
+ *
+ * transport class<-----attribute container<----class device
+ *
+ * Usually the attribute container is per-HBA, but the design doesn't
+ * mandate that.  Although most of the services will be specific to
+ * the actual external storage connection used by the HBA, the generic
+ * transport class is framed entirely in terms of generic devices to
+ * allow it to be used by any physical HBA in the system.
+ */
+#include <linux/attribute_container.h>
+#include <linux/transport_class.h>
+
+/**
+ * transport_class_register - register an initial transport class
+ *
+ * @tclass:	a pointer to the transport class structure to be initialised
+ *
+ * The transport class contains an embedded class which is used to
+ * identify it.  The caller should initialise this structure with
+ * zeros and then generic class must have been initialised with the
+ * actual transport class unique name.  There's a macro
+ * DECLARE_TRANSPORT_CLASS() to do this (declared classes still must
+ * be registered).
+ *
+ * Returns 0 on success or error on failure.
+ */
+int transport_class_register(struct transport_class *tclass)
+{
+	return class_register(&tclass->class);
+}
+EXPORT_SYMBOL_GPL(transport_class_register);
+
+/**
+ * transport_class_unregister - unregister a previously registered class
+ *
+ * @tclass: The transport class to unregister
+ *
+ * Must be called prior to deallocating the memory for the transport
+ * class.
+ */
+void transport_class_unregister(struct transport_class *tclass)
+{
+	class_unregister(&tclass->class);
+}
+EXPORT_SYMBOL_GPL(transport_class_unregister);
+
+static int anon_transport_dummy_function(struct transport_container *tc,
+					 struct device *dev,
+					 struct class_device *cdev)
+{
+	/* do nothing */
+	return 0;
+}
+
+/**
+ * anon_transport_class_register - register an anonymous class
+ *
+ * @atc: The anon transport class to register
+ *
+ * The anonymous transport class contains both a transport class and a
+ * container.  The idea of an anonymous class is that it never
+ * actually has any device attributes associated with it (and thus
+ * saves on container storage).  So it can only be used for triggering
+ * events.  Use prezero and then use DECLARE_ANON_TRANSPORT_CLASS() to
+ * initialise the anon transport class storage.
+ */
+int anon_transport_class_register(struct anon_transport_class *atc)
+{
+	int error;
+	atc->container.class = &atc->tclass.class;
+	attribute_container_set_no_classdevs(&atc->container);
+	error = attribute_container_register(&atc->container);
+	if (error)
+		return error;
+	atc->tclass.setup = anon_transport_dummy_function;
+	atc->tclass.remove = anon_transport_dummy_function;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(anon_transport_class_register);
+
+/**
+ * anon_transport_class_unregister - unregister an anon class
+ *
+ * @atc: Pointer to the anon transport class to unregister
+ *
+ * Must be called prior to deallocating the memory for the anon
+ * transport class.
+ */
+void anon_transport_class_unregister(struct anon_transport_class *atc)
+{
+	attribute_container_unregister(&atc->container);
+}
+EXPORT_SYMBOL_GPL(anon_transport_class_unregister);
+
+static int transport_setup_classdev(struct attribute_container *cont,
+				    struct device *dev,
+				    struct class_device *classdev)
+{
+	struct transport_class *tclass = class_to_transport_class(cont->class);
+	struct transport_container *tcont = attribute_container_to_transport_container(cont);
+
+	if (tclass->setup)
+		tclass->setup(tcont, dev, classdev);
+
+	return 0;
+}
+
+/**
+ * transport_setup_device - declare a new dev for transport class association
+ *			    but don't make it visible yet.
+ *
+ * @dev: the generic device representing the entity being added
+ *
+ * Usually, dev represents some component in the HBA system (either
+ * the HBA itself or a device remote across the HBA bus).  This
+ * routine is simply a trigger point to see if any set of transport
+ * classes wishes to associate with the added device.  This allocates
+ * storage for the class device and initialises it, but does not yet
+ * add it to the system or add attributes to it (you do this with
+ * transport_add_device).  If you have no need for a separate setup
+ * and add operations, use transport_register_device (see
+ * transport_class.h).
+ */
+
+void transport_setup_device(struct device *dev)
+{
+	attribute_container_add_device(dev, transport_setup_classdev);
+}
+EXPORT_SYMBOL_GPL(transport_setup_device);
+
+static int transport_add_class_device(struct attribute_container *cont,
+				      struct device *dev,
+				      struct class_device *classdev)
+{
+	int error = attribute_container_add_class_device(classdev);
+	struct transport_container *tcont = 
+		attribute_container_to_transport_container(cont);
+
+	if (!error && tcont->statistics)
+		error = sysfs_create_group(&classdev->kobj, tcont->statistics);
+
+	return error;
+}
+
+
+/**
+ * transport_add_device - declare a new dev for transport class association
+ *
+ * @dev: the generic device representing the entity being added
+ *
+ * Usually, dev represents some component in the HBA system (either
+ * the HBA itself or a device remote across the HBA bus).  This
+ * routine is simply a trigger point used to add the device to the
+ * system and register attributes for it.
+ */
+
+void transport_add_device(struct device *dev)
+{
+	attribute_container_device_trigger(dev, transport_add_class_device);
+}
+EXPORT_SYMBOL_GPL(transport_add_device);
+
+static int transport_configure(struct attribute_container *cont,
+			       struct device *dev,
+			       struct class_device *cdev)
+{
+	struct transport_class *tclass = class_to_transport_class(cont->class);
+	struct transport_container *tcont = attribute_container_to_transport_container(cont);
+
+	if (tclass->configure)
+		tclass->configure(tcont, dev, cdev);
+
+	return 0;
+}
+
+/**
+ * transport_configure_device - configure an already set up device
+ *
+ * @dev: generic device representing device to be configured
+ *
+ * The idea of configure is simply to provide a point within the setup
+ * process to allow the transport class to extract information from a
+ * device after it has been setup.  This is used in SCSI because we
+ * have to have a setup device to begin using the HBA, but after we
+ * send the initial inquiry, we use configure to extract the device
+ * parameters.  The device need not have been added to be configured.
+ */
+void transport_configure_device(struct device *dev)
+{
+	attribute_container_device_trigger(dev, transport_configure);
+}
+EXPORT_SYMBOL_GPL(transport_configure_device);
+
+static int transport_remove_classdev(struct attribute_container *cont,
+				     struct device *dev,
+				     struct class_device *classdev)
+{
+	struct transport_container *tcont = 
+		attribute_container_to_transport_container(cont);
+	struct transport_class *tclass = class_to_transport_class(cont->class);
+
+	if (tclass->remove)
+		tclass->remove(tcont, dev, classdev);
+
+	if (tclass->remove != anon_transport_dummy_function) {
+		if (tcont->statistics)
+			sysfs_remove_group(&classdev->kobj, tcont->statistics);
+		attribute_container_class_device_del(classdev);
+	}
+
+	return 0;
+}
+
+
+/**
+ * transport_remove_device - remove the visibility of a device
+ *
+ * @dev: generic device to remove
+ *
+ * This call removes the visibility of the device (to the user from
+ * sysfs), but does not destroy it.  To eliminate a device entirely
+ * you must also call transport_destroy_device.  If you don't need to
+ * do remove and destroy as separate operations, use
+ * transport_unregister_device() (see transport_class.h) which will
+ * perform both calls for you.
+ */
+void transport_remove_device(struct device *dev)
+{
+	attribute_container_device_trigger(dev, transport_remove_classdev);
+}
+EXPORT_SYMBOL_GPL(transport_remove_device);
+
+static void transport_destroy_classdev(struct attribute_container *cont,
+				      struct device *dev,
+				      struct class_device *classdev)
+{
+	struct transport_class *tclass = class_to_transport_class(cont->class);
+
+	if (tclass->remove != anon_transport_dummy_function)
+		class_device_put(classdev);
+}
+
+
+/**
+ * transport_destroy_device - destroy a removed device
+ *
+ * @dev: device to eliminate from the transport class.
+ *
+ * This call triggers the elimination of storage associated with the
+ * transport classdev.  Note: all it really does is relinquish a
+ * reference to the classdev.  The memory will not be freed until the
+ * last reference goes to zero.  Note also that the classdev retains a
+ * reference count on dev, so dev too will remain for as long as the
+ * transport class device remains around.
+ */
+void transport_destroy_device(struct device *dev)
+{
+	attribute_container_remove_device(dev, transport_destroy_classdev);
+}
+EXPORT_SYMBOL_GPL(transport_destroy_device);
diff --git a/kernel_addons/backport/2.6.9_U4/include/linux/attribute_container.h b/kernel_addons/backport/2.6.9_U4/include/linux/attribute_container.h
new file mode 100644
index 0000000..93bfb0b
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/linux/attribute_container.h
@@ -0,0 +1,71 @@
+/*
+ * class_container.h - a generic container for all classes
+ *
+ * Copyright (c) 2005 - James Bottomley <James.Bottomley at steeleye.com>
+ *
+ * This file is licensed under GPLv2
+ */
+
+#ifndef _ATTRIBUTE_CONTAINER_H_
+#define _ATTRIBUTE_CONTAINER_H_
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/klist.h>
+#include <linux/spinlock.h>
+
+struct attribute_container {
+	struct list_head	node;
+	struct klist		containers;
+	struct class		*class;
+	struct class_device_attribute **attrs;
+	int (*match)(struct attribute_container *, struct device *);
+#define	ATTRIBUTE_CONTAINER_NO_CLASSDEVS	0x01
+	unsigned long		flags;
+};
+
+static inline int
+attribute_container_no_classdevs(struct attribute_container *atc)
+{
+	return atc->flags & ATTRIBUTE_CONTAINER_NO_CLASSDEVS;
+}
+
+static inline void
+attribute_container_set_no_classdevs(struct attribute_container *atc)
+{
+	atc->flags |= ATTRIBUTE_CONTAINER_NO_CLASSDEVS;
+}
+
+int attribute_container_register(struct attribute_container *cont);
+int attribute_container_unregister(struct attribute_container *cont);
+void attribute_container_create_device(struct device *dev,
+				       int (*fn)(struct attribute_container *,
+						 struct device *,
+						 struct class_device *));
+void attribute_container_add_device(struct device *dev,
+				    int (*fn)(struct attribute_container *,
+					      struct device *,
+					      struct class_device *));
+void attribute_container_remove_device(struct device *dev,
+				       void (*fn)(struct attribute_container *,
+						  struct device *,
+						  struct class_device *));
+void attribute_container_device_trigger(struct device *dev, 
+					int (*fn)(struct attribute_container *,
+						  struct device *,
+						  struct class_device *));
+void attribute_container_trigger(struct device *dev, 
+				 int (*fn)(struct attribute_container *,
+					   struct device *));
+int attribute_container_add_attrs(struct class_device *classdev);
+int attribute_container_add_class_device(struct class_device *classdev);
+int attribute_container_add_class_device_adapter(struct attribute_container *cont,
+						 struct device *dev,
+						 struct class_device *classdev);
+void attribute_container_remove_attrs(struct class_device *classdev);
+void attribute_container_class_device_del(struct class_device *classdev);
+struct attribute_container *attribute_container_classdev_to_container(struct class_device *);
+struct class_device *attribute_container_find_class_device(struct attribute_container *, struct device *);
+struct class_device_attribute **attribute_container_classdev_to_attrs(const struct class_device *classdev);
+
+#endif
diff --git a/kernel_addons/backport/2.6.9_U4/include/linux/klist.h b/kernel_addons/backport/2.6.9_U4/include/linux/klist.h
new file mode 100644
index 0000000..7407125
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/linux/klist.h
@@ -0,0 +1,61 @@
+/*
+ *	klist.h - Some generic list helpers, extending struct list_head a bit.
+ *
+ *	Implementations are found in lib/klist.c
+ *
+ *
+ *	Copyright (C) 2005 Patrick Mochel
+ *
+ *	This file is rleased under the GPL v2.
+ */
+
+#ifndef _LINUX_KLIST_H
+#define _LINUX_KLIST_H
+
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+
+struct klist_node;
+struct klist {
+	spinlock_t		k_lock;
+	struct list_head	k_list;
+	void			(*get)(struct klist_node *);
+	void			(*put)(struct klist_node *);
+};
+
+
+extern void klist_init(struct klist * k, void (*get)(struct klist_node *),
+		       void (*put)(struct klist_node *));
+
+struct klist_node {
+	struct klist		* n_klist;
+	struct list_head	n_node;
+	struct kref		n_ref;
+	struct completion	n_removed;
+};
+
+extern void klist_add_tail(struct klist_node * n, struct klist * k);
+extern void klist_add_head(struct klist_node * n, struct klist * k);
+
+extern void klist_del(struct klist_node * n);
+extern void klist_remove(struct klist_node * n);
+
+extern int klist_node_attached(struct klist_node * n);
+
+
+struct klist_iter {
+	struct klist		* i_klist;
+	struct list_head	* i_head;
+	struct klist_node	* i_cur;
+};
+
+
+extern void klist_iter_init(struct klist * k, struct klist_iter * i);
+extern void klist_iter_init_node(struct klist * k, struct klist_iter * i, 
+				 struct klist_node * n);
+extern void klist_iter_exit(struct klist_iter * i);
+extern struct klist_node * klist_next(struct klist_iter * i);
+
+#endif
diff --git a/kernel_addons/backport/2.6.9_U4/include/scsi/scsi_device.h b/kernel_addons/backport/2.6.9_U4/include/scsi/scsi_device.h
new file mode 100644
index 0000000..f353e0b
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/scsi/scsi_device.h
@@ -0,0 +1,19 @@
+#ifndef _SCSI_SCSI_DEVICE_H_BACKPORT
+#define _SCSI_SCSI_DEVICE_H_BACKPORT
+
+#include_next <scsi/scsi_device.h>
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <asm/atomic.h>
+
+struct scsi_lun;
+
+extern void int_to_scsilun(unsigned int, struct scsi_lun *);
+extern void scsi_target_block(struct device *);
+extern void scsi_target_unblock(struct device *);
+extern void starget_for_each_device(struct scsi_target *, void *,
+		     void (*fn)(struct scsi_device *, void *));
+#endif /* _SCSI_SCSI_DEVICE_H_BACKPORT */
diff --git a/kernel_addons/backport/2.6.9_U4/include/scsi/scsi_transport.h b/kernel_addons/backport/2.6.9_U4/include/scsi/scsi_transport.h
new file mode 100644
index 0000000..99c2b12
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/scsi/scsi_transport.h
@@ -0,0 +1,8 @@
+#ifndef _SCSI_SCSI_TRANSPORT_H_BACKPORT
+#define _SCSI_SCSI_TRANSPORT_H_BACKPORT
+
+#include_next <scsi/scsi_transport.h>
+
+#include <linux/transport_class.h>
+
+#endif /* _SCSI_SCSI_TRANSPORT_H_BACKPORT */
diff --git a/kernel_addons/backport/2.6.9_U4/include/src/attribute_container.c b/kernel_addons/backport/2.6.9_U4/include/src/attribute_container.c
new file mode 100644
index 0000000..44948d1
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/src/attribute_container.c
@@ -0,0 +1,438 @@
+/*
+ * attribute_container.c - implementation of a simple container for classes
+ *
+ * Copyright (c) 2005 - James Bottomley <James.Bottomley at steeleye.com>
+ *
+ * This file is licensed under GPLv2
+ *
+ * The basic idea here is to enable a device to be attached to an
+ * aritrary numer of classes without having to allocate storage for them.
+ * Instead, the contained classes select the devices they need to attach
+ * to via a matching function.
+ */
+
+#include <linux/attribute_container.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+
+#include "base.h"
+
+/* This is a private structure used to tie the classdev and the
+ * container .. it should never be visible outside this file */
+struct internal_container {
+	struct klist_node node;
+	struct attribute_container *cont;
+	struct class_device classdev;
+};
+
+static void internal_container_klist_get(struct klist_node *n)
+{
+	struct internal_container *ic =
+		container_of(n, struct internal_container, node);
+	class_device_get(&ic->classdev);
+}
+
+static void internal_container_klist_put(struct klist_node *n)
+{
+	struct internal_container *ic =
+		container_of(n, struct internal_container, node);
+	class_device_put(&ic->classdev);
+}
+
+
+/**
+ * attribute_container_classdev_to_container - given a classdev, return the container
+ *
+ * @classdev: the class device created by attribute_container_add_device.
+ *
+ * Returns the container associated with this classdev.
+ */
+struct attribute_container *
+attribute_container_classdev_to_container(struct class_device *classdev)
+{
+	struct internal_container *ic =
+		container_of(classdev, struct internal_container, classdev);
+	return ic->cont;
+}
+EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container);
+
+static struct list_head attribute_container_list;
+
+static DECLARE_MUTEX(attribute_container_mutex);
+
+/**
+ * attribute_container_register - register an attribute container
+ *
+ * @cont: The container to register.  This must be allocated by the
+ *        callee and should also be zeroed by it.
+ */
+int
+attribute_container_register(struct attribute_container *cont)
+{
+	INIT_LIST_HEAD(&cont->node);
+	klist_init(&cont->containers,internal_container_klist_get,
+		   internal_container_klist_put);
+		
+	down(&attribute_container_mutex);
+	list_add_tail(&cont->node, &attribute_container_list);
+	up(&attribute_container_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(attribute_container_register);
+
+/**
+ * attribute_container_unregister - remove a container registration
+ *
+ * @cont: previously registered container to remove
+ */
+int
+attribute_container_unregister(struct attribute_container *cont)
+{
+	int retval = -EBUSY;
+	down(&attribute_container_mutex);
+	spin_lock(&cont->containers.k_lock);
+	if (!list_empty(&cont->containers.k_list))
+		goto out;
+	retval = 0;
+	list_del(&cont->node);
+ out:
+	spin_unlock(&cont->containers.k_lock);
+	up(&attribute_container_mutex);
+	return retval;
+		
+}
+EXPORT_SYMBOL_GPL(attribute_container_unregister);
+
+/* private function used as class release */
+static void attribute_container_release(struct class_device *classdev)
+{
+	struct internal_container *ic 
+		= container_of(classdev, struct internal_container, classdev);
+	struct device *dev = classdev->dev;
+
+	kfree(ic);
+	put_device(dev);
+}
+
+/**
+ * attribute_container_add_device - see if any container is interested in dev
+ *
+ * @dev: device to add attributes to
+ * @fn:	 function to trigger addition of class device.
+ *
+ * This function allocates storage for the class device(s) to be
+ * attached to dev (one for each matching attribute_container).  If no
+ * fn is provided, the code will simply register the class device via
+ * class_device_add.  If a function is provided, it is expected to add
+ * the class device at the appropriate time.  One of the things that
+ * might be necessary is to allocate and initialise the classdev and
+ * then add it a later time.  To do this, call this routine for
+ * allocation and initialisation and then use
+ * attribute_container_device_trigger() to call class_device_add() on
+ * it.  Note: after this, the class device contains a reference to dev
+ * which is not relinquished until the release of the classdev.
+ */
+void
+attribute_container_add_device(struct device *dev,
+			       int (*fn)(struct attribute_container *,
+					 struct device *,
+					 struct class_device *))
+{
+	struct attribute_container *cont;
+
+	down(&attribute_container_mutex);
+	list_for_each_entry(cont, &attribute_container_list, node) {
+		struct internal_container *ic;
+
+		if (attribute_container_no_classdevs(cont))
+			continue;
+
+		if (!cont->match(cont, dev))
+			continue;
+
+		ic = kzalloc(sizeof(*ic), GFP_KERNEL);
+		if (!ic) {
+			dev_printk(KERN_ERR, dev, "failed to allocate class container\n");
+			continue;
+		}
+
+		ic->cont = cont;
+		class_device_initialize(&ic->classdev);
+		ic->classdev.dev = get_device(dev);
+		ic->classdev.class = cont->class;
+		cont->class->release = attribute_container_release;
+		strcpy(ic->classdev.class_id, dev->bus_id);
+		if (fn)
+			fn(cont, dev, &ic->classdev);
+		else
+			attribute_container_add_class_device(&ic->classdev);
+		klist_add_tail(&ic->node, &cont->containers);
+	}
+	up(&attribute_container_mutex);
+}
+
+/* FIXME: can't break out of this unless klist_iter_exit is also
+ * called before doing the break
+ */
+#define klist_for_each_entry(pos, head, member, iter) \
+	for (klist_iter_init(head, iter); (pos = ({ \
+		struct klist_node *n = klist_next(iter); \
+		n ? container_of(n, typeof(*pos), member) : \
+			({ klist_iter_exit(iter) ; NULL; }); \
+	}) ) != NULL; )
+			
+
+/**
+ * attribute_container_remove_device - make device eligible for removal.
+ *
+ * @dev:  The generic device
+ * @fn:	  A function to call to remove the device
+ *
+ * This routine triggers device removal.  If fn is NULL, then it is
+ * simply done via class_device_unregister (note that if something
+ * still has a reference to the classdev, then the memory occupied
+ * will not be freed until the classdev is released).  If you want a
+ * two phase release: remove from visibility and then delete the
+ * device, then you should use this routine with a fn that calls
+ * class_device_del() and then use
+ * attribute_container_device_trigger() to do the final put on the
+ * classdev.
+ */
+void
+attribute_container_remove_device(struct device *dev,
+				  void (*fn)(struct attribute_container *,
+					     struct device *,
+					     struct class_device *))
+{
+	struct attribute_container *cont;
+
+	down(&attribute_container_mutex);
+	list_for_each_entry(cont, &attribute_container_list, node) {
+		struct internal_container *ic;
+		struct klist_iter iter;
+
+		if (attribute_container_no_classdevs(cont))
+			continue;
+
+		if (!cont->match(cont, dev))
+			continue;
+
+		klist_for_each_entry(ic, &cont->containers, node, &iter) {
+			if (dev != ic->classdev.dev)
+				continue;
+			klist_del(&ic->node);
+			if (fn)
+				fn(cont, dev, &ic->classdev);
+			else {
+				attribute_container_remove_attrs(&ic->classdev);
+				class_device_unregister(&ic->classdev);
+			}
+		}
+	}
+	up(&attribute_container_mutex);
+}
+
+/**
+ * attribute_container_device_trigger - execute a trigger for each matching classdev
+ *
+ * @dev:  The generic device to run the trigger for
+ * @fn	  the function to execute for each classdev.
+ *
+ * This funcion is for executing a trigger when you need to know both
+ * the container and the classdev.  If you only care about the
+ * container, then use attribute_container_trigger() instead.
+ */
+void
+attribute_container_device_trigger(struct device *dev, 
+				   int (*fn)(struct attribute_container *,
+					     struct device *,
+					     struct class_device *))
+{
+	struct attribute_container *cont;
+
+	down(&attribute_container_mutex);
+	list_for_each_entry(cont, &attribute_container_list, node) {
+		struct internal_container *ic;
+		struct klist_iter iter;
+
+		if (!cont->match(cont, dev))
+			continue;
+
+		if (attribute_container_no_classdevs(cont)) {
+			fn(cont, dev, NULL);
+			continue;
+		}
+
+		klist_for_each_entry(ic, &cont->containers, node, &iter) {
+			if (dev == ic->classdev.dev)
+				fn(cont, dev, &ic->classdev);
+		}
+	}
+	up(&attribute_container_mutex);
+}
+
+/**
+ * attribute_container_trigger - trigger a function for each matching container
+ *
+ * @dev:  The generic device to activate the trigger for
+ * @fn:	  the function to trigger
+ *
+ * This routine triggers a function that only needs to know the
+ * matching containers (not the classdev) associated with a device.
+ * It is more lightweight than attribute_container_device_trigger, so
+ * should be used in preference unless the triggering function
+ * actually needs to know the classdev.
+ */
+void
+attribute_container_trigger(struct device *dev,
+			    int (*fn)(struct attribute_container *,
+				      struct device *))
+{
+	struct attribute_container *cont;
+
+	down(&attribute_container_mutex);
+	list_for_each_entry(cont, &attribute_container_list, node) {
+		if (cont->match(cont, dev))
+			fn(cont, dev);
+	}
+	up(&attribute_container_mutex);
+}
+
+/**
+ * attribute_container_add_attrs - add attributes
+ *
+ * @classdev: The class device
+ *
+ * This simply creates all the class device sysfs files from the
+ * attributes listed in the container
+ */
+int
+attribute_container_add_attrs(struct class_device *classdev)
+{
+	struct attribute_container *cont =
+		attribute_container_classdev_to_container(classdev);
+	struct class_device_attribute **attrs =	cont->attrs;
+	int i, error;
+
+	if (!attrs)
+		return 0;
+
+	for (i = 0; attrs[i]; i++) {
+		error = class_device_create_file(classdev, attrs[i]);
+		if (error)
+			return error;
+	}
+
+	return 0;
+}
+
+/**
+ * attribute_container_add_class_device - same function as class_device_add
+ *
+ * @classdev:	the class device to add
+ *
+ * This performs essentially the same function as class_device_add except for
+ * attribute containers, namely add the classdev to the system and then
+ * create the attribute files
+ */
+int
+attribute_container_add_class_device(struct class_device *classdev)
+{
+	int error = class_device_add(classdev);
+	if (error)
+		return error;
+	return attribute_container_add_attrs(classdev);
+}
+
+/**
+ * attribute_container_add_class_device_adapter - simple adapter for triggers
+ *
+ * This function is identical to attribute_container_add_class_device except
+ * that it is designed to be called from the triggers
+ */
+int
+attribute_container_add_class_device_adapter(struct attribute_container *cont,
+					     struct device *dev,
+					     struct class_device *classdev)
+{
+	return attribute_container_add_class_device(classdev);
+}
+
+/**
+ * attribute_container_remove_attrs - remove any attribute files
+ *
+ * @classdev: The class device to remove the files from
+ *
+ */
+void
+attribute_container_remove_attrs(struct class_device *classdev)
+{
+	struct attribute_container *cont =
+		attribute_container_classdev_to_container(classdev);
+	struct class_device_attribute **attrs =	cont->attrs;
+	int i;
+
+	if (!attrs)
+		return;
+
+	for (i = 0; attrs[i]; i++)
+		class_device_remove_file(classdev, attrs[i]);
+}
+
+/**
+ * attribute_container_class_device_del - equivalent of class_device_del
+ *
+ * @classdev: the class device
+ *
+ * This function simply removes all the attribute files and then calls
+ * class_device_del.
+ */
+void
+attribute_container_class_device_del(struct class_device *classdev)
+{
+	attribute_container_remove_attrs(classdev);
+	class_device_del(classdev);
+}
+
+/**
+ * attribute_container_find_class_device - find the corresponding class_device
+ *
+ * @cont:	the container
+ * @dev:	the generic device
+ *
+ * Looks up the device in the container's list of class devices and returns
+ * the corresponding class_device.
+ */
+struct class_device *
+attribute_container_find_class_device(struct attribute_container *cont,
+				      struct device *dev)
+{
+	struct class_device *cdev = NULL;
+	struct internal_container *ic;
+	struct klist_iter iter;
+
+	klist_for_each_entry(ic, &cont->containers, node, &iter) {
+		if (ic->classdev.dev == dev) {
+			cdev = &ic->classdev;
+			/* FIXME: must exit iterator then break */
+			klist_iter_exit(&iter);
+			break;
+		}
+	}
+
+	return cdev;
+}
+EXPORT_SYMBOL_GPL(attribute_container_find_class_device);
+
+int
+attribute_container_init(void)
+{
+	INIT_LIST_HEAD(&attribute_container_list);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(attribute_container_init);
diff --git a/kernel_addons/backport/2.6.9_U4/include/src/base.h b/kernel_addons/backport/2.6.9_U4/include/src/base.h
new file mode 100644
index 0000000..a5f8936
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/src/base.h
@@ -0,0 +1 @@
+extern int attribute_container_init(void);
diff --git a/kernel_addons/backport/2.6.9_U4/include/src/init.c b/kernel_addons/backport/2.6.9_U4/include/src/init.c
new file mode 100644
index 0000000..15f0bc6
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/src/init.c
@@ -0,0 +1,26 @@
+/*
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/memory.h>
+
+#include "base.h"
+
+/**
+ *	driver_init - initialize driver model.
+ *
+ *	Call the driver model init functions to initialize their
+ *	subsystems. Called early from init/main.c.
+ */
+
+void __init driver_init(void)
+{
+	attribute_container_init();
+}
diff --git a/kernel_addons/backport/2.6.9_U4/include/src/klist.c b/kernel_addons/backport/2.6.9_U4/include/src/klist.c
new file mode 100644
index 0000000..3b29ebc
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/src/klist.c
@@ -0,0 +1,287 @@
+/*
+ *	klist.c - Routines for manipulating klists.
+ *
+ *
+ *	This klist interface provides a couple of structures that wrap around 
+ *	struct list_head to provide explicit list "head" (struct klist) and 
+ *	list "node" (struct klist_node) objects. For struct klist, a spinlock
+ *	is included that protects access to the actual list itself. struct 
+ *	klist_node provides a pointer to the klist that owns it and a kref
+ *	reference count that indicates the number of current users of that node
+ *	in the list.
+ *
+ *	The entire point is to provide an interface for iterating over a list
+ *	that is safe and allows for modification of the list during the
+ *	iteration (e.g. insertion and removal), including modification of the
+ *	current node on the list.
+ *
+ *	It works using a 3rd object type - struct klist_iter - that is declared
+ *	and initialized before an iteration. klist_next() is used to acquire the
+ *	next element in the list. It returns NULL if there are no more items.
+ *	Internally, that routine takes the klist's lock, decrements the reference
+ *	count of the previous klist_node and increments the count of the next
+ *	klist_node. It then drops the lock and returns.
+ *
+ *	There are primitives for adding and removing nodes to/from a klist. 
+ *	When deleting, klist_del() will simply decrement the reference count. 
+ *	Only when the count goes to 0 is the node removed from the list. 
+ *	klist_remove() will try to delete the node from the list and block
+ *	until it is actually removed. This is useful for objects (like devices)
+ *	that have been removed from the system and must be freed (but must wait
+ *	until all accessors have finished).
+ *
+ *	Copyright (C) 2005 Patrick Mochel
+ *
+ *	This file is released under the GPL v2.
+ */
+
+#include <linux/klist.h>
+#include <linux/module.h>
+
+
+/**
+ *	klist_init - Initialize a klist structure. 
+ *	@k:	The klist we're initializing.
+ *	@get:	The get function for the embedding object (NULL if none)
+ *	@put:	The put function for the embedding object (NULL if none)
+ *
+ * Initialises the klist structure.  If the klist_node structures are
+ * going to be embedded in refcounted objects (necessary for safe
+ * deletion) then the get/put arguments are used to initialise
+ * functions that take and release references on the embedding
+ * objects.
+ */
+
+void klist_init(struct klist * k, void (*get)(struct klist_node *),
+		void (*put)(struct klist_node *))
+{
+	INIT_LIST_HEAD(&k->k_list);
+	spin_lock_init(&k->k_lock);
+	k->get = get;
+	k->put = put;
+}
+
+EXPORT_SYMBOL_GPL(klist_init);
+
+
+static void add_head(struct klist * k, struct klist_node * n)
+{
+	spin_lock(&k->k_lock);
+	list_add(&n->n_node, &k->k_list);
+	spin_unlock(&k->k_lock);
+}
+
+static void add_tail(struct klist * k, struct klist_node * n)
+{
+	spin_lock(&k->k_lock);
+	list_add_tail(&n->n_node, &k->k_list);
+	spin_unlock(&k->k_lock);
+}
+
+
+static void klist_node_init(struct klist * k, struct klist_node * n)
+{
+	INIT_LIST_HEAD(&n->n_node);
+	init_completion(&n->n_removed);
+	kref_init(&n->n_ref);
+	n->n_klist = k;
+	if (k->get)
+		k->get(n);
+}
+
+
+/**
+ *	klist_add_head - Initialize a klist_node and add it to front.
+ *	@n:	node we're adding.
+ *	@k:	klist it's going on.
+ */
+
+void klist_add_head(struct klist_node * n, struct klist * k)
+{
+	klist_node_init(k, n);
+	add_head(k, n);
+}
+
+EXPORT_SYMBOL_GPL(klist_add_head);
+
+
+/**
+ *	klist_add_tail - Initialize a klist_node and add it to back.
+ *	@n:	node we're adding.
+ *	@k:	klist it's going on.
+ */
+
+void klist_add_tail(struct klist_node * n, struct klist * k)
+{
+	klist_node_init(k, n);
+	add_tail(k, n);
+}
+
+EXPORT_SYMBOL_GPL(klist_add_tail);
+
+
+static void klist_release(struct kref * kref)
+{
+	struct klist_node * n = container_of(kref, struct klist_node, n_ref);
+
+	list_del(&n->n_node);
+	complete(&n->n_removed);
+	n->n_klist = NULL;
+}
+
+static int klist_dec_and_del(struct klist_node * n)
+{
+	return kref_put_new(&n->n_ref, klist_release);
+}
+
+
+/**
+ *	klist_del - Decrement the reference count of node and try to remove.
+ *	@n:	node we're deleting.
+ */
+
+void klist_del(struct klist_node * n)
+{
+	struct klist * k = n->n_klist;
+	void (*put)(struct klist_node *) = k->put;
+
+	spin_lock(&k->k_lock);
+	if (!klist_dec_and_del(n))
+		put = NULL;
+	spin_unlock(&k->k_lock);
+	if (put)
+		put(n);
+}
+
+EXPORT_SYMBOL_GPL(klist_del);
+
+
+/**
+ *	klist_remove - Decrement the refcount of node and wait for it to go away.
+ *	@n:	node we're removing.
+ */
+
+void klist_remove(struct klist_node * n)
+{
+	klist_del(n);
+	wait_for_completion(&n->n_removed);
+}
+
+EXPORT_SYMBOL_GPL(klist_remove);
+
+
+/**
+ *	klist_node_attached - Say whether a node is bound to a list or not.
+ *	@n:	Node that we're testing.
+ */
+
+int klist_node_attached(struct klist_node * n)
+{
+	return (n->n_klist != NULL);
+}
+
+EXPORT_SYMBOL_GPL(klist_node_attached);
+
+
+/**
+ *	klist_iter_init_node - Initialize a klist_iter structure.
+ *	@k:	klist we're iterating.
+ *	@i:	klist_iter we're filling.
+ *	@n:	node to start with.
+ *
+ *	Similar to klist_iter_init(), but starts the action off with @n, 
+ *	instead of with the list head.
+ */
+
+void klist_iter_init_node(struct klist * k, struct klist_iter * i, struct klist_node * n)
+{
+	i->i_klist = k;
+	i->i_head = &k->k_list;
+	i->i_cur = n;
+	if (n)
+		kref_get(&n->n_ref);
+}
+
+EXPORT_SYMBOL_GPL(klist_iter_init_node);
+
+
+/**
+ *	klist_iter_init - Iniitalize a klist_iter structure.
+ *	@k:	klist we're iterating.
+ *	@i:	klist_iter structure we're filling.
+ *
+ *	Similar to klist_iter_init_node(), but start with the list head.
+ */
+
+void klist_iter_init(struct klist * k, struct klist_iter * i)
+{
+	klist_iter_init_node(k, i, NULL);
+}
+
+EXPORT_SYMBOL_GPL(klist_iter_init);
+
+
+/**
+ *	klist_iter_exit - Finish a list iteration.
+ *	@i:	Iterator structure.
+ *
+ *	Must be called when done iterating over list, as it decrements the 
+ *	refcount of the current node. Necessary in case iteration exited before
+ *	the end of the list was reached, and always good form.
+ */
+
+void klist_iter_exit(struct klist_iter * i)
+{
+	if (i->i_cur) {
+		klist_del(i->i_cur);
+		i->i_cur = NULL;
+	}
+}
+
+EXPORT_SYMBOL_GPL(klist_iter_exit);
+
+
+static struct klist_node * to_klist_node(struct list_head * n)
+{
+	return container_of(n, struct klist_node, n_node);
+}
+
+
+/**
+ *	klist_next - Ante up next node in list.
+ *	@i:	Iterator structure.
+ *
+ *	First grab list lock. Decrement the reference count of the previous
+ *	node, if there was one. Grab the next node, increment its reference 
+ *	count, drop the lock, and return that next node.
+ */
+
+struct klist_node * klist_next(struct klist_iter * i)
+{
+	struct list_head * next;
+	struct klist_node * lnode = i->i_cur;
+	struct klist_node * knode = NULL;
+	void (*put)(struct klist_node *) = i->i_klist->put;
+
+	spin_lock(&i->i_klist->k_lock);
+	if (lnode) {
+		next = lnode->n_node.next;
+		if (!klist_dec_and_del(lnode))
+			put = NULL;
+	} else
+		next = i->i_head->next;
+
+	if (next != i->i_head) {
+		knode = to_klist_node(next);
+		kref_get(&knode->n_ref);
+	}
+	i->i_cur = knode;
+	spin_unlock(&i->i_klist->k_lock);
+	if (put && lnode)
+		put(lnode);
+	return knode;
+}
+
+EXPORT_SYMBOL_GPL(klist_next);
+
+
diff --git a/kernel_addons/backport/2.6.9_U4/include/src/kref_new.c b/kernel_addons/backport/2.6.9_U4/include/src/kref_new.c
new file mode 100644
index 0000000..d45bb3f
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/src/kref_new.c
@@ -0,0 +1,29 @@
+#include <linux/kref.h>
+#include <linux/module.h>
+
+/**
+ * kref_put - decrement refcount for object.
+ * @kref: object.
+ * @release: pointer to the function that will clean up the object when the
+ *           last reference to the object is released.
+ *           This pointer is required, and it is not acceptable to pass kfree
+ *           in as this function.
+ *
+ * Decrement the refcount, and if 0, call release().
+ * Return 1 if the object was removed, otherwise return 0.  Beware, if this
+ * function returns 0, you still can not count on the kref from remaining in
+ * memory.  Only use the return value if you want to see if the kref is now
+ * gone, not present.
+ */
+int kref_put_new(struct kref *kref, void (*release)(struct kref *kref))
+{
+        WARN_ON(release == NULL);
+        WARN_ON(release == (void (*)(struct kref *))kfree);
+
+        if (atomic_dec_and_test(&kref->refcount)) {
+                release(kref);
+                return 1;
+        }
+        return 0;
+}
+EXPORT_SYMBOL(kref_put_new);
diff --git a/kernel_addons/backport/2.6.9_U4/include/src/scsi.c b/kernel_addons/backport/2.6.9_U4/include/src/scsi.c
new file mode 100644
index 0000000..8c833c0
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/src/scsi.c
@@ -0,0 +1,50 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/unistd.h>
+#include <linux/spinlock.h>
+#include <linux/kmod.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+
+/**
+ * starget_for_each_device  -  helper to walk all devices of a target
+ * @starget:	target whose devices we want to iterate over.
+ *
+ * This traverses over each devices of @shost.  The devices have
+ * a reference that must be released by scsi_host_put when breaking
+ * out of the loop.
+ */
+void starget_for_each_device(struct scsi_target *starget, void * data,
+		     void (*fn)(struct scsi_device *, void *))
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct scsi_device *sdev;
+
+	printk("%s: entry\n", __FUNCTION__);
+	shost_for_each_device(sdev, shost) {
+		if ((sdev->channel == starget->channel) &&
+		    (sdev->id == starget->id))
+			fn(sdev, data);
+	}
+	printk("%s: exit\n", __FUNCTION__);
+}
+EXPORT_SYMBOL(starget_for_each_device);
diff --git a/kernel_addons/backport/2.6.9_U4/include/src/scsi_lib.c b/kernel_addons/backport/2.6.9_U4/include/src/scsi_lib.c
new file mode 100644
index 0000000..327b53f
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/src/scsi_lib.c
@@ -0,0 +1,164 @@
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/kernel.h>
+#include <linux/mempool.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hardirq.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+
+int scsi_is_target_device(const struct device *dev)
+{
+        char *str = dev->bus_id;
+
+	if (strncmp(str, "target", 6) == 0) {
+		return 1;
+	}
+
+        return 0;
+}
+
+/**
+ * scsi_internal_device_block - internal function to put a device
+ *                              temporarily into the SDEV_BLOCK state
+ * @sdev:       device to block
+ *
+ * Block request made by scsi lld's to temporarily stop all
+ * scsi commands on the specified device.  Called from interrupt
+ * or normal process context.
+ *
+ * Returns zero if successful or error if not
+ *
+ * Notes:
+ *      This routine transitions the device to the SDEV_BLOCK state
+ *      (which must be a legal transition).  When the device is in this
+ *      state, all commands are deferred until the scsi lld reenables
+ *      the device with scsi_device_unblock or device_block_tmo fires.
+ *      This routine assumes the host_lock is held on entry.
+ **/
+int
+scsi_internal_device_block(struct scsi_device *sdev)
+{
+        request_queue_t *q = sdev->request_queue;
+        unsigned long flags;
+        int err = 0;
+
+        err = scsi_device_set_state(sdev, SDEV_BLOCK);
+        if (err)
+		return err;
+                
+        /*
+         * The device has transitioned to SDEV_BLOCK.  Stop the
+         * block layer from calling the midlayer with this device's
+         * request queue.
+         */
+        spin_lock_irqsave(q->queue_lock, flags);
+        blk_stop_queue(q);
+        spin_unlock_irqrestore(q->queue_lock, flags);
+
+        return 0;
+}
+EXPORT_SYMBOL_GPL(scsi_internal_device_block);
+
+/**
+ * scsi_internal_device_unblock - resume a device after a block request
+ * @sdev:       device to resume
+ *
+ * Called by scsi lld's or the midlayer to restart the device queue
+ * for the previously suspended scsi device.  Called from interrupt or
+ * normal process context.
+ *
+ * Returns zero if successful or error if not.
+ *
+ * Notes:
+ *      This routine transitions the device to the SDEV_RUNNING state
+ *      (which must be a legal transition) allowing the midlayer to
+ *      goose the queue for this device.  This routine assumes the
+ *      host_lock is held upon entry.
+ **/
+int
+scsi_internal_device_unblock(struct scsi_device *sdev)
+{
+        request_queue_t *q = sdev->request_queue;
+        int err;
+        unsigned long flags;
+
+
+        /*
+         * Try to transition the scsi device to SDEV_RUNNING
+         * and goose the device queue if successful.
+         */
+        err = scsi_device_set_state(sdev, SDEV_RUNNING);
+        if (err)
+		return err;
+                
+        spin_lock_irqsave(q->queue_lock, flags);
+        blk_start_queue(q);
+        spin_unlock_irqrestore(q->queue_lock, flags);
+
+        return 0;
+}
+EXPORT_SYMBOL_GPL(scsi_internal_device_unblock);
+
+static void
+device_block(struct scsi_device *sdev, void *data)
+{
+        scsi_internal_device_block(sdev);
+}
+
+static int
+target_block(struct device *dev, void *data)
+{
+        if (scsi_is_target_device(dev))
+                starget_for_each_device(to_scsi_target(dev), NULL,
+                                        device_block);
+
+        return 0;
+}
+
+void
+scsi_target_block(struct device *dev)
+{
+        if (scsi_is_target_device(dev))
+                starget_for_each_device(to_scsi_target(dev), NULL,
+                                        device_block);
+        else
+                device_for_each_child(dev, NULL, target_block);
+}
+EXPORT_SYMBOL_GPL(scsi_target_block);
+
+static void
+device_unblock(struct scsi_device *sdev, void *data)
+{
+        scsi_internal_device_unblock(sdev);
+}
+
+static int
+target_unblock(struct device *dev, void *data)
+{
+        if (scsi_is_target_device(dev))
+                starget_for_each_device(to_scsi_target(dev), NULL,
+                                        device_unblock);
+        return 0;
+}
+
+void
+scsi_target_unblock(struct device *dev)
+{
+        if (scsi_is_target_device(dev))
+                starget_for_each_device(to_scsi_target(dev), NULL,
+                                        device_unblock);
+        else
+                device_for_each_child(dev, NULL, target_unblock);
+}
+EXPORT_SYMBOL_GPL(scsi_target_unblock);
diff --git a/kernel_addons/backport/2.6.9_U4/include/src/scsi_scan.c b/kernel_addons/backport/2.6.9_U4/include/src/scsi_scan.c
new file mode 100644
index 0000000..b7b7674
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/src/scsi_scan.c
@@ -0,0 +1,48 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/spinlock.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_devinfo.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_eh.h>
+
+/**
+ * int_to_scsilun: reverts an int into a scsi_lun
+ * @int:        integer to be reverted
+ * @scsilun:    struct scsi_lun to be set.
+ *
+ * Description:
+ *     Reverts the functionality of the scsilun_to_int, which packed
+ *     an 8-byte lun value into an int. This routine unpacks the int
+ *     back into the lun value.
+ *     Note: the scsilun_to_int() routine does not truly handle all
+ *     8bytes of the lun value. This functions restores only as much
+ *     as was set by the routine.
+ *
+ * Notes:
+ *     Given an integer : 0x0b030a04,  this function returns a
+ *     scsi_lun of : struct scsi_lun of: 0a 04 0b 03 00 00 00 00
+ *
+ **/
+void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun)
+{
+        int i;
+
+        memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
+
+        for (i = 0; i < sizeof(lun); i += 2) {
+                scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
+                scsilun->scsi_lun[i+1] = lun & 0xFF;
+                lun = lun >> 16;
+        }
+}
+EXPORT_SYMBOL(int_to_scsilun);
diff --git a/kernel_addons/backport/2.6.9_U4/include/src/transport_class.c b/kernel_addons/backport/2.6.9_U4/include/src/transport_class.c
new file mode 100644
index 0000000..f25e7c6
--- /dev/null
+++ b/kernel_addons/backport/2.6.9_U4/include/src/transport_class.c
@@ -0,0 +1,280 @@
+/*
+ * transport_class.c - implementation of generic transport classes
+ *                     using attribute_containers
+ *
+ * Copyright (c) 2005 - James Bottomley <James.Bottomley at steeleye.com>
+ *
+ * This file is licensed under GPLv2
+ *
+ * The basic idea here is to allow any "device controller" (which
+ * would most often be a Host Bus Adapter to use the services of one
+ * or more tranport classes for performing transport specific
+ * services.  Transport specific services are things that the generic
+ * command layer doesn't want to know about (speed settings, line
+ * condidtioning, etc), but which the user might be interested in.
+ * Thus, the HBA's use the routines exported by the transport classes
+ * to perform these functions.  The transport classes export certain
+ * values to the user via sysfs using attribute containers.
+ *
+ * Note: because not every HBA will care about every transport
+ * attribute, there's a many to one relationship that goes like this:
+ *
+ * transport class<-----attribute container<----class device
+ *
+ * Usually the attribute container is per-HBA, but the design doesn't
+ * mandate that.  Although most of the services will be specific to
+ * the actual external storage connection used by the HBA, the generic
+ * transport class is framed entirely in terms of generic devices to
+ * allow it to be used by any physical HBA in the system.
+ */
+#include <linux/attribute_container.h>
+#include <linux/transport_class.h>
+
+/**
+ * transport_class_register - register an initial transport class
+ *
+ * @tclass:	a pointer to the transport class structure to be initialised
+ *
+ * The transport class contains an embedded class which is used to
+ * identify it.  The caller should initialise this structure with
+ * zeros and then generic class must have been initialised with the
+ * actual transport class unique name.  There's a macro
+ * DECLARE_TRANSPORT_CLASS() to do this (declared classes still must
+ * be registered).
+ *
+ * Returns 0 on success or error on failure.
+ */
+int transport_class_register(struct transport_class *tclass)
+{
+	return class_register(&tclass->class);
+}
+EXPORT_SYMBOL_GPL(transport_class_register);
+
+/**
+ * transport_class_unregister - unregister a previously registered class
+ *
+ * @tclass: The transport class to unregister
+ *
+ * Must be called prior to deallocating the memory for the transport
+ * class.
+ */
+void transport_class_unregister(struct transport_class *tclass)
+{
+	class_unregister(&tclass->class);
+}
+EXPORT_SYMBOL_GPL(transport_class_unregister);
+
+static int anon_transport_dummy_function(struct transport_container *tc,
+					 struct device *dev,
+					 struct class_device *cdev)
+{
+	/* do nothing */
+	return 0;
+}
+
+/**
+ * anon_transport_class_register - register an anonymous class
+ *
+ * @atc: The anon transport class to register
+ *
+ * The anonymous transport class contains both a transport class and a
+ * container.  The idea of an anonymous class is that it never
+ * actually has any device attributes associated with it (and thus
+ * saves on container storage).  So it can only be used for triggering
+ * events.  Use prezero and then use DECLARE_ANON_TRANSPORT_CLASS() to
+ * initialise the anon transport class storage.
+ */
+int anon_transport_class_register(struct anon_transport_class *atc)
+{
+	int error;
+	atc->container.class = &atc->tclass.class;
+	attribute_container_set_no_classdevs(&atc->container);
+	error = attribute_container_register(&atc->container);
+	if (error)
+		return error;
+	atc->tclass.setup = anon_transport_dummy_function;
+	atc->tclass.remove = anon_transport_dummy_function;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(anon_transport_class_register);
+
+/**
+ * anon_transport_class_unregister - unregister an anon class
+ *
+ * @atc: Pointer to the anon transport class to unregister
+ *
+ * Must be called prior to deallocating the memory for the anon
+ * transport class.
+ */
+void anon_transport_class_unregister(struct anon_transport_class *atc)
+{
+	attribute_container_unregister(&atc->container);
+}
+EXPORT_SYMBOL_GPL(anon_transport_class_unregister);
+
+static int transport_setup_classdev(struct attribute_container *cont,
+				    struct device *dev,
+				    struct class_device *classdev)
+{
+	struct transport_class *tclass = class_to_transport_class(cont->class);
+	struct transport_container *tcont = attribute_container_to_transport_container(cont);
+
+	if (tclass->setup)
+		tclass->setup(tcont, dev, classdev);
+
+	return 0;
+}
+
+/**
+ * transport_setup_device - declare a new dev for transport class association
+ *			    but don't make it visible yet.
+ *
+ * @dev: the generic device representing the entity being added
+ *
+ * Usually, dev represents some component in the HBA system (either
+ * the HBA itself or a device remote across the HBA bus).  This
+ * routine is simply a trigger point to see if any set of transport
+ * classes wishes to associate with the added device.  This allocates
+ * storage for the class device and initialises it, but does not yet
+ * add it to the system or add attributes to it (you do this with
+ * transport_add_device).  If you have no need for a separate setup
+ * and add operations, use transport_register_device (see
+ * transport_class.h).
+ */
+
+void transport_setup_device(struct device *dev)
+{
+	attribute_container_add_device(dev, transport_setup_classdev);
+}
+EXPORT_SYMBOL_GPL(transport_setup_device);
+
+static int transport_add_class_device(struct attribute_container *cont,
+				      struct device *dev,
+				      struct class_device *classdev)
+{
+	int error = attribute_container_add_class_device(classdev);
+	struct transport_container *tcont = 
+		attribute_container_to_transport_container(cont);
+
+	if (!error && tcont->statistics)
+		error = sysfs_create_group(&classdev->kobj, tcont->statistics);
+
+	return error;
+}
+
+
+/**
+ * transport_add_device - declare a new dev for transport class association
+ *
+ * @dev: the generic device representing the entity being added
+ *
+ * Usually, dev represents some component in the HBA system (either
+ * the HBA itself or a device remote across the HBA bus).  This
+ * routine is simply a trigger point used to add the device to the
+ * system and register attributes for it.
+ */
+
+void transport_add_device(struct device *dev)
+{
+	attribute_container_device_trigger(dev, transport_add_class_device);
+}
+EXPORT_SYMBOL_GPL(transport_add_device);
+
+static int transport_configure(struct attribute_container *cont,
+			       struct device *dev,
+			       struct class_device *cdev)
+{
+	struct transport_class *tclass = class_to_transport_class(cont->class);
+	struct transport_container *tcont = attribute_container_to_transport_container(cont);
+
+	if (tclass->configure)
+		tclass->configure(tcont, dev, cdev);
+
+	return 0;
+}
+
+/**
+ * transport_configure_device - configure an already set up device
+ *
+ * @dev: generic device representing device to be configured
+ *
+ * The idea of configure is simply to provide a point within the setup
+ * process to allow the transport class to extract information from a
+ * device after it has been setup.  This is used in SCSI because we
+ * have to have a setup device to begin using the HBA, but after we
+ * send the initial inquiry, we use configure to extract the device
+ * parameters.  The device need not have been added to be configured.
+ */
+void transport_configure_device(struct device *dev)
+{
+	attribute_container_device_trigger(dev, transport_configure);
+}
+EXPORT_SYMBOL_GPL(transport_configure_device);
+
+static int transport_remove_classdev(struct attribute_container *cont,
+				     struct device *dev,
+				     struct class_device *classdev)
+{
+	struct transport_container *tcont = 
+		attribute_container_to_transport_container(cont);
+	struct transport_class *tclass = class_to_transport_class(cont->class);
+
+	if (tclass->remove)
+		tclass->remove(tcont, dev, classdev);
+
+	if (tclass->remove != anon_transport_dummy_function) {
+		if (tcont->statistics)
+			sysfs_remove_group(&classdev->kobj, tcont->statistics);
+		attribute_container_class_device_del(classdev);
+	}
+
+	return 0;
+}
+
+
+/**
+ * transport_remove_device - remove the visibility of a device
+ *
+ * @dev: generic device to remove
+ *
+ * This call removes the visibility of the device (to the user from
+ * sysfs), but does not destroy it.  To eliminate a device entirely
+ * you must also call transport_destroy_device.  If you don't need to
+ * do remove and destroy as separate operations, use
+ * transport_unregister_device() (see transport_class.h) which will
+ * perform both calls for you.
+ */
+void transport_remove_device(struct device *dev)
+{
+	attribute_container_device_trigger(dev, transport_remove_classdev);
+}
+EXPORT_SYMBOL_GPL(transport_remove_device);
+
+static void transport_destroy_classdev(struct attribute_container *cont,
+				      struct device *dev,
+				      struct class_device *classdev)
+{
+	struct transport_class *tclass = class_to_transport_class(cont->class);
+
+	if (tclass->remove != anon_transport_dummy_function)
+		class_device_put(classdev);
+}
+
+
+/**
+ * transport_destroy_device - destroy a removed device
+ *
+ * @dev: device to eliminate from the transport class.
+ *
+ * This call triggers the elimination of storage associated with the
+ * transport classdev.  Note: all it really does is relinquish a
+ * reference to the classdev.  The memory will not be freed until the
+ * last reference goes to zero.  Note also that the classdev retains a
+ * reference count on dev, so dev too will remain for as long as the
+ * transport class device remains around.
+ */
+void transport_destroy_device(struct device *dev)
+{
+	attribute_container_remove_device(dev, transport_destroy_classdev);
+}
+EXPORT_SYMBOL_GPL(transport_destroy_device);
diff --git a/kernel_patches/backport/2.6.9_U3/add_iscsi_proto_h.patch b/kernel_patches/backport/2.6.9_U3/add_iscsi_proto_h.patch
new file mode 100644
index 0000000..c4df6bb
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U3/add_iscsi_proto_h.patch
@@ -0,0 +1,591 @@
+diff -rupN linux-2.6.20-like-rh4/include/scsi/iscsi_proto.h linux-2.6.20/include/scsi/iscsi_proto.h
+--- linux-2.6.20-like-rh4/include/scsi/iscsi_proto.h	1970-01-01 02:00:00.000000000 +0200
++++ linux-2.6.20/include/scsi/iscsi_proto.h	2007-02-04 20:44:54.000000000 +0200
+@@ -0,0 +1,587 @@
++/*
++ * RFC 3720 (iSCSI) protocol data types
++ *
++ * Copyright (C) 2005 Dmitry Yusupov
++ * Copyright (C) 2005 Alex Aizman
++ * maintained by open-iscsi at googlegroups.com
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published
++ * by the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * See the file COPYING included with this distribution for more details.
++ */
++
++#ifndef ISCSI_PROTO_H
++#define ISCSI_PROTO_H
++
++#define ISCSI_DRAFT20_VERSION	0x00
++
++/* default iSCSI listen port for incoming connections */
++#define ISCSI_LISTEN_PORT	3260
++
++/* Padding word length */
++#define PAD_WORD_LEN		4
++
++/*
++ * useful common(control and data pathes) macro
++ */
++#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2]))
++#define hton24(p, v) { \
++        p[0] = (((v) >> 16) & 0xFF); \
++        p[1] = (((v) >> 8) & 0xFF); \
++        p[2] = ((v) & 0xFF); \
++}
++#define zero_data(p) {p[0]=0;p[1]=0;p[2]=0;}
++
++/*
++ * iSCSI Template Message Header
++ */
++struct iscsi_hdr {
++	uint8_t		opcode;
++	uint8_t		flags;		/* Final bit */
++	uint8_t		rsvd2[2];
++	uint8_t		hlength;	/* AHSs total length */
++	uint8_t		dlength[3];	/* Data length */
++	uint8_t		lun[8];
++	__be32		itt;		/* Initiator Task Tag */
++	__be32		ttt;		/* Target Task Tag */
++	__be32		statsn;
++	__be32		exp_statsn;
++	__be32		max_statsn;
++	uint8_t		other[12];
++};
++
++/************************* RFC 3720 Begin *****************************/
++
++#define ISCSI_RESERVED_TAG		0xffffffff
++
++/* Opcode encoding bits */
++#define ISCSI_OP_RETRY			0x80
++#define ISCSI_OP_IMMEDIATE		0x40
++#define ISCSI_OPCODE_MASK		0x3F
++
++/* Initiator Opcode values */
++#define ISCSI_OP_NOOP_OUT		0x00
++#define ISCSI_OP_SCSI_CMD		0x01
++#define ISCSI_OP_SCSI_TMFUNC		0x02
++#define ISCSI_OP_LOGIN			0x03
++#define ISCSI_OP_TEXT			0x04
++#define ISCSI_OP_SCSI_DATA_OUT		0x05
++#define ISCSI_OP_LOGOUT			0x06
++#define ISCSI_OP_SNACK			0x10
++
++#define ISCSI_OP_VENDOR1_CMD		0x1c
++#define ISCSI_OP_VENDOR2_CMD		0x1d
++#define ISCSI_OP_VENDOR3_CMD		0x1e
++#define ISCSI_OP_VENDOR4_CMD		0x1f
++
++/* Target Opcode values */
++#define ISCSI_OP_NOOP_IN		0x20
++#define ISCSI_OP_SCSI_CMD_RSP		0x21
++#define ISCSI_OP_SCSI_TMFUNC_RSP	0x22
++#define ISCSI_OP_LOGIN_RSP		0x23
++#define ISCSI_OP_TEXT_RSP		0x24
++#define ISCSI_OP_SCSI_DATA_IN		0x25
++#define ISCSI_OP_LOGOUT_RSP		0x26
++#define ISCSI_OP_R2T			0x31
++#define ISCSI_OP_ASYNC_EVENT		0x32
++#define ISCSI_OP_REJECT			0x3f
++
++struct iscsi_ahs_hdr {
++	__be16 ahslength;
++	uint8_t ahstype;
++	uint8_t ahspec[5];
++};
++
++#define ISCSI_AHSTYPE_CDB		1
++#define ISCSI_AHSTYPE_RLENGTH		2
++
++/* iSCSI PDU Header */
++struct iscsi_cmd {
++	uint8_t opcode;
++	uint8_t flags;
++	__be16 rsvd2;
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	__be32 itt;	/* Initiator Task Tag */
++	__be32 data_length;
++	__be32 cmdsn;
++	__be32 exp_statsn;
++	uint8_t cdb[16];	/* SCSI Command Block */
++	/* Additional Data (Command Dependent) */
++};
++
++/* Command PDU flags */
++#define ISCSI_FLAG_CMD_FINAL		0x80
++#define ISCSI_FLAG_CMD_READ		0x40
++#define ISCSI_FLAG_CMD_WRITE		0x20
++#define ISCSI_FLAG_CMD_ATTR_MASK	0x07	/* 3 bits */
++
++/* SCSI Command Attribute values */
++#define ISCSI_ATTR_UNTAGGED		0
++#define ISCSI_ATTR_SIMPLE		1
++#define ISCSI_ATTR_ORDERED		2
++#define ISCSI_ATTR_HEAD_OF_QUEUE	3
++#define ISCSI_ATTR_ACA			4
++
++struct iscsi_rlength_ahdr {
++	__be16 ahslength;
++	uint8_t ahstype;
++	uint8_t reserved;
++	__be32 read_length;
++};
++
++/* SCSI Response Header */
++struct iscsi_cmd_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t response;
++	uint8_t cmd_status;
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	rsvd1;
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	__be32	exp_datasn;
++	__be32	bi_residual_count;
++	__be32	residual_count;
++	/* Response or Sense Data (optional) */
++};
++
++/* Command Response PDU flags */
++#define ISCSI_FLAG_CMD_BIDI_OVERFLOW	0x10
++#define ISCSI_FLAG_CMD_BIDI_UNDERFLOW	0x08
++#define ISCSI_FLAG_CMD_OVERFLOW		0x04
++#define ISCSI_FLAG_CMD_UNDERFLOW	0x02
++
++/* iSCSI Status values. Valid if Rsp Selector bit is not set */
++#define ISCSI_STATUS_CMD_COMPLETED	0
++#define ISCSI_STATUS_TARGET_FAILURE	1
++#define ISCSI_STATUS_SUBSYS_FAILURE	2
++
++/* Asynchronous Event Header */
++struct iscsi_async {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2[2];
++	uint8_t rsvd3;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	uint8_t rsvd4[8];
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	uint8_t async_event;
++	uint8_t async_vcode;
++	__be16	param1;
++	__be16	param2;
++	__be16	param3;
++	uint8_t rsvd5[4];
++};
++
++/* iSCSI Event Codes */
++#define ISCSI_ASYNC_MSG_SCSI_EVENT			0
++#define ISCSI_ASYNC_MSG_REQUEST_LOGOUT			1
++#define ISCSI_ASYNC_MSG_DROPPING_CONNECTION		2
++#define ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS	3
++#define ISCSI_ASYNC_MSG_PARAM_NEGOTIATION		4
++#define ISCSI_ASYNC_MSG_VENDOR_SPECIFIC			255
++
++/* NOP-Out Message */
++struct iscsi_nopout {
++	uint8_t opcode;
++	uint8_t flags;
++	__be16	rsvd2;
++	uint8_t rsvd3;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	ttt;	/* Target Transfer Tag */
++	__be32	cmdsn;
++	__be32	exp_statsn;
++	uint8_t rsvd4[16];
++};
++
++/* NOP-In Message */
++struct iscsi_nopin {
++	uint8_t opcode;
++	uint8_t flags;
++	__be16	rsvd2;
++	uint8_t rsvd3;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	ttt;	/* Target Transfer Tag */
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	uint8_t rsvd4[12];
++};
++
++/* SCSI Task Management Message Header */
++struct iscsi_tm {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd1[2];
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	rtt;	/* Reference Task Tag */
++	__be32	cmdsn;
++	__be32	exp_statsn;
++	__be32	refcmdsn;
++	__be32	exp_datasn;
++	uint8_t rsvd2[8];
++};
++
++#define ISCSI_FLAG_TM_FUNC_MASK			0x7F
++
++/* Function values */
++#define ISCSI_TM_FUNC_ABORT_TASK		1
++#define ISCSI_TM_FUNC_ABORT_TASK_SET		2
++#define ISCSI_TM_FUNC_CLEAR_ACA			3
++#define ISCSI_TM_FUNC_CLEAR_TASK_SET		4
++#define ISCSI_TM_FUNC_LOGICAL_UNIT_RESET	5
++#define ISCSI_TM_FUNC_TARGET_WARM_RESET		6
++#define ISCSI_TM_FUNC_TARGET_COLD_RESET		7
++#define ISCSI_TM_FUNC_TASK_REASSIGN		8
++
++/* SCSI Task Management Response Header */
++struct iscsi_tm_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t response;	/* see Response values below */
++	uint8_t qualifier;
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd2[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	rtt;	/* Reference Task Tag */
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	uint8_t rsvd3[12];
++};
++
++/* Response values */
++#define ISCSI_TMF_RSP_COMPLETE		0x00
++#define ISCSI_TMF_RSP_NO_TASK		0x01
++#define ISCSI_TMF_RSP_NO_LUN		0x02
++#define ISCSI_TMF_RSP_TASK_ALLEGIANT	0x03
++#define ISCSI_TMF_RSP_NO_FAILOVER	0x04
++#define ISCSI_TMF_RSP_NOT_SUPPORTED	0x05
++#define ISCSI_TMF_RSP_AUTH_FAILED	0x06
++#define ISCSI_TMF_RSP_REJECTED		0xff
++
++/* Ready To Transfer Header */
++struct iscsi_r2t_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2[2];
++	uint8_t	hlength;
++	uint8_t	dlength[3];
++	uint8_t lun[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	ttt;	/* Target Transfer Tag */
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	__be32	r2tsn;
++	__be32	data_offset;
++	__be32	data_length;
++};
++
++/* SCSI Data Hdr */
++struct iscsi_data {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2[2];
++	uint8_t rsvd3;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	__be32	itt;
++	__be32	ttt;
++	__be32	rsvd4;
++	__be32	exp_statsn;
++	__be32	rsvd5;
++	__be32	datasn;
++	__be32	offset;
++	__be32	rsvd6;
++	/* Payload */
++};
++
++/* SCSI Data Response Hdr */
++struct iscsi_data_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2;
++	uint8_t cmd_status;
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	__be32	itt;
++	__be32	ttt;
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	__be32	datasn;
++	__be32	offset;
++	__be32	residual_count;
++};
++
++/* Data Response PDU flags */
++#define ISCSI_FLAG_DATA_ACK		0x40
++#define ISCSI_FLAG_DATA_OVERFLOW	0x04
++#define ISCSI_FLAG_DATA_UNDERFLOW	0x02
++#define ISCSI_FLAG_DATA_STATUS		0x01
++
++/* Text Header */
++struct iscsi_text {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2[2];
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd4[8];
++	__be32	itt;
++	__be32	ttt;
++	__be32	cmdsn;
++	__be32	exp_statsn;
++	uint8_t rsvd5[16];
++	/* Text - key=value pairs */
++};
++
++#define ISCSI_FLAG_TEXT_CONTINUE	0x40
++
++/* Text Response Header */
++struct iscsi_text_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2[2];
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd4[8];
++	__be32	itt;
++	__be32	ttt;
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	uint8_t rsvd5[12];
++	/* Text Response - key:value pairs */
++};
++
++/* Login Header */
++struct iscsi_login {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t max_version;	/* Max. version supported */
++	uint8_t min_version;	/* Min. version supported */
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t isid[6];	/* Initiator Session ID */
++	__be16	tsih;	/* Target Session Handle */
++	__be32	itt;	/* Initiator Task Tag */
++	__be16	cid;
++	__be16	rsvd3;
++	__be32	cmdsn;
++	__be32	exp_statsn;
++	uint8_t rsvd5[16];
++};
++
++/* Login PDU flags */
++#define ISCSI_FLAG_LOGIN_TRANSIT		0x80
++#define ISCSI_FLAG_LOGIN_CONTINUE		0x40
++#define ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK	0x0C	/* 2 bits */
++#define ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK	0x03	/* 2 bits */
++
++#define ISCSI_LOGIN_CURRENT_STAGE(flags) \
++	((flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2)
++#define ISCSI_LOGIN_NEXT_STAGE(flags) \
++	(flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK)
++
++/* Login Response Header */
++struct iscsi_login_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t max_version;	/* Max. version supported */
++	uint8_t active_version;	/* Active version */
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t isid[6];	/* Initiator Session ID */
++	__be16	tsih;	/* Target Session Handle */
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	rsvd3;
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	uint8_t status_class;	/* see Login RSP ststus classes below */
++	uint8_t status_detail;	/* see Login RSP Status details below */
++	uint8_t rsvd4[10];
++};
++
++/* Login stage (phase) codes for CSG, NSG */
++#define ISCSI_INITIAL_LOGIN_STAGE		-1
++#define ISCSI_SECURITY_NEGOTIATION_STAGE	0
++#define ISCSI_OP_PARMS_NEGOTIATION_STAGE	1
++#define ISCSI_FULL_FEATURE_PHASE		3
++
++/* Login Status response classes */
++#define ISCSI_STATUS_CLS_SUCCESS		0x00
++#define ISCSI_STATUS_CLS_REDIRECT		0x01
++#define ISCSI_STATUS_CLS_INITIATOR_ERR		0x02
++#define ISCSI_STATUS_CLS_TARGET_ERR		0x03
++
++/* Login Status response detail codes */
++/* Class-0 (Success) */
++#define ISCSI_LOGIN_STATUS_ACCEPT		0x00
++
++/* Class-1 (Redirection) */
++#define ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP	0x01
++#define ISCSI_LOGIN_STATUS_TGT_MOVED_PERM	0x02
++
++/* Class-2 (Initiator Error) */
++#define ISCSI_LOGIN_STATUS_INIT_ERR		0x00
++#define ISCSI_LOGIN_STATUS_AUTH_FAILED		0x01
++#define ISCSI_LOGIN_STATUS_TGT_FORBIDDEN	0x02
++#define ISCSI_LOGIN_STATUS_TGT_NOT_FOUND	0x03
++#define ISCSI_LOGIN_STATUS_TGT_REMOVED		0x04
++#define ISCSI_LOGIN_STATUS_NO_VERSION		0x05
++#define ISCSI_LOGIN_STATUS_ISID_ERROR		0x06
++#define ISCSI_LOGIN_STATUS_MISSING_FIELDS	0x07
++#define ISCSI_LOGIN_STATUS_CONN_ADD_FAILED	0x08
++#define ISCSI_LOGIN_STATUS_NO_SESSION_TYPE	0x09
++#define ISCSI_LOGIN_STATUS_NO_SESSION		0x0a
++#define ISCSI_LOGIN_STATUS_INVALID_REQUEST	0x0b
++
++/* Class-3 (Target Error) */
++#define ISCSI_LOGIN_STATUS_TARGET_ERROR		0x00
++#define ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE	0x01
++#define ISCSI_LOGIN_STATUS_NO_RESOURCES		0x02
++
++/* Logout Header */
++struct iscsi_logout {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd1[2];
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd2[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be16	cid;
++	uint8_t rsvd3[2];
++	__be32	cmdsn;
++	__be32	exp_statsn;
++	uint8_t rsvd4[16];
++};
++
++/* Logout PDU flags */
++#define ISCSI_FLAG_LOGOUT_REASON_MASK	0x7F
++
++/* logout reason_code values */
++
++#define ISCSI_LOGOUT_REASON_CLOSE_SESSION	0
++#define ISCSI_LOGOUT_REASON_CLOSE_CONNECTION	1
++#define ISCSI_LOGOUT_REASON_RECOVERY		2
++#define ISCSI_LOGOUT_REASON_AEN_REQUEST		3
++
++/* Logout Response Header */
++struct iscsi_logout_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t response;	/* see Logout response values below */
++	uint8_t rsvd2;
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd3[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	rsvd4;
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	__be32	rsvd5;
++	__be16	t2wait;
++	__be16	t2retain;
++	__be32	rsvd6;
++};
++
++/* logout response status values */
++
++#define ISCSI_LOGOUT_SUCCESS			0
++#define ISCSI_LOGOUT_CID_NOT_FOUND		1
++#define ISCSI_LOGOUT_RECOVERY_UNSUPPORTED	2
++#define ISCSI_LOGOUT_CLEANUP_FAILED		3
++
++/* SNACK Header */
++struct iscsi_snack {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2[14];
++	__be32	itt;
++	__be32	begrun;
++	__be32	runlength;
++	__be32	exp_statsn;
++	__be32	rsvd3;
++	__be32	exp_datasn;
++	uint8_t rsvd6[8];
++};
++
++/* SNACK PDU flags */
++#define ISCSI_FLAG_SNACK_TYPE_MASK	0x0F	/* 4 bits */
++
++/* Reject Message Header */
++struct iscsi_reject {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t reason;
++	uint8_t rsvd2;
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd3[8];
++	__be32  ffffffff;
++	uint8_t rsvd4[4];
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	__be32	datasn;
++	uint8_t rsvd5[8];
++	/* Text - Rejected hdr */
++};
++
++/* Reason for Reject */
++#define ISCSI_REASON_CMD_BEFORE_LOGIN	1
++#define ISCSI_REASON_DATA_DIGEST_ERROR	2
++#define ISCSI_REASON_DATA_SNACK_REJECT	3
++#define ISCSI_REASON_PROTOCOL_ERROR	4
++#define ISCSI_REASON_CMD_NOT_SUPPORTED	5
++#define ISCSI_REASON_IMM_CMD_REJECT		6
++#define ISCSI_REASON_TASK_IN_PROGRESS	7
++#define ISCSI_REASON_INVALID_SNACK		8
++#define ISCSI_REASON_BOOKMARK_INVALID	9
++#define ISCSI_REASON_BOOKMARK_NO_RESOURCES	10
++#define ISCSI_REASON_NEGOTIATION_RESET	11
++
++/* Max. number of Key=Value pairs in a text message */
++#define MAX_KEY_VALUE_PAIRS	8192
++
++/* maximum length for text keys/values */
++#define KEY_MAXLEN		64
++#define VALUE_MAXLEN		255
++#define TARGET_NAME_MAXLEN	VALUE_MAXLEN
++
++#define DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH	8192
++
++/************************* RFC 3720 End *****************************/
++
++#endif /* ISCSI_PROTO_H */
diff --git a/kernel_patches/backport/2.6.9_U3/add_iser.patch b/kernel_patches/backport/2.6.9_U3/add_iser.patch
new file mode 100644
index 0000000..0da53d2
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U3/add_iser.patch
@@ -0,0 +1,13 @@
+diff -rup linux-2.6.20/drivers/infiniband/ulp/iser/iser_initiator.c linux-2.6.20-backport-rh4-u3/drivers/infiniband/ulp/iser/iser_initiator.c
+--- linux-2.6.20/drivers/infiniband/ulp/iser/iser_initiator.c	2007-02-04 20:44:54.000000000 +0200
++++ linux-2.6.20-backport-rh4-u3/drivers/infiniband/ulp/iser/iser_initiator.c	2007-03-26 11:27:11.000000000 +0200
+@@ -618,7 +618,8 @@ void iser_snd_completion(struct iser_des
+ 
+ 	if (resume_tx) {
+ 		iser_dbg("%ld resuming tx\n",jiffies);
+-		scsi_queue_work(conn->session->host, &conn->xmitwork);
++		//scsi_queue_work(conn->session->host, &conn->xmitwork);
++		schedule_work(&conn->xmitwork);
+ 	}
+ 
+ 	if (tx_desc->type == ISCSI_TX_CONTROL) { 
diff --git a/kernel_patches/backport/2.6.9_U3/add_memory_h.patch b/kernel_patches/backport/2.6.9_U3/add_memory_h.patch
new file mode 100644
index 0000000..5daad2e
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U3/add_memory_h.patch
@@ -0,0 +1,93 @@
+diff -rupN linux-2.6.20-like-rh4/include/linux/memory.h linux-2.6.20/include/linux/memory.h
+--- linux-2.6.20-like-rh4/include/linux/memory.h	1970-01-01 02:00:00.000000000 +0200
++++ linux-2.6.20/include/linux/memory.h	2007-02-04 20:44:54.000000000 +0200
+@@ -0,0 +1,89 @@
++/*
++ * include/linux/memory.h - generic memory definition
++ *
++ * This is mainly for topological representation. We define the
++ * basic "struct memory_block" here, which can be embedded in per-arch
++ * definitions or NUMA information.
++ *
++ * Basic handling of the devices is done in drivers/base/memory.c
++ * and system devices are handled in drivers/base/sys.c.
++ *
++ * Memory block are exported via sysfs in the class/memory/devices/
++ * directory.
++ *
++ */
++#ifndef _LINUX_MEMORY_H_
++#define _LINUX_MEMORY_H_
++
++#include <linux/sysdev.h>
++#include <linux/node.h>
++#include <linux/compiler.h>
++
++#include <asm/semaphore.h>
++
++struct memory_block {
++	unsigned long phys_index;
++	unsigned long state;
++	/*
++	 * This serializes all state change requests.  It isn't
++	 * held during creation because the control files are
++	 * created long after the critical areas during
++	 * initialization.
++	 */
++	struct semaphore state_sem;
++	int phys_device;		/* to which fru does this belong? */
++	void *hw;			/* optional pointer to fw/hw data */
++	int (*phys_callback)(struct memory_block *);
++	struct sys_device sysdev;
++};
++
++/* These states are exposed to userspace as text strings in sysfs */
++#define	MEM_ONLINE		(1<<0) /* exposed to userspace */
++#define	MEM_GOING_OFFLINE	(1<<1) /* exposed to userspace */
++#define	MEM_OFFLINE		(1<<2) /* exposed to userspace */
++
++/*
++ * All of these states are currently kernel-internal for notifying
++ * kernel components and architectures.
++ *
++ * For MEM_MAPPING_INVALID, all notifier chains with priority >0
++ * are called before pfn_to_page() becomes invalid.  The priority=0
++ * entry is reserved for the function that actually makes
++ * pfn_to_page() stop working.  Any notifiers that want to be called
++ * after that should have priority <0.
++ */
++#define	MEM_MAPPING_INVALID	(1<<3)
++
++struct notifier_block;
++struct mem_section;
++
++#ifndef CONFIG_MEMORY_HOTPLUG_SPARSE
++static inline int memory_dev_init(void)
++{
++	return 0;
++}
++static inline int register_memory_notifier(struct notifier_block *nb)
++{
++	return 0;
++}
++static inline void unregister_memory_notifier(struct notifier_block *nb)
++{
++}
++#else
++extern int register_new_memory(struct mem_section *);
++extern int unregister_memory_section(struct mem_section *);
++extern int memory_dev_init(void);
++extern int remove_memory_block(unsigned long, struct mem_section *, int);
++
++#define CONFIG_MEM_BLOCK_SIZE	(PAGES_PER_SECTION<<PAGE_SHIFT)
++
++
++#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
++
++#define hotplug_memory_notifier(fn, pri) {			\
++	static struct notifier_block fn##_mem_nb =		\
++		{ .notifier_call = fn, .priority = pri };	\
++	register_memory_notifier(&fn##_mem_nb);			\
++}
++
++#endif /* _LINUX_MEMORY_H_ */
diff --git a/kernel_patches/backport/2.6.9_U3/add_open_iscsi.patch b/kernel_patches/backport/2.6.9_U3/add_open_iscsi.patch
new file mode 100644
index 0000000..d77c663
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U3/add_open_iscsi.patch
@@ -0,0 +1,504 @@
+diff -rup linux-2.6.20/drivers/scsi/iscsi_tcp.c linux-2.6.20-backport-rh4-u3/drivers/scsi/iscsi_tcp.c
+--- linux-2.6.20/drivers/scsi/iscsi_tcp.c	2007-02-04 20:44:54.000000000 +0200
++++ linux-2.6.20-backport-rh4-u3/drivers/scsi/iscsi_tcp.c	2007-04-01 13:11:17.000000000 +0300
+@@ -108,7 +108,7 @@ iscsi_hdr_digest(struct iscsi_conn *conn
+ {
+ 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ 
+-	crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
++	crypto_digest_digest(tcp_conn->tx_tfm, &buf->sg, 1, crc);
+ 	buf->sg.length = tcp_conn->hdr_size;
+ }
+ 
+@@ -419,7 +419,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s
+ 	tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
+ 	list_move_tail(&ctask->running, &conn->xmitqueue);
+ 
+-	scsi_queue_work(session->host, &conn->xmitwork);
++	schedule_work(&conn->xmitwork);
+ 	conn->r2t_pdus_cnt++;
+ 	spin_unlock(&session->lock);
+ 
+@@ -468,8 +468,7 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *co
+ 
+ 		sg_init_one(&sg, (u8 *)hdr,
+ 			    sizeof(struct iscsi_hdr) + ahslen);
+-		crypto_hash_digest(&tcp_conn->rx_hash, &sg, sg.length,
+-				   (u8 *)&cdgst);
++		crypto_digest_digest(tcp_conn->rx_tfm, &sg, 1, (u8 *)&cdgst);
+ 		rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) +
+ 				     ahslen);
+ 		if (cdgst != rdgst) {
+@@ -676,7 +675,7 @@ iscsi_tcp_copy(struct iscsi_conn *conn, 
+ }
+ 
+ static inline void
+-partial_sg_digest_update(struct hash_desc *desc, struct scatterlist *sg,
++partial_sg_digest_update(struct crypto_tfm *tfm, struct scatterlist *sg,
+ 			 int offset, int length)
+ {
+ 	struct scatterlist temp;
+@@ -684,7 +683,7 @@ partial_sg_digest_update(struct hash_des
+ 	memcpy(&temp, sg, sizeof(struct scatterlist));
+ 	temp.offset = offset;
+ 	temp.length = length;
+-	crypto_hash_update(desc, &temp, length);
++	crypto_digest_update(tfm, &temp, 1);
+ }
+ 
+ static void
+@@ -693,7 +692,7 @@ iscsi_recv_digest_update(struct iscsi_tc
+ 	struct scatterlist tmp;
+ 
+ 	sg_init_one(&tmp, buf, len);
+-	crypto_hash_update(&tcp_conn->rx_hash, &tmp, len);
++	crypto_digest_update(tcp_conn->rx_tfm, &tmp, 1);
+ }
+ 
+ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
+@@ -747,12 +746,12 @@ static int iscsi_scsi_data_in(struct isc
+ 		if (!rc) {
+ 			if (conn->datadgst_en) {
+ 				if (!offset)
+-					crypto_hash_update(
+-							&tcp_conn->rx_hash,
+-							&sg[i], sg[i].length);
++					crypto_digest_update(
++							tcp_conn->rx_tfm,
++							&sg[i], 1);
+ 				else
+ 					partial_sg_digest_update(
+-							&tcp_conn->rx_hash,
++							tcp_conn->rx_tfm,
+ 							&sg[i],
+ 							sg[i].offset + offset,
+ 							sg[i].length - offset);
+@@ -766,10 +765,9 @@ static int iscsi_scsi_data_in(struct isc
+ 				/*
+ 				 * data-in is complete, but buffer not...
+ 				 */
+-				partial_sg_digest_update(&tcp_conn->rx_hash,
+-							 &sg[i],
+-							 sg[i].offset,
+-							 sg[i].length-rc);
++				partial_sg_digest_update(tcp_conn->rx_tfm,
++						&sg[i],
++						sg[i].offset, sg[i].length-rc);
+ 			rc = 0;
+ 			break;
+ 		}
+@@ -887,7 +885,7 @@ more:
+ 		rc = iscsi_tcp_hdr_recv(conn);
+ 		if (!rc && tcp_conn->in.datalen) {
+ 			if (conn->datadgst_en)
+-				crypto_hash_init(&tcp_conn->rx_hash);
++				crypto_digest_init(tcp_conn->rx_tfm);
+ 			tcp_conn->in_progress = IN_PROGRESS_DATA_RECV;
+ 		} else if (rc) {
+ 			iscsi_conn_failure(conn, rc);
+@@ -944,11 +942,11 @@ more:
+ 					  tcp_conn->in.padding);
+ 				memset(pad, 0, tcp_conn->in.padding);
+ 				sg_init_one(&sg, pad, tcp_conn->in.padding);
+-				crypto_hash_update(&tcp_conn->rx_hash,
+-						   &sg, sg.length);
++				crypto_digest_update(tcp_conn->rx_tfm,
++						     &sg, 1);
+ 			}
+-			crypto_hash_final(&tcp_conn->rx_hash,
+-					  (u8 *) &tcp_conn->in.datadgst);
++			crypto_digest_final(tcp_conn->rx_tfm,
++					    (u8 *) &tcp_conn->in.datadgst);
+ 			debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
+ 			tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
+ 			tcp_conn->data_copied = 0;
+@@ -1043,7 +1041,7 @@ iscsi_write_space(struct sock *sk)
+ 
+ 	tcp_conn->old_write_space(sk);
+ 	debug_tcp("iscsi_write_space: cid %d\n", conn->id);
+-	scsi_queue_work(conn->session->host, &conn->xmitwork);
++	schedule_work(&conn->xmitwork);
+ }
+ 
+ static void
+@@ -1193,7 +1191,7 @@ static inline void
+ iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
+ 		      struct iscsi_tcp_cmd_task *tcp_ctask)
+ {
+-	crypto_hash_init(&tcp_conn->tx_hash);
++	crypto_digest_init(tcp_conn->tx_tfm);
+ 	tcp_ctask->digest_count = 4;
+ }
+ 
+@@ -1449,9 +1447,8 @@ iscsi_send_padding(struct iscsi_conn *co
+ 		iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
+ 				   tcp_ctask->pad_count);
+ 		if (conn->datadgst_en)
+-			crypto_hash_update(&tcp_conn->tx_hash,
+-					   &tcp_ctask->sendbuf.sg,
+-					   tcp_ctask->sendbuf.sg.length);
++			crypto_digest_update(tcp_conn->tx_tfm,
++					     &tcp_ctask->sendbuf.sg, 1);
+ 	} else if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_PAD))
+ 		return 0;
+ 
+@@ -1483,7 +1480,7 @@ iscsi_send_digest(struct iscsi_conn *con
+ 	tcp_conn = conn->dd_data;
+ 
+ 	if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_DATA_DIGEST)) {
+-		crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest);
++		crypto_digest_final(tcp_conn->tx_tfm, (u8*)digest);
+ 		iscsi_buf_init_iov(buf, (char*)digest, 4);
+ 	}
+ 	tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_DATA_DIGEST;
+@@ -1517,7 +1514,7 @@ iscsi_send_data(struct iscsi_cmd_task *c
+ 		rc = iscsi_sendpage(conn, sendbuf, count, &buf_sent);
+ 		*sent = *sent + buf_sent;
+ 		if (buf_sent && conn->datadgst_en)
+-			partial_sg_digest_update(&tcp_conn->tx_hash,
++			partial_sg_digest_update(tcp_conn->tx_tfm,
+ 				&sendbuf->sg, sendbuf->sg.offset + offset,
+ 				buf_sent);
+ 		if (!iscsi_buf_left(sendbuf) && *sg != tcp_ctask->bad_sg) {
+@@ -1774,22 +1771,18 @@ iscsi_tcp_conn_create(struct iscsi_cls_s
+ 	/* initial operational parameters */
+ 	tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
+ 
+-	tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+-						  CRYPTO_ALG_ASYNC);
+-	tcp_conn->tx_hash.flags = 0;
+-	if (IS_ERR(tcp_conn->tx_hash.tfm))
++	tcp_conn->tx_tfm = crypto_alloc_tfm("crc32c", 0);
++	if (!tcp_conn->tx_tfm)
+ 		goto free_tcp_conn;
+ 
+-	tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+-						  CRYPTO_ALG_ASYNC);
+-	tcp_conn->rx_hash.flags = 0;
+-	if (IS_ERR(tcp_conn->rx_hash.tfm))
++	tcp_conn->rx_tfm = crypto_alloc_tfm("crc32c", 0);
++	if (!tcp_conn->rx_tfm)
+ 		goto free_tx_tfm;
+ 
+ 	return cls_conn;
+ 
+ free_tx_tfm:
+-	crypto_free_hash(tcp_conn->tx_hash.tfm);
++	crypto_free_tfm(tcp_conn->tx_tfm);
+ free_tcp_conn:
+ 	kfree(tcp_conn);
+ tcp_conn_alloc_fail:
+@@ -1823,10 +1816,10 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_
+ 	iscsi_tcp_release_conn(conn);
+ 	iscsi_conn_teardown(cls_conn);
+ 
+-	if (tcp_conn->tx_hash.tfm)
+-		crypto_free_hash(tcp_conn->tx_hash.tfm);
+-	if (tcp_conn->rx_hash.tfm)
+-		crypto_free_hash(tcp_conn->rx_hash.tfm);
++	if (tcp_conn->tx_tfm)
++		crypto_free_tfm(tcp_conn->tx_tfm);
++	if (tcp_conn->rx_tfm)
++		crypto_free_tfm(tcp_conn->rx_tfm);
+ 
+ 	kfree(tcp_conn);
+ }
+@@ -2017,7 +2010,7 @@ iscsi_tcp_conn_get_param(struct iscsi_cl
+ {
+ 	struct iscsi_conn *conn = cls_conn->dd_data;
+ 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+-	struct inet_sock *inet;
++	struct inet_opt *inet;
+ 	struct ipv6_pinfo *np;
+ 	struct sock *sk;
+ 	int len;
+@@ -2044,11 +2037,13 @@ iscsi_tcp_conn_get_param(struct iscsi_cl
+ 		sk = tcp_conn->sock->sk;
+ 		if (sk->sk_family == PF_INET) {
+ 			inet = inet_sk(sk);
+-			len = sprintf(buf, NIPQUAD_FMT "\n",
++			len = sprintf(buf, "%u.%u.%u.%u\n",
+ 				      NIPQUAD(inet->daddr));
+ 		} else {
+ 			np = inet6_sk(sk);
+-			len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr));
++			len = sprintf(buf,
++				"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
++				NIP6(np->daddr));
+ 		}
+ 		mutex_unlock(&conn->xmitmutex);
+ 		break;
+@@ -2135,7 +2130,6 @@ static void iscsi_tcp_session_destroy(st
+ static struct scsi_host_template iscsi_sht = {
+ 	.name			= "iSCSI Initiator over TCP/IP",
+ 	.queuecommand           = iscsi_queuecommand,
+-	.change_queue_depth	= iscsi_change_queue_depth,
+ 	.can_queue		= ISCSI_XMIT_CMDS_MAX - 1,
+ 	.sg_tablesize		= ISCSI_SG_TABLESIZE,
+ 	.cmd_per_lun		= ISCSI_DEF_CMD_PER_LUN,
+diff -rup linux-2.6.20/drivers/scsi/iscsi_tcp.h linux-2.6.20-backport-rh4-u3/drivers/scsi/iscsi_tcp.h
+--- linux-2.6.20/drivers/scsi/iscsi_tcp.h	2007-02-04 20:44:54.000000000 +0200
++++ linux-2.6.20-backport-rh4-u3/drivers/scsi/iscsi_tcp.h	2007-04-01 13:11:55.000000000 +0300
+@@ -49,7 +49,6 @@
+ #define ISCSI_SG_TABLESIZE		SG_ALL
+ #define ISCSI_TCP_MAX_CMD_LEN		16
+ 
+-struct crypto_hash;
+ struct socket;
+ 
+ /* Socket connection recieve helper */
+@@ -93,8 +92,8 @@ struct iscsi_tcp_conn {
+ 	void			(*old_write_space)(struct sock *);
+ 
+ 	/* data and header digests */
+-	struct hash_desc	tx_hash;	/* CRC32C (Tx) */
+-	struct hash_desc	rx_hash;	/* CRC32C (Rx) */
++	struct crypto_tfm	*tx_tfm;	/* CRC32C (Tx) */
++	struct crypto_tfm	*rx_tfm;	/* CRC32C (Rx) */
+ 
+ 	/* MIB custom statistics */
+ 	uint32_t		sendpage_failures_cnt;
+diff -rup linux-2.6.20/drivers/scsi/libiscsi.c linux-2.6.20-backport-rh4-u3/drivers/scsi/libiscsi.c
+--- linux-2.6.20/drivers/scsi/libiscsi.c	2007-02-04 20:44:54.000000000 +0200
++++ linux-2.6.20-backport-rh4-u3/drivers/scsi/libiscsi.c	2007-04-01 13:15:57.000000000 +0300
+@@ -23,6 +23,7 @@
+  */
+ #include <linux/types.h>
+ #include <linux/mutex.h>
++#include <linux/gfp.h>
+ #include <linux/kfifo.h>
+ #include <linux/delay.h>
+ #include <net/tcp.h>
+@@ -831,7 +832,7 @@ int iscsi_queuecommand(struct scsi_cmnd 
+ 		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+ 	spin_unlock(&session->lock);
+ 
+-	scsi_queue_work(host, &conn->xmitwork);
++	schedule_work(&conn->xmitwork);
+ 	return 0;
+ 
+ reject:
+@@ -932,7 +933,7 @@ iscsi_conn_send_generic(struct iscsi_con
+ 	else
+ 	        __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
+ 
+-	scsi_queue_work(session->host, &conn->xmitwork);
++	schedule_work(&conn->xmitwork);
+ 	return 0;
+ }
+ 
+@@ -1370,7 +1371,6 @@ iscsi_session_setup(struct iscsi_transpo
+ 	shost->max_lun = iscsit->max_lun;
+ 	shost->max_cmd_len = iscsit->max_cmd_len;
+ 	shost->transportt = scsit;
+-	shost->transportt->create_work_queue = 1;
+ 	*hostno = shost->host_no;
+ 
+ 	session = iscsi_hostdata(shost->hostdata);
+diff -rup linux-2.6.20/drivers/scsi/scsi_transport_iscsi.c linux-2.6.20-backport-rh4-u3/drivers/scsi/scsi_transport_iscsi.c
+--- linux-2.6.20/drivers/scsi/scsi_transport_iscsi.c	2007-02-04 20:44:54.000000000 +0200
++++ linux-2.6.20-backport-rh4-u3/drivers/scsi/scsi_transport_iscsi.c	2007-04-01 13:18:33.000000000 +0300
+@@ -29,11 +29,15 @@
+ #include <scsi/scsi_transport.h>
+ #include <scsi/scsi_transport_iscsi.h>
+ #include <scsi/iscsi_if.h>
++#include <linux/transport_class.h>
++#include <linux/netlink.h>
+ 
+ #define ISCSI_SESSION_ATTRS 11
+ #define ISCSI_CONN_ATTRS 11
+ #define ISCSI_HOST_ATTRS 0
+-#define ISCSI_TRANSPORT_VERSION "2.0-724"
++#define ISCSI_TRANSPORT_VERSION "2.0-754"
++
++#define SCAN_WILD_CARD   ~0
+ 
+ struct iscsi_internal {
+ 	int daemon_pid;
+@@ -65,6 +69,8 @@ static DEFINE_SPINLOCK(iscsi_transport_l
+ #define cdev_to_iscsi_internal(_cdev) \
+ 	container_of(_cdev, struct iscsi_internal, cdev)
+ 
++extern int attribute_container_init(void);
++
+ static void iscsi_transport_release(struct class_device *cdev)
+ {
+ 	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
+@@ -80,6 +86,17 @@ static struct class iscsi_transport_clas
+ 	.release = iscsi_transport_release,
+ };
+ 
++static void iscsi_host_class_release(struct class_device *class_dev)
++{
++	struct Scsi_Host *shost = transport_class_to_shost(class_dev);
++	put_device(&shost->shost_gendev);
++}
++
++struct class iscsi_host_class = {
++	.name = "iscsi_host",
++	.release = iscsi_host_class_release,
++};
++
+ static ssize_t
+ show_transport_handle(struct class_device *cdev, char *buf)
+ {
+@@ -115,10 +132,8 @@ static struct attribute_group iscsi_tran
+ 	.attrs = iscsi_transport_attrs,
+ };
+ 
+-static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
+-			    struct class_device *cdev)
++static int iscsi_setup_host(struct Scsi_Host *shost)
+ {
+-	struct Scsi_Host *shost = dev_to_shost(dev);
+ 	struct iscsi_host *ihost = shost->shost_data;
+ 
+ 	memset(ihost, 0, sizeof(*ihost));
+@@ -127,12 +142,6 @@ static int iscsi_setup_host(struct trans
+ 	return 0;
+ }
+ 
+-static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
+-			       "iscsi_host",
+-			       iscsi_setup_host,
+-			       NULL,
+-			       NULL);
+-
+ static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
+ 			       "iscsi_session",
+ 			       NULL,
+@@ -216,28 +225,10 @@ static int iscsi_is_session_dev(const st
+ 	return dev->release == iscsi_session_release;
+ }
+ 
+-static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
+-			   uint id, uint lun)
+-{
+-	struct iscsi_host *ihost = shost->shost_data;
+-	struct iscsi_cls_session *session;
+-
+-	mutex_lock(&ihost->mutex);
+-	list_for_each_entry(session, &ihost->sessions, host_list) {
+-		if ((channel == SCAN_WILD_CARD || channel == 0) &&
+-		    (id == SCAN_WILD_CARD || id == session->target_id))
+-			scsi_scan_target(&session->dev, 0,
+-					 session->target_id, lun, 1);
+-	}
+-	mutex_unlock(&ihost->mutex);
+-
+-	return 0;
+-}
+-
+-static void session_recovery_timedout(struct work_struct *work)
++static void session_recovery_timedout(void *data)
+ {
+ 	struct iscsi_cls_session *session =
+-		container_of(work, struct iscsi_cls_session,
++		container_of(data, struct iscsi_cls_session,
+ 			     recovery_work.work);
+ 
+ 	dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed "
+@@ -362,8 +353,6 @@ void iscsi_remove_session(struct iscsi_c
+ 	list_del(&session->host_list);
+ 	mutex_unlock(&ihost->mutex);
+ 
+-	scsi_remove_target(&session->dev);
+-
+ 	transport_unregister_device(&session->dev);
+ 	device_del(&session->dev);
+ }
+@@ -452,6 +441,7 @@ iscsi_create_conn(struct iscsi_cls_sessi
+ 		goto release_parent_ref;
+ 	}
+ 	transport_register_device(&conn->dev);
++
+ 	return conn;
+ 
+ release_parent_ref:
+@@ -606,9 +596,8 @@ iscsi_if_send_reply(int pid, int seq, in
+ 	struct nlmsghdr	*nlh;
+ 	int len = NLMSG_SPACE(size);
+ 	int flags = multi ? NLM_F_MULTI : 0;
+-	int t = done ? NLMSG_DONE : type;
+ 
+-	skb = alloc_skb(len, GFP_ATOMIC);
++	skb = alloc_skb(len, GFP_KERNEL);
+ 	/*
+ 	 * FIXME:
+ 	 * user is supposed to react on iferror == -ENOMEM;
+@@ -649,7 +638,7 @@ iscsi_if_get_stats(struct iscsi_transpor
+ 	do {
+ 		int actual_size;
+ 
+-		skbstat = alloc_skb(len, GFP_ATOMIC);
++		skbstat = alloc_skb(len, GFP_KERNEL);
+ 		if (!skbstat) {
+ 			dev_printk(KERN_ERR, &conn->dev, "iscsi: can not "
+ 				   "deliver stats: OOM\n");
+@@ -1269,24 +1258,6 @@ static int iscsi_conn_match(struct attri
+ 	return &priv->conn_cont.ac == cont;
+ }
+ 
+-static int iscsi_host_match(struct attribute_container *cont,
+-			    struct device *dev)
+-{
+-	struct Scsi_Host *shost;
+-	struct iscsi_internal *priv;
+-
+-	if (!scsi_is_host_device(dev))
+-		return 0;
+-
+-	shost = dev_to_shost(dev);
+-	if (!shost->transportt  ||
+-	    shost->transportt->host_attrs.ac.class != &iscsi_host_class.class)
+-		return 0;
+-
+-        priv = to_iscsi_internal(shost->transportt);
+-        return &priv->t.host_attrs.ac == cont;
+-}
+-
+ struct scsi_transport_template *
+ iscsi_register_transport(struct iscsi_transport *tt)
+ {
+@@ -1306,7 +1277,6 @@ iscsi_register_transport(struct iscsi_tr
+ 	INIT_LIST_HEAD(&priv->list);
+ 	priv->daemon_pid = -1;
+ 	priv->iscsi_transport = tt;
+-	priv->t.user_scan = iscsi_user_scan;
+ 
+ 	priv->cdev.class = &iscsi_transport_class;
+ 	snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
+@@ -1319,12 +1289,11 @@ iscsi_register_transport(struct iscsi_tr
+ 		goto unregister_cdev;
+ 
+ 	/* host parameters */
+-	priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
+-	priv->t.host_attrs.ac.class = &iscsi_host_class.class;
+-	priv->t.host_attrs.ac.match = iscsi_host_match;
++
++	priv->t.host_attrs = &priv->host_attrs[0];
++	priv->t.host_class = &iscsi_host_class;
++	priv->t.host_setup = iscsi_setup_host;
+ 	priv->t.host_size = sizeof(struct iscsi_host);
+-	priv->host_attrs[0] = NULL;
+-	transport_container_register(&priv->t.host_attrs);
+ 
+ 	/* connection parameters */
+ 	priv->conn_cont.ac.attrs = &priv->conn_attrs[0];
+@@ -1402,7 +1371,6 @@ int iscsi_unregister_transport(struct is
+ 
+ 	transport_container_unregister(&priv->conn_cont);
+ 	transport_container_unregister(&priv->session_cont);
+-	transport_container_unregister(&priv->t.host_attrs);
+ 
+ 	sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
+ 	class_device_unregister(&priv->cdev);
+@@ -1419,6 +1387,8 @@ static __init int iscsi_transport_init(v
+ 	printk(KERN_INFO "Loading iSCSI transport class v%s.\n",
+ 		ISCSI_TRANSPORT_VERSION);
+ 
++	attribute_container_init();
++
+ 	err = class_register(&iscsi_transport_class);
+ 	if (err)
+ 		return err; 
diff --git a/kernel_patches/backport/2.6.9_U3/add_open_iscsi_h.patch b/kernel_patches/backport/2.6.9_U3/add_open_iscsi_h.patch
new file mode 100644
index 0000000..6dd4429
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U3/add_open_iscsi_h.patch
@@ -0,0 +1,60 @@
+diff -rupN linux-2.6.20-rc7/include/scsi/iscsi_compat.h linux-2.6.9/include/scsi/iscsi_compat.h
+--- linux-2.6.20-rc7/include/scsi/iscsi_compat.h	1970-01-01 02:00:00.000000000 +0200
++++ linux-2.6.9/include/scsi/iscsi_compat.h	2007-02-08 08:45:39.000000000 +0200
+@@ -0,0 +1,16 @@
++#ifndef ISCSI_COMPAT
++#define ISCSI_COMPAT
++
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <scsi/scsi.h>
++
++#define __nlmsg_put(skb, daemon_pid, seq, type, len, flags) \
++       __nlmsg_put(skb, daemon_pid, 0, 0, len)
++
++#define netlink_kernel_create(uint, groups, input, mod) \
++       netlink_kernel_create(uint, input)
++
++#define gfp_t unsigned
++
++#endif /* ISCSI_COMPAT */
+diff -rupN linux-2.6.20-rc7/include/scsi/iscsi_if.h linux-2.6.9/include/scsi/iscsi_if.h
+--- linux-2.6.20-rc7/include/scsi/iscsi_if.h	2006-11-29 23:57:37.000000000 +0200
++++ linux-2.6.9/include/scsi/iscsi_if.h	2007-02-04 12:50:15.000000000 +0200
+@@ -277,7 +277,6 @@ enum iscsi_param {
+  * These flags describes reason of stop_conn() call
+  */
+ #define STOP_CONN_TERM		0x1
+-#define STOP_CONN_SUSPEND	0x2
+ #define STOP_CONN_RECOVER	0x3
+ 
+ #define ISCSI_STATS_CUSTOM_MAX		32
+diff -rupN linux-2.6.20-rc7/include/scsi/libiscsi.h linux-2.6.9/include/scsi/libiscsi.h
+--- linux-2.6.20-rc7/include/scsi/libiscsi.h	2007-02-07 11:10:56.000000000 +0200
++++ linux-2.6.9/include/scsi/libiscsi.h	2007-02-07 15:51:59.000000000 +0200
+@@ -25,10 +25,9 @@
+ 
+ #include <linux/types.h>
+ #include <linux/mutex.h>
+-#include <linux/timer.h>
+-#include <linux/workqueue.h>
+ #include <scsi/iscsi_proto.h>
+ #include <scsi/iscsi_if.h>
++#include <scsi/iscsi_compat.h>
+ 
+ struct scsi_transport_template;
+ struct scsi_device;
+diff -rupN linux-2.6.20-rc7/include/scsi/scsi_transport_iscsi.h linux-2.6.9/include/scsi/scsi_transport_iscsi.h
+--- linux-2.6.20-rc7/include/scsi/scsi_transport_iscsi.h	2007-02-07 11:10:56.000000000 +0200
++++ linux-2.6.9/include/scsi/scsi_transport_iscsi.h	2007-02-07 15:52:50.000000000 +0200
+@@ -24,7 +24,9 @@
+ #define SCSI_TRANSPORT_ISCSI_H
+ 
+ #include <linux/device.h>
+-#include <scsi/iscsi_if.h>
++#include "iscsi_if.h"
++#include "iscsi_compat.h"
++//#include <../drivers/scsi/transport_class.h>
+ 
+ struct scsi_transport_template;
+ struct iscsi_transport;
diff --git a/kernel_patches/backport/2.6.9_U3/add_transport_class_h.patch b/kernel_patches/backport/2.6.9_U3/add_transport_class_h.patch
new file mode 100644
index 0000000..f2425e0
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U3/add_transport_class_h.patch
@@ -0,0 +1,104 @@
+diff -rupN linux-2.6.20-like-rh4/include/linux/transport_class.h linux-2.6.20/include/linux/transport_class.h
+--- linux-2.6.20-like-rh4/include/linux/transport_class.h	1970-01-01 02:00:00.000000000 +0200
++++ linux-2.6.20/include/linux/transport_class.h	2007-02-04 20:44:54.000000000 +0200
+@@ -0,0 +1,100 @@
++/*
++ * transport_class.h - a generic container for all transport classes
++ *
++ * Copyright (c) 2005 - James Bottomley <James.Bottomley at steeleye.com>
++ *
++ * This file is licensed under GPLv2
++ */
++
++#ifndef _TRANSPORT_CLASS_H_
++#define _TRANSPORT_CLASS_H_
++
++#include <linux/device.h>
++#include <linux/attribute_container.h>
++
++struct transport_container;
++
++struct transport_class {
++	struct class class;
++	int (*setup)(struct transport_container *, struct device *,
++		     struct class_device *);
++	int (*configure)(struct transport_container *, struct device *,
++			 struct class_device *);
++	int (*remove)(struct transport_container *, struct device *,
++		      struct class_device *);
++};
++
++#define DECLARE_TRANSPORT_CLASS(cls, nm, su, rm, cfg)			\
++struct transport_class cls = {						\
++	.class = {							\
++		.name = nm,						\
++	},								\
++	.setup = su,							\
++	.remove = rm,							\
++	.configure = cfg,						\
++}
++
++
++struct anon_transport_class {
++	struct transport_class tclass;
++	struct attribute_container container;
++};
++
++#define DECLARE_ANON_TRANSPORT_CLASS(cls, mtch, cfg)		\
++struct anon_transport_class cls = {				\
++	.tclass = {						\
++		.configure = cfg,				\
++	},							\
++	. container = {						\
++		.match = mtch,					\
++	},							\
++}
++
++#define class_to_transport_class(x) \
++	container_of(x, struct transport_class, class)
++
++struct transport_container {
++	struct attribute_container ac;
++	struct attribute_group *statistics;
++};
++
++#define attribute_container_to_transport_container(x) \
++	container_of(x, struct transport_container, ac)
++
++void transport_remove_device(struct device *);
++void transport_add_device(struct device *);
++void transport_setup_device(struct device *);
++void transport_configure_device(struct device *);
++void transport_destroy_device(struct device *);
++
++static inline void
++transport_register_device(struct device *dev)
++{
++	transport_setup_device(dev);
++	transport_add_device(dev);
++}
++
++static inline void
++transport_unregister_device(struct device *dev)
++{
++	transport_remove_device(dev);
++	transport_destroy_device(dev);
++}
++
++static inline int transport_container_register(struct transport_container *tc)
++{
++	return attribute_container_register(&tc->ac);
++}
++
++static inline int transport_container_unregister(struct transport_container *tc)
++{
++	return attribute_container_unregister(&tc->ac);
++}
++
++int transport_class_register(struct transport_class *);
++int anon_transport_class_register(struct anon_transport_class *);
++void transport_class_unregister(struct transport_class *);
++void anon_transport_class_unregister(struct anon_transport_class *);
++
++
++#endif
diff --git a/kernel_patches/backport/2.6.9_U3/fix_inclusion_order_iscsi_iser.patch b/kernel_patches/backport/2.6.9_U3/fix_inclusion_order_iscsi_iser.patch
new file mode 100644
index 0000000..3c2a969
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U3/fix_inclusion_order_iscsi_iser.patch
@@ -0,0 +1,13 @@
+--- linux-2.6.20-rc7-orig/drivers/infiniband/ulp/iser/iscsi_iser.c	2007-02-08 09:13:43.000000000 +0200
++++ linux-2.6.20-rc7/drivers/infiniband/ulp/iser/iscsi_iser.c	2007-02-08 09:14:31.000000000 +0200
+@@ -70,9 +70,8 @@
+ #include <scsi/scsi_tcq.h>
+ #include <scsi/scsi_host.h>
+ #include <scsi/scsi.h>
+-#include <scsi/scsi_transport_iscsi.h>
+-
+ #include "iscsi_iser.h"
++#include <scsi/scsi_transport_iscsi.h>
+ 
+ static unsigned int iscsi_max_lun = 512;
+ module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
diff --git a/kernel_patches/backport/2.6.9_U3/linux_stuff_to_2_6_17.patch b/kernel_patches/backport/2.6.9_U3/linux_stuff_to_2_6_17.patch
index e84b964..52c0136 100644
--- a/kernel_patches/backport/2.6.9_U3/linux_stuff_to_2_6_17.patch
+++ b/kernel_patches/backport/2.6.9_U3/linux_stuff_to_2_6_17.patch
@@ -19,6 +19,62 @@ index 0000000..58cf933
 +++ b/drivers/infiniband/core/kfifo.c
 @@ -0,0 +1 @@
 +#include "src/kfifo.c"
+diff --git a/drivers/infiniband/core/init.c b/drivers/infiniband/core/init.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/init.c
+@@ -0,0 +1 @@
++#include "src/init.c"
+diff --git a/drivers/infiniband/core/attribute_container.c b/drivers/infiniband/core/attribute_container.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/attribute_container.c
+@@ -0,0 +1 @@
++#include "src/attribute_container.c"
+diff --git a/drivers/infiniband/core/transport_class.c b/drivers/infiniband/core/transport_class.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/transport_class.c
+@@ -0,0 +1 @@
++#include "src/transport_class.c"
+diff --git a/drivers/infiniband/core/klist.c b/drivers/infiniband/core/klist.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/klist.c
+@@ -0,0 +1 @@
++#include "src/klist.c"
+diff --git a/drivers/infiniband/core/scsi.c b/drivers/infiniband/core/scsi.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/scsi.c
+@@ -0,0 +1 @@
++#include "src/scsi.c"
+diff --git a/drivers/infiniband/core/scsi_lib.c b/drivers/infiniband/core/scsi_lib.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/scsi_lib.c
+@@ -0,0 +1 @@
++#include "src/scsi_lib.c"
+diff --git a/drivers/infiniband/core/scsi_scan.c b/drivers/infiniband/core/scsi_scan.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/scsi_scan.c
+@@ -0,0 +1 @@
++#include "src/scsi_scan.c"
+diff --git a/drivers/infiniband/core/kref_new.c b/drivers/infiniband/core/kref_new.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/kref_new.c
+@@ -0,0 +1 @@
++#include "src/kref_new.c"
 diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
 index 50fb1cd..456bfd0 100644
 --- a/drivers/infiniband/core/Makefile
@@ -28,4 +84,4 @@ index 50fb1cd..456bfd0 100644
  ib_uverbs-y :=			uverbs_main.o uverbs_cmd.o uverbs_mem.o \
  				uverbs_marshall.o
 +
-+ib_core-y +=			genalloc.o netevent.o kfifo.o
++ib_core-y +=			genalloc.o netevent.o kfifo.o scsi.o scsi_lib.o scsi_scan.o init.o attribute_container.o transport_class.o klist.o kref_new.o
diff --git a/kernel_patches/backport/2.6.9_U3/netlink-01-add_netlink_h.patch b/kernel_patches/backport/2.6.9_U3/netlink-01-add_netlink_h.patch
new file mode 100644
index 0000000..cc071ef
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U3/netlink-01-add_netlink_h.patch
@@ -0,0 +1,247 @@
+diff -rupN linux-2.6.20-like-rh4/include/linux/netlink.h linux-2.6.20/include/linux/netlink.h
+--- linux-2.6.20-like-rh4/include/linux/netlink.h	1970-01-01 02:00:00.000000000 +0200
++++ linux-2.6.20/include/linux/netlink.h	2007-02-04 20:44:54.000000000 +0200
+@@ -0,0 +1,243 @@
++#ifndef __LINUX_NETLINK_H
++#define __LINUX_NETLINK_H
++
++#include <linux/socket.h> /* for sa_family_t */
++#include <linux/types.h>
++
++#define NETLINK_ROUTE		0	/* Routing/device hook				*/
++#define NETLINK_UNUSED		1	/* Unused number				*/
++#define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
++#define NETLINK_FIREWALL	3	/* Firewalling hook				*/
++#define NETLINK_INET_DIAG	4	/* INET socket monitoring			*/
++#define NETLINK_NFLOG		5	/* netfilter/iptables ULOG */
++#define NETLINK_XFRM		6	/* ipsec */
++#define NETLINK_SELINUX		7	/* SELinux event notifications */
++#define NETLINK_ISCSI		8	/* Open-iSCSI */
++#define NETLINK_AUDIT		9	/* auditing */
++#define NETLINK_FIB_LOOKUP	10	
++#define NETLINK_CONNECTOR	11
++#define NETLINK_NETFILTER	12	/* netfilter subsystem */
++#define NETLINK_IP6_FW		13
++#define NETLINK_DNRTMSG		14	/* DECnet routing messages */
++#define NETLINK_KOBJECT_UEVENT	15	/* Kernel messages to userspace */
++#define NETLINK_GENERIC		16
++/* leave room for NETLINK_DM (DM Events) */
++#define NETLINK_SCSITRANSPORT	18	/* SCSI Transports */
++
++#define MAX_LINKS 32		
++
++struct sockaddr_nl
++{
++	sa_family_t	nl_family;	/* AF_NETLINK	*/
++	unsigned short	nl_pad;		/* zero		*/
++	__u32		nl_pid;		/* process pid	*/
++       	__u32		nl_groups;	/* multicast groups mask */
++};
++
++struct nlmsghdr
++{
++	__u32		nlmsg_len;	/* Length of message including header */
++	__u16		nlmsg_type;	/* Message content */
++	__u16		nlmsg_flags;	/* Additional flags */
++	__u32		nlmsg_seq;	/* Sequence number */
++	__u32		nlmsg_pid;	/* Sending process PID */
++};
++
++/* Flags values */
++
++#define NLM_F_REQUEST		1	/* It is request message. 	*/
++#define NLM_F_MULTI		2	/* Multipart message, terminated by NLMSG_DONE */
++#define NLM_F_ACK		4	/* Reply with ack, with zero or error code */
++#define NLM_F_ECHO		8	/* Echo this request 		*/
++
++/* Modifiers to GET request */
++#define NLM_F_ROOT	0x100	/* specify tree	root	*/
++#define NLM_F_MATCH	0x200	/* return all matching	*/
++#define NLM_F_ATOMIC	0x400	/* atomic GET		*/
++#define NLM_F_DUMP	(NLM_F_ROOT|NLM_F_MATCH)
++
++/* Modifiers to NEW request */
++#define NLM_F_REPLACE	0x100	/* Override existing		*/
++#define NLM_F_EXCL	0x200	/* Do not touch, if it exists	*/
++#define NLM_F_CREATE	0x400	/* Create, if it does not exist	*/
++#define NLM_F_APPEND	0x800	/* Add to end of list		*/
++
++/*
++   4.4BSD ADD		NLM_F_CREATE|NLM_F_EXCL
++   4.4BSD CHANGE	NLM_F_REPLACE
++
++   True CHANGE		NLM_F_CREATE|NLM_F_REPLACE
++   Append		NLM_F_CREATE
++   Check		NLM_F_EXCL
++ */
++
++#define NLMSG_ALIGNTO	4
++#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
++#define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
++#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
++#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
++#define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
++#define NLMSG_NEXT(nlh,len)	 ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
++				  (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
++#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
++			   (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
++			   (nlh)->nlmsg_len <= (len))
++#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
++
++#define NLMSG_NOOP		0x1	/* Nothing.		*/
++#define NLMSG_ERROR		0x2	/* Error		*/
++#define NLMSG_DONE		0x3	/* End of a dump	*/
++#define NLMSG_OVERRUN		0x4	/* Data lost		*/
++
++#define NLMSG_MIN_TYPE		0x10	/* < 0x10: reserved control messages */
++
++struct nlmsgerr
++{
++	int		error;
++	struct nlmsghdr msg;
++};
++
++#define NETLINK_ADD_MEMBERSHIP	1
++#define NETLINK_DROP_MEMBERSHIP	2
++#define NETLINK_PKTINFO		3
++
++struct nl_pktinfo
++{
++	__u32	group;
++};
++
++#define NET_MAJOR 36		/* Major 36 is reserved for networking 						*/
++
++enum {
++	NETLINK_UNCONNECTED = 0,
++	NETLINK_CONNECTED,
++};
++
++/*
++ *  <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
++ * +---------------------+- - -+- - - - - - - - - -+- - -+
++ * |        Header       | Pad |     Payload       | Pad |
++ * |   (struct nlattr)   | ing |                   | ing |
++ * +---------------------+- - -+- - - - - - - - - -+- - -+
++ *  <-------------- nlattr->nla_len -------------->
++ */
++
++struct nlattr
++{
++	__u16           nla_len;
++	__u16           nla_type;
++};
++
++#define NLA_ALIGNTO		4
++#define NLA_ALIGN(len)		(((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
++#define NLA_HDRLEN		((int) NLA_ALIGN(sizeof(struct nlattr)))
++
++#ifdef __KERNEL__
++
++#include <linux/capability.h>
++#include <linux/skbuff.h>
++
++struct netlink_skb_parms
++{
++	struct ucred		creds;		/* Skb credentials	*/
++	__u32			pid;
++	__u32			dst_group;
++	kernel_cap_t		eff_cap;
++	__u32			loginuid;	/* Login (audit) uid */
++	__u32			sid;		/* SELinux security id */
++};
++
++#define NETLINK_CB(skb)		(*(struct netlink_skb_parms*)&((skb)->cb))
++#define NETLINK_CREDS(skb)	(&NETLINK_CB((skb)).creds)
++
++
++extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module);
++extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
++extern int netlink_has_listeners(struct sock *sk, unsigned int group);
++extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
++extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
++			     __u32 group, gfp_t allocation);
++extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);
++extern int netlink_register_notifier(struct notifier_block *nb);
++extern int netlink_unregister_notifier(struct notifier_block *nb);
++
++/* finegrained unicast helpers: */
++struct sock *netlink_getsockbyfilp(struct file *filp);
++int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock,
++		long timeo, struct sock *ssk);
++void netlink_detachskb(struct sock *sk, struct sk_buff *skb);
++int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
++
++/*
++ *	skb should fit one page. This choice is good for headerless malloc.
++ */
++#define NLMSG_GOODORDER 0
++#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))
++#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN)
++
++
++struct netlink_callback
++{
++	struct sk_buff	*skb;
++	struct nlmsghdr	*nlh;
++	int		(*dump)(struct sk_buff * skb, struct netlink_callback *cb);
++	int		(*done)(struct netlink_callback *cb);
++	int		family;
++	long		args[5];
++};
++
++struct netlink_notify
++{
++	int pid;
++	int protocol;
++};
++
++static __inline__ struct nlmsghdr *
++__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags)
++{
++	struct nlmsghdr *nlh;
++	int size = NLMSG_LENGTH(len);
++
++	nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));
++	nlh->nlmsg_type = type;
++	nlh->nlmsg_len = size;
++	nlh->nlmsg_flags = flags;
++	nlh->nlmsg_pid = pid;
++	nlh->nlmsg_seq = seq;
++	memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size);
++	return nlh;
++}
++
++#define NLMSG_NEW(skb, pid, seq, type, len, flags) \
++({	if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) \
++		goto nlmsg_failure; \
++	__nlmsg_put(skb, pid, seq, type, len, flags); })
++
++#define NLMSG_PUT(skb, pid, seq, type, len) \
++	NLMSG_NEW(skb, pid, seq, type, len, 0)
++
++#define NLMSG_NEW_ANSWER(skb, cb, type, len, flags) \
++	NLMSG_NEW(skb, NETLINK_CB((cb)->skb).pid, \
++		  (cb)->nlh->nlmsg_seq, type, len, flags)
++
++#define NLMSG_END(skb, nlh) \
++({	(nlh)->nlmsg_len = (skb)->tail - (unsigned char *) (nlh); \
++	(skb)->len; })
++
++#define NLMSG_CANCEL(skb, nlh) \
++({	skb_trim(skb, (unsigned char *) (nlh) - (skb)->data); \
++	-1; })
++
++extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
++			      struct nlmsghdr *nlh,
++			      int (*dump)(struct sk_buff *skb, struct netlink_callback*),
++			      int (*done)(struct netlink_callback*));
++
++
++#define NL_NONROOT_RECV 0x1
++#define NL_NONROOT_SEND 0x2
++extern void netlink_set_nonroot(int protocol, unsigned flag);
++
++#endif /* __KERNEL__ */
++
++#endif	/* __LINUX_NETLINK_H */
diff --git a/kernel_patches/backport/2.6.9_U3/netlink-02-netlink_h_for_rh4.patch b/kernel_patches/backport/2.6.9_U3/netlink-02-netlink_h_for_rh4.patch
new file mode 100644
index 0000000..d9ba403
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U3/netlink-02-netlink_h_for_rh4.patch
@@ -0,0 +1,200 @@
+diff -rup linux-2.6.20/include/linux/netlink.h linux-2.6.20-backport-rh4-u3/include/linux/netlink.h
+--- linux-2.6.20/include/linux/netlink.h	2007-02-04 20:44:54.000000000 +0200
++++ linux-2.6.20-backport-rh4-u3/include/linux/netlink.h	2007-03-08 10:09:43.000000000 +0200
+@@ -5,24 +5,19 @@
+ #include <linux/types.h>
+ 
+ #define NETLINK_ROUTE		0	/* Routing/device hook				*/
+-#define NETLINK_UNUSED		1	/* Unused number				*/
++#define NETLINK_SKIP		1	/* Reserved for ENskip  			*/
+ #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
+ #define NETLINK_FIREWALL	3	/* Firewalling hook				*/
+-#define NETLINK_INET_DIAG	4	/* INET socket monitoring			*/
++#define NETLINK_TCPDIAG		4	/* TCP socket monitoring			*/
+ #define NETLINK_NFLOG		5	/* netfilter/iptables ULOG */
+ #define NETLINK_XFRM		6	/* ipsec */
+ #define NETLINK_SELINUX		7	/* SELinux event notifications */
+-#define NETLINK_ISCSI		8	/* Open-iSCSI */
++#define NETLINK_ISCSI		8
+ #define NETLINK_AUDIT		9	/* auditing */
+-#define NETLINK_FIB_LOOKUP	10	
+-#define NETLINK_CONNECTOR	11
+-#define NETLINK_NETFILTER	12	/* netfilter subsystem */
++#define NETLINK_ROUTE6		11	/* af_inet6 route comm channel */
+ #define NETLINK_IP6_FW		13
+ #define NETLINK_DNRTMSG		14	/* DECnet routing messages */
+-#define NETLINK_KOBJECT_UEVENT	15	/* Kernel messages to userspace */
+-#define NETLINK_GENERIC		16
+-/* leave room for NETLINK_DM (DM Events) */
+-#define NETLINK_SCSITRANSPORT	18	/* SCSI Transports */
++#define NETLINK_TAPBASE		16	/* 16 to 31 are ethertap */
+ 
+ #define MAX_LINKS 32		
+ 
+@@ -73,8 +68,7 @@ struct nlmsghdr
+ 
+ #define NLMSG_ALIGNTO	4
+ #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+-#define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+-#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
++#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+ #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+ #define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+ #define NLMSG_NEXT(nlh,len)	 ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+@@ -89,23 +83,12 @@ struct nlmsghdr
+ #define NLMSG_DONE		0x3	/* End of a dump	*/
+ #define NLMSG_OVERRUN		0x4	/* Data lost		*/
+ 
+-#define NLMSG_MIN_TYPE		0x10	/* < 0x10: reserved control messages */
+-
+ struct nlmsgerr
+ {
+ 	int		error;
+ 	struct nlmsghdr msg;
+ };
+ 
+-#define NETLINK_ADD_MEMBERSHIP	1
+-#define NETLINK_DROP_MEMBERSHIP	2
+-#define NETLINK_PKTINFO		3
+-
+-struct nl_pktinfo
+-{
+-	__u32	group;
+-};
+-
+ #define NET_MAJOR 36		/* Major 36 is reserved for networking 						*/
+ 
+ enum {
+@@ -113,25 +96,6 @@ enum {
+ 	NETLINK_CONNECTED,
+ };
+ 
+-/*
+- *  <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+- * +---------------------+- - -+- - - - - - - - - -+- - -+
+- * |        Header       | Pad |     Payload       | Pad |
+- * |   (struct nlattr)   | ing |                   | ing |
+- * +---------------------+- - -+- - - - - - - - - -+- - -+
+- *  <-------------- nlattr->nla_len -------------->
+- */
+-
+-struct nlattr
+-{
+-	__u16           nla_len;
+-	__u16           nla_type;
+-};
+-
+-#define NLA_ALIGNTO		4
+-#define NLA_ALIGN(len)		(((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+-#define NLA_HDRLEN		((int) NLA_ALIGN(sizeof(struct nlattr)))
+-
+ #ifdef __KERNEL__
+ 
+ #include <linux/capability.h>
+@@ -141,39 +105,42 @@ struct netlink_skb_parms
+ {
+ 	struct ucred		creds;		/* Skb credentials	*/
+ 	__u32			pid;
+-	__u32			dst_group;
++	__u32			groups;
++	__u32			dst_pid;
++	__u32			dst_groups;
+ 	kernel_cap_t		eff_cap;
+ 	__u32			loginuid;	/* Login (audit) uid */
+-	__u32			sid;		/* SELinux security id */
+ };
+ 
+ #define NETLINK_CB(skb)		(*(struct netlink_skb_parms*)&((skb)->cb))
+ #define NETLINK_CREDS(skb)	(&NETLINK_CB((skb)).creds)
+ 
+ 
+-extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module);
++extern int netlink_attach(int unit, int (*function)(int,struct sk_buff *skb));
++extern void netlink_detach(int unit);
++extern int netlink_post(int unit, struct sk_buff *skb);
++extern struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));
+ extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
+-extern int netlink_has_listeners(struct sock *sk, unsigned int group);
+ extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
+ extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
+-			     __u32 group, gfp_t allocation);
++			     __u32 group, int allocation);
+ extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);
+ extern int netlink_register_notifier(struct notifier_block *nb);
+ extern int netlink_unregister_notifier(struct notifier_block *nb);
+ 
+ /* finegrained unicast helpers: */
++struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid);
+ struct sock *netlink_getsockbyfilp(struct file *filp);
+-int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock,
+-		long timeo, struct sock *ssk);
++int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long timeo);
+ void netlink_detachskb(struct sock *sk, struct sk_buff *skb);
+ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
+ 
+ /*
+  *	skb should fit one page. This choice is good for headerless malloc.
++ *
++ *      FIXME: What is the best size for SLAB???? --ANK
+  */
+-#define NLMSG_GOODORDER 0
+-#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))
+-#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN)
++#define NLMSG_GOODSIZE (PAGE_SIZE - ((sizeof(struct sk_buff)+0xF)&~0xF))
+ 
+ 
+ struct netlink_callback
+@@ -183,7 +150,7 @@ struct netlink_callback
+ 	int		(*dump)(struct sk_buff * skb, struct netlink_callback *cb);
+ 	int		(*done)(struct netlink_callback *cb);
+ 	int		family;
+-	long		args[5];
++	long		args[4];
+ };
+ 
+ struct netlink_notify
+@@ -193,7 +160,7 @@ struct netlink_notify
+ };
+ 
+ static __inline__ struct nlmsghdr *
+-__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags)
++__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len)
+ {
+ 	struct nlmsghdr *nlh;
+ 	int size = NLMSG_LENGTH(len);
+@@ -201,32 +168,15 @@ __nlmsg_put(struct sk_buff *skb, u32 pid
+ 	nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));
+ 	nlh->nlmsg_type = type;
+ 	nlh->nlmsg_len = size;
+-	nlh->nlmsg_flags = flags;
++	nlh->nlmsg_flags = 0;
+ 	nlh->nlmsg_pid = pid;
+ 	nlh->nlmsg_seq = seq;
+-	memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size);
+ 	return nlh;
+ }
+ 
+-#define NLMSG_NEW(skb, pid, seq, type, len, flags) \
+-({	if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) \
+-		goto nlmsg_failure; \
+-	__nlmsg_put(skb, pid, seq, type, len, flags); })
+-
+ #define NLMSG_PUT(skb, pid, seq, type, len) \
+-	NLMSG_NEW(skb, pid, seq, type, len, 0)
+-
+-#define NLMSG_NEW_ANSWER(skb, cb, type, len, flags) \
+-	NLMSG_NEW(skb, NETLINK_CB((cb)->skb).pid, \
+-		  (cb)->nlh->nlmsg_seq, type, len, flags)
+-
+-#define NLMSG_END(skb, nlh) \
+-({	(nlh)->nlmsg_len = (skb)->tail - (unsigned char *) (nlh); \
+-	(skb)->len; })
+-
+-#define NLMSG_CANCEL(skb, nlh) \
+-({	skb_trim(skb, (unsigned char *) (nlh) - (skb)->data); \
+-	-1; })
++({ if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) goto nlmsg_failure; \
++   __nlmsg_put(skb, pid, seq, type, len); })
+ 
+ extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
+ 			      struct nlmsghdr *nlh,
diff --git a/kernel_patches/backport/2.6.9_U4/add_iscsi_proto_h.patch b/kernel_patches/backport/2.6.9_U4/add_iscsi_proto_h.patch
new file mode 100644
index 0000000..c4df6bb
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U4/add_iscsi_proto_h.patch
@@ -0,0 +1,591 @@
+diff -rupN linux-2.6.20-like-rh4/include/scsi/iscsi_proto.h linux-2.6.20/include/scsi/iscsi_proto.h
+--- linux-2.6.20-like-rh4/include/scsi/iscsi_proto.h	1970-01-01 02:00:00.000000000 +0200
++++ linux-2.6.20/include/scsi/iscsi_proto.h	2007-02-04 20:44:54.000000000 +0200
+@@ -0,0 +1,587 @@
++/*
++ * RFC 3720 (iSCSI) protocol data types
++ *
++ * Copyright (C) 2005 Dmitry Yusupov
++ * Copyright (C) 2005 Alex Aizman
++ * maintained by open-iscsi at googlegroups.com
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published
++ * by the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * See the file COPYING included with this distribution for more details.
++ */
++
++#ifndef ISCSI_PROTO_H
++#define ISCSI_PROTO_H
++
++#define ISCSI_DRAFT20_VERSION	0x00
++
++/* default iSCSI listen port for incoming connections */
++#define ISCSI_LISTEN_PORT	3260
++
++/* Padding word length */
++#define PAD_WORD_LEN		4
++
++/*
++ * useful common(control and data pathes) macro
++ */
++#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2]))
++#define hton24(p, v) { \
++        p[0] = (((v) >> 16) & 0xFF); \
++        p[1] = (((v) >> 8) & 0xFF); \
++        p[2] = ((v) & 0xFF); \
++}
++#define zero_data(p) {p[0]=0;p[1]=0;p[2]=0;}
++
++/*
++ * iSCSI Template Message Header
++ */
++struct iscsi_hdr {
++	uint8_t		opcode;
++	uint8_t		flags;		/* Final bit */
++	uint8_t		rsvd2[2];
++	uint8_t		hlength;	/* AHSs total length */
++	uint8_t		dlength[3];	/* Data length */
++	uint8_t		lun[8];
++	__be32		itt;		/* Initiator Task Tag */
++	__be32		ttt;		/* Target Task Tag */
++	__be32		statsn;
++	__be32		exp_statsn;
++	__be32		max_statsn;
++	uint8_t		other[12];
++};
++
++/************************* RFC 3720 Begin *****************************/
++
++#define ISCSI_RESERVED_TAG		0xffffffff
++
++/* Opcode encoding bits */
++#define ISCSI_OP_RETRY			0x80
++#define ISCSI_OP_IMMEDIATE		0x40
++#define ISCSI_OPCODE_MASK		0x3F
++
++/* Initiator Opcode values */
++#define ISCSI_OP_NOOP_OUT		0x00
++#define ISCSI_OP_SCSI_CMD		0x01
++#define ISCSI_OP_SCSI_TMFUNC		0x02
++#define ISCSI_OP_LOGIN			0x03
++#define ISCSI_OP_TEXT			0x04
++#define ISCSI_OP_SCSI_DATA_OUT		0x05
++#define ISCSI_OP_LOGOUT			0x06
++#define ISCSI_OP_SNACK			0x10
++
++#define ISCSI_OP_VENDOR1_CMD		0x1c
++#define ISCSI_OP_VENDOR2_CMD		0x1d
++#define ISCSI_OP_VENDOR3_CMD		0x1e
++#define ISCSI_OP_VENDOR4_CMD		0x1f
++
++/* Target Opcode values */
++#define ISCSI_OP_NOOP_IN		0x20
++#define ISCSI_OP_SCSI_CMD_RSP		0x21
++#define ISCSI_OP_SCSI_TMFUNC_RSP	0x22
++#define ISCSI_OP_LOGIN_RSP		0x23
++#define ISCSI_OP_TEXT_RSP		0x24
++#define ISCSI_OP_SCSI_DATA_IN		0x25
++#define ISCSI_OP_LOGOUT_RSP		0x26
++#define ISCSI_OP_R2T			0x31
++#define ISCSI_OP_ASYNC_EVENT		0x32
++#define ISCSI_OP_REJECT			0x3f
++
++struct iscsi_ahs_hdr {
++	__be16 ahslength;
++	uint8_t ahstype;
++	uint8_t ahspec[5];
++};
++
++#define ISCSI_AHSTYPE_CDB		1
++#define ISCSI_AHSTYPE_RLENGTH		2
++
++/* iSCSI PDU Header */
++struct iscsi_cmd {
++	uint8_t opcode;
++	uint8_t flags;
++	__be16 rsvd2;
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	__be32 itt;	/* Initiator Task Tag */
++	__be32 data_length;
++	__be32 cmdsn;
++	__be32 exp_statsn;
++	uint8_t cdb[16];	/* SCSI Command Block */
++	/* Additional Data (Command Dependent) */
++};
++
++/* Command PDU flags */
++#define ISCSI_FLAG_CMD_FINAL		0x80
++#define ISCSI_FLAG_CMD_READ		0x40
++#define ISCSI_FLAG_CMD_WRITE		0x20
++#define ISCSI_FLAG_CMD_ATTR_MASK	0x07	/* 3 bits */
++
++/* SCSI Command Attribute values */
++#define ISCSI_ATTR_UNTAGGED		0
++#define ISCSI_ATTR_SIMPLE		1
++#define ISCSI_ATTR_ORDERED		2
++#define ISCSI_ATTR_HEAD_OF_QUEUE	3
++#define ISCSI_ATTR_ACA			4
++
++struct iscsi_rlength_ahdr {
++	__be16 ahslength;
++	uint8_t ahstype;
++	uint8_t reserved;
++	__be32 read_length;
++};
++
++/* SCSI Response Header */
++struct iscsi_cmd_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t response;
++	uint8_t cmd_status;
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	rsvd1;
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	__be32	exp_datasn;
++	__be32	bi_residual_count;
++	__be32	residual_count;
++	/* Response or Sense Data (optional) */
++};
++
++/* Command Response PDU flags */
++#define ISCSI_FLAG_CMD_BIDI_OVERFLOW	0x10
++#define ISCSI_FLAG_CMD_BIDI_UNDERFLOW	0x08
++#define ISCSI_FLAG_CMD_OVERFLOW		0x04
++#define ISCSI_FLAG_CMD_UNDERFLOW	0x02
++
++/* iSCSI Status values. Valid if Rsp Selector bit is not set */
++#define ISCSI_STATUS_CMD_COMPLETED	0
++#define ISCSI_STATUS_TARGET_FAILURE	1
++#define ISCSI_STATUS_SUBSYS_FAILURE	2
++
++/* Asynchronous Event Header */
++struct iscsi_async {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2[2];
++	uint8_t rsvd3;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	uint8_t rsvd4[8];
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	uint8_t async_event;
++	uint8_t async_vcode;
++	__be16	param1;
++	__be16	param2;
++	__be16	param3;
++	uint8_t rsvd5[4];
++};
++
++/* iSCSI Event Codes */
++#define ISCSI_ASYNC_MSG_SCSI_EVENT			0
++#define ISCSI_ASYNC_MSG_REQUEST_LOGOUT			1
++#define ISCSI_ASYNC_MSG_DROPPING_CONNECTION		2
++#define ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS	3
++#define ISCSI_ASYNC_MSG_PARAM_NEGOTIATION		4
++#define ISCSI_ASYNC_MSG_VENDOR_SPECIFIC			255
++
++/* NOP-Out Message */
++struct iscsi_nopout {
++	uint8_t opcode;
++	uint8_t flags;
++	__be16	rsvd2;
++	uint8_t rsvd3;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	ttt;	/* Target Transfer Tag */
++	__be32	cmdsn;
++	__be32	exp_statsn;
++	uint8_t rsvd4[16];
++};
++
++/* NOP-In Message */
++struct iscsi_nopin {
++	uint8_t opcode;
++	uint8_t flags;
++	__be16	rsvd2;
++	uint8_t rsvd3;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	ttt;	/* Target Transfer Tag */
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	uint8_t rsvd4[12];
++};
++
++/* SCSI Task Management Message Header */
++struct iscsi_tm {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd1[2];
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	rtt;	/* Reference Task Tag */
++	__be32	cmdsn;
++	__be32	exp_statsn;
++	__be32	refcmdsn;
++	__be32	exp_datasn;
++	uint8_t rsvd2[8];
++};
++
++#define ISCSI_FLAG_TM_FUNC_MASK			0x7F
++
++/* Function values */
++#define ISCSI_TM_FUNC_ABORT_TASK		1
++#define ISCSI_TM_FUNC_ABORT_TASK_SET		2
++#define ISCSI_TM_FUNC_CLEAR_ACA			3
++#define ISCSI_TM_FUNC_CLEAR_TASK_SET		4
++#define ISCSI_TM_FUNC_LOGICAL_UNIT_RESET	5
++#define ISCSI_TM_FUNC_TARGET_WARM_RESET		6
++#define ISCSI_TM_FUNC_TARGET_COLD_RESET		7
++#define ISCSI_TM_FUNC_TASK_REASSIGN		8
++
++/* SCSI Task Management Response Header */
++struct iscsi_tm_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t response;	/* see Response values below */
++	uint8_t qualifier;
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd2[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	rtt;	/* Reference Task Tag */
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	uint8_t rsvd3[12];
++};
++
++/* Response values */
++#define ISCSI_TMF_RSP_COMPLETE		0x00
++#define ISCSI_TMF_RSP_NO_TASK		0x01
++#define ISCSI_TMF_RSP_NO_LUN		0x02
++#define ISCSI_TMF_RSP_TASK_ALLEGIANT	0x03
++#define ISCSI_TMF_RSP_NO_FAILOVER	0x04
++#define ISCSI_TMF_RSP_NOT_SUPPORTED	0x05
++#define ISCSI_TMF_RSP_AUTH_FAILED	0x06
++#define ISCSI_TMF_RSP_REJECTED		0xff
++
++/* Ready To Transfer Header */
++struct iscsi_r2t_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2[2];
++	uint8_t	hlength;
++	uint8_t	dlength[3];
++	uint8_t lun[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	ttt;	/* Target Transfer Tag */
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	__be32	r2tsn;
++	__be32	data_offset;
++	__be32	data_length;
++};
++
++/* SCSI Data Hdr */
++struct iscsi_data {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2[2];
++	uint8_t rsvd3;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	__be32	itt;
++	__be32	ttt;
++	__be32	rsvd4;
++	__be32	exp_statsn;
++	__be32	rsvd5;
++	__be32	datasn;
++	__be32	offset;
++	__be32	rsvd6;
++	/* Payload */
++};
++
++/* SCSI Data Response Hdr */
++struct iscsi_data_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2;
++	uint8_t cmd_status;
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t lun[8];
++	__be32	itt;
++	__be32	ttt;
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	__be32	datasn;
++	__be32	offset;
++	__be32	residual_count;
++};
++
++/* Data Response PDU flags */
++#define ISCSI_FLAG_DATA_ACK		0x40
++#define ISCSI_FLAG_DATA_OVERFLOW	0x04
++#define ISCSI_FLAG_DATA_UNDERFLOW	0x02
++#define ISCSI_FLAG_DATA_STATUS		0x01
++
++/* Text Header */
++struct iscsi_text {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2[2];
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd4[8];
++	__be32	itt;
++	__be32	ttt;
++	__be32	cmdsn;
++	__be32	exp_statsn;
++	uint8_t rsvd5[16];
++	/* Text - key=value pairs */
++};
++
++#define ISCSI_FLAG_TEXT_CONTINUE	0x40
++
++/* Text Response Header */
++struct iscsi_text_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2[2];
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd4[8];
++	__be32	itt;
++	__be32	ttt;
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	uint8_t rsvd5[12];
++	/* Text Response - key:value pairs */
++};
++
++/* Login Header */
++struct iscsi_login {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t max_version;	/* Max. version supported */
++	uint8_t min_version;	/* Min. version supported */
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t isid[6];	/* Initiator Session ID */
++	__be16	tsih;	/* Target Session Handle */
++	__be32	itt;	/* Initiator Task Tag */
++	__be16	cid;
++	__be16	rsvd3;
++	__be32	cmdsn;
++	__be32	exp_statsn;
++	uint8_t rsvd5[16];
++};
++
++/* Login PDU flags */
++#define ISCSI_FLAG_LOGIN_TRANSIT		0x80
++#define ISCSI_FLAG_LOGIN_CONTINUE		0x40
++#define ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK	0x0C	/* 2 bits */
++#define ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK	0x03	/* 2 bits */
++
++#define ISCSI_LOGIN_CURRENT_STAGE(flags) \
++	((flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2)
++#define ISCSI_LOGIN_NEXT_STAGE(flags) \
++	(flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK)
++
++/* Login Response Header */
++struct iscsi_login_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t max_version;	/* Max. version supported */
++	uint8_t active_version;	/* Active version */
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t isid[6];	/* Initiator Session ID */
++	__be16	tsih;	/* Target Session Handle */
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	rsvd3;
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	uint8_t status_class;	/* see Login RSP ststus classes below */
++	uint8_t status_detail;	/* see Login RSP Status details below */
++	uint8_t rsvd4[10];
++};
++
++/* Login stage (phase) codes for CSG, NSG */
++#define ISCSI_INITIAL_LOGIN_STAGE		-1
++#define ISCSI_SECURITY_NEGOTIATION_STAGE	0
++#define ISCSI_OP_PARMS_NEGOTIATION_STAGE	1
++#define ISCSI_FULL_FEATURE_PHASE		3
++
++/* Login Status response classes */
++#define ISCSI_STATUS_CLS_SUCCESS		0x00
++#define ISCSI_STATUS_CLS_REDIRECT		0x01
++#define ISCSI_STATUS_CLS_INITIATOR_ERR		0x02
++#define ISCSI_STATUS_CLS_TARGET_ERR		0x03
++
++/* Login Status response detail codes */
++/* Class-0 (Success) */
++#define ISCSI_LOGIN_STATUS_ACCEPT		0x00
++
++/* Class-1 (Redirection) */
++#define ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP	0x01
++#define ISCSI_LOGIN_STATUS_TGT_MOVED_PERM	0x02
++
++/* Class-2 (Initiator Error) */
++#define ISCSI_LOGIN_STATUS_INIT_ERR		0x00
++#define ISCSI_LOGIN_STATUS_AUTH_FAILED		0x01
++#define ISCSI_LOGIN_STATUS_TGT_FORBIDDEN	0x02
++#define ISCSI_LOGIN_STATUS_TGT_NOT_FOUND	0x03
++#define ISCSI_LOGIN_STATUS_TGT_REMOVED		0x04
++#define ISCSI_LOGIN_STATUS_NO_VERSION		0x05
++#define ISCSI_LOGIN_STATUS_ISID_ERROR		0x06
++#define ISCSI_LOGIN_STATUS_MISSING_FIELDS	0x07
++#define ISCSI_LOGIN_STATUS_CONN_ADD_FAILED	0x08
++#define ISCSI_LOGIN_STATUS_NO_SESSION_TYPE	0x09
++#define ISCSI_LOGIN_STATUS_NO_SESSION		0x0a
++#define ISCSI_LOGIN_STATUS_INVALID_REQUEST	0x0b
++
++/* Class-3 (Target Error) */
++#define ISCSI_LOGIN_STATUS_TARGET_ERROR		0x00
++#define ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE	0x01
++#define ISCSI_LOGIN_STATUS_NO_RESOURCES		0x02
++
++/* Logout Header */
++struct iscsi_logout {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd1[2];
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd2[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be16	cid;
++	uint8_t rsvd3[2];
++	__be32	cmdsn;
++	__be32	exp_statsn;
++	uint8_t rsvd4[16];
++};
++
++/* Logout PDU flags */
++#define ISCSI_FLAG_LOGOUT_REASON_MASK	0x7F
++
++/* logout reason_code values */
++
++#define ISCSI_LOGOUT_REASON_CLOSE_SESSION	0
++#define ISCSI_LOGOUT_REASON_CLOSE_CONNECTION	1
++#define ISCSI_LOGOUT_REASON_RECOVERY		2
++#define ISCSI_LOGOUT_REASON_AEN_REQUEST		3
++
++/* Logout Response Header */
++struct iscsi_logout_rsp {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t response;	/* see Logout response values below */
++	uint8_t rsvd2;
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd3[8];
++	__be32	itt;	/* Initiator Task Tag */
++	__be32	rsvd4;
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	__be32	rsvd5;
++	__be16	t2wait;
++	__be16	t2retain;
++	__be32	rsvd6;
++};
++
++/* logout response status values */
++
++#define ISCSI_LOGOUT_SUCCESS			0
++#define ISCSI_LOGOUT_CID_NOT_FOUND		1
++#define ISCSI_LOGOUT_RECOVERY_UNSUPPORTED	2
++#define ISCSI_LOGOUT_CLEANUP_FAILED		3
++
++/* SNACK Header */
++struct iscsi_snack {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t rsvd2[14];
++	__be32	itt;
++	__be32	begrun;
++	__be32	runlength;
++	__be32	exp_statsn;
++	__be32	rsvd3;
++	__be32	exp_datasn;
++	uint8_t rsvd6[8];
++};
++
++/* SNACK PDU flags */
++#define ISCSI_FLAG_SNACK_TYPE_MASK	0x0F	/* 4 bits */
++
++/* Reject Message Header */
++struct iscsi_reject {
++	uint8_t opcode;
++	uint8_t flags;
++	uint8_t reason;
++	uint8_t rsvd2;
++	uint8_t hlength;
++	uint8_t dlength[3];
++	uint8_t rsvd3[8];
++	__be32  ffffffff;
++	uint8_t rsvd4[4];
++	__be32	statsn;
++	__be32	exp_cmdsn;
++	__be32	max_cmdsn;
++	__be32	datasn;
++	uint8_t rsvd5[8];
++	/* Text - Rejected hdr */
++};
++
++/* Reason for Reject */
++#define ISCSI_REASON_CMD_BEFORE_LOGIN	1
++#define ISCSI_REASON_DATA_DIGEST_ERROR	2
++#define ISCSI_REASON_DATA_SNACK_REJECT	3
++#define ISCSI_REASON_PROTOCOL_ERROR	4
++#define ISCSI_REASON_CMD_NOT_SUPPORTED	5
++#define ISCSI_REASON_IMM_CMD_REJECT		6
++#define ISCSI_REASON_TASK_IN_PROGRESS	7
++#define ISCSI_REASON_INVALID_SNACK		8
++#define ISCSI_REASON_BOOKMARK_INVALID	9
++#define ISCSI_REASON_BOOKMARK_NO_RESOURCES	10
++#define ISCSI_REASON_NEGOTIATION_RESET	11
++
++/* Max. number of Key=Value pairs in a text message */
++#define MAX_KEY_VALUE_PAIRS	8192
++
++/* maximum length for text keys/values */
++#define KEY_MAXLEN		64
++#define VALUE_MAXLEN		255
++#define TARGET_NAME_MAXLEN	VALUE_MAXLEN
++
++#define DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH	8192
++
++/************************* RFC 3720 End *****************************/
++
++#endif /* ISCSI_PROTO_H */
diff --git a/kernel_patches/backport/2.6.9_U4/add_iser.patch b/kernel_patches/backport/2.6.9_U4/add_iser.patch
new file mode 100644
index 0000000..0da53d2
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U4/add_iser.patch
@@ -0,0 +1,13 @@
+diff -rup linux-2.6.20/drivers/infiniband/ulp/iser/iser_initiator.c linux-2.6.20-backport-rh4-u3/drivers/infiniband/ulp/iser/iser_initiator.c
+--- linux-2.6.20/drivers/infiniband/ulp/iser/iser_initiator.c	2007-02-04 20:44:54.000000000 +0200
++++ linux-2.6.20-backport-rh4-u3/drivers/infiniband/ulp/iser/iser_initiator.c	2007-03-26 11:27:11.000000000 +0200
+@@ -618,7 +618,8 @@ void iser_snd_completion(struct iser_des
+ 
+ 	if (resume_tx) {
+ 		iser_dbg("%ld resuming tx\n",jiffies);
+-		scsi_queue_work(conn->session->host, &conn->xmitwork);
++		//scsi_queue_work(conn->session->host, &conn->xmitwork);
++		schedule_work(&conn->xmitwork);
+ 	}
+ 
+ 	if (tx_desc->type == ISCSI_TX_CONTROL) { 
diff --git a/kernel_patches/backport/2.6.9_U4/add_memory_h.patch b/kernel_patches/backport/2.6.9_U4/add_memory_h.patch
new file mode 100644
index 0000000..5daad2e
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U4/add_memory_h.patch
@@ -0,0 +1,93 @@
+diff -rupN linux-2.6.20-like-rh4/include/linux/memory.h linux-2.6.20/include/linux/memory.h
+--- linux-2.6.20-like-rh4/include/linux/memory.h	1970-01-01 02:00:00.000000000 +0200
++++ linux-2.6.20/include/linux/memory.h	2007-02-04 20:44:54.000000000 +0200
+@@ -0,0 +1,89 @@
++/*
++ * include/linux/memory.h - generic memory definition
++ *
++ * This is mainly for topological representation. We define the
++ * basic "struct memory_block" here, which can be embedded in per-arch
++ * definitions or NUMA information.
++ *
++ * Basic handling of the devices is done in drivers/base/memory.c
++ * and system devices are handled in drivers/base/sys.c.
++ *
++ * Memory block are exported via sysfs in the class/memory/devices/
++ * directory.
++ *
++ */
++#ifndef _LINUX_MEMORY_H_
++#define _LINUX_MEMORY_H_
++
++#include <linux/sysdev.h>
++#include <linux/node.h>
++#include <linux/compiler.h>
++
++#include <asm/semaphore.h>
++
++struct memory_block {
++	unsigned long phys_index;
++	unsigned long state;
++	/*
++	 * This serializes all state change requests.  It isn't
++	 * held during creation because the control files are
++	 * created long after the critical areas during
++	 * initialization.
++	 */
++	struct semaphore state_sem;
++	int phys_device;		/* to which fru does this belong? */
++	void *hw;			/* optional pointer to fw/hw data */
++	int (*phys_callback)(struct memory_block *);
++	struct sys_device sysdev;
++};
++
++/* These states are exposed to userspace as text strings in sysfs */
++#define	MEM_ONLINE		(1<<0) /* exposed to userspace */
++#define	MEM_GOING_OFFLINE	(1<<1) /* exposed to userspace */
++#define	MEM_OFFLINE		(1<<2) /* exposed to userspace */
++
++/*
++ * All of these states are currently kernel-internal for notifying
++ * kernel components and architectures.
++ *
++ * For MEM_MAPPING_INVALID, all notifier chains with priority >0
++ * are called before pfn_to_page() becomes invalid.  The priority=0
++ * entry is reserved for the function that actually makes
++ * pfn_to_page() stop working.  Any notifiers that want to be called
++ * after that should have priority <0.
++ */
++#define	MEM_MAPPING_INVALID	(1<<3)
++
++struct notifier_block;
++struct mem_section;
++
++#ifndef CONFIG_MEMORY_HOTPLUG_SPARSE
++static inline int memory_dev_init(void)
++{
++	return 0;
++}
++static inline int register_memory_notifier(struct notifier_block *nb)
++{
++	return 0;
++}
++static inline void unregister_memory_notifier(struct notifier_block *nb)
++{
++}
++#else
++extern int register_new_memory(struct mem_section *);
++extern int unregister_memory_section(struct mem_section *);
++extern int memory_dev_init(void);
++extern int remove_memory_block(unsigned long, struct mem_section *, int);
++
++#define CONFIG_MEM_BLOCK_SIZE	(PAGES_PER_SECTION<<PAGE_SHIFT)
++
++
++#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
++
++#define hotplug_memory_notifier(fn, pri) {			\
++	static struct notifier_block fn##_mem_nb =		\
++		{ .notifier_call = fn, .priority = pri };	\
++	register_memory_notifier(&fn##_mem_nb);			\
++}
++
++#endif /* _LINUX_MEMORY_H_ */
diff --git a/kernel_patches/backport/2.6.9_U4/add_open_iscsi.patch b/kernel_patches/backport/2.6.9_U4/add_open_iscsi.patch
new file mode 100644
index 0000000..d77c663
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U4/add_open_iscsi.patch
@@ -0,0 +1,504 @@
+diff -rup linux-2.6.20/drivers/scsi/iscsi_tcp.c linux-2.6.20-backport-rh4-u3/drivers/scsi/iscsi_tcp.c
+--- linux-2.6.20/drivers/scsi/iscsi_tcp.c	2007-02-04 20:44:54.000000000 +0200
++++ linux-2.6.20-backport-rh4-u3/drivers/scsi/iscsi_tcp.c	2007-04-01 13:11:17.000000000 +0300
+@@ -108,7 +108,7 @@ iscsi_hdr_digest(struct iscsi_conn *conn
+ {
+ 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ 
+-	crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
++	crypto_digest_digest(tcp_conn->tx_tfm, &buf->sg, 1, crc);
+ 	buf->sg.length = tcp_conn->hdr_size;
+ }
+ 
+@@ -419,7 +419,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s
+ 	tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
+ 	list_move_tail(&ctask->running, &conn->xmitqueue);
+ 
+-	scsi_queue_work(session->host, &conn->xmitwork);
++	schedule_work(&conn->xmitwork);
+ 	conn->r2t_pdus_cnt++;
+ 	spin_unlock(&session->lock);
+ 
+@@ -468,8 +468,7 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *co
+ 
+ 		sg_init_one(&sg, (u8 *)hdr,
+ 			    sizeof(struct iscsi_hdr) + ahslen);
+-		crypto_hash_digest(&tcp_conn->rx_hash, &sg, sg.length,
+-				   (u8 *)&cdgst);
++		crypto_digest_digest(tcp_conn->rx_tfm, &sg, 1, (u8 *)&cdgst);
+ 		rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) +
+ 				     ahslen);
+ 		if (cdgst != rdgst) {
+@@ -676,7 +675,7 @@ iscsi_tcp_copy(struct iscsi_conn *conn, 
+ }
+ 
+ static inline void
+-partial_sg_digest_update(struct hash_desc *desc, struct scatterlist *sg,
++partial_sg_digest_update(struct crypto_tfm *tfm, struct scatterlist *sg,
+ 			 int offset, int length)
+ {
+ 	struct scatterlist temp;
+@@ -684,7 +683,7 @@ partial_sg_digest_update(struct hash_des
+ 	memcpy(&temp, sg, sizeof(struct scatterlist));
+ 	temp.offset = offset;
+ 	temp.length = length;
+-	crypto_hash_update(desc, &temp, length);
++	crypto_digest_update(tfm, &temp, 1);
+ }
+ 
+ static void
+@@ -693,7 +692,7 @@ iscsi_recv_digest_update(struct iscsi_tc
+ 	struct scatterlist tmp;
+ 
+ 	sg_init_one(&tmp, buf, len);
+-	crypto_hash_update(&tcp_conn->rx_hash, &tmp, len);
++	crypto_digest_update(tcp_conn->rx_tfm, &tmp, 1);
+ }
+ 
+ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
+@@ -747,12 +746,12 @@ static int iscsi_scsi_data_in(struct isc
+ 		if (!rc) {
+ 			if (conn->datadgst_en) {
+ 				if (!offset)
+-					crypto_hash_update(
+-							&tcp_conn->rx_hash,
+-							&sg[i], sg[i].length);
++					crypto_digest_update(
++							tcp_conn->rx_tfm,
++							&sg[i], 1);
+ 				else
+ 					partial_sg_digest_update(
+-							&tcp_conn->rx_hash,
++							tcp_conn->rx_tfm,
+ 							&sg[i],
+ 							sg[i].offset + offset,
+ 							sg[i].length - offset);
+@@ -766,10 +765,9 @@ static int iscsi_scsi_data_in(struct isc
+ 				/*
+ 				 * data-in is complete, but buffer not...
+ 				 */
+-				partial_sg_digest_update(&tcp_conn->rx_hash,
+-							 &sg[i],
+-							 sg[i].offset,
+-							 sg[i].length-rc);
++				partial_sg_digest_update(tcp_conn->rx_tfm,
++						&sg[i],
++						sg[i].offset, sg[i].length-rc);
+ 			rc = 0;
+ 			break;
+ 		}
+@@ -887,7 +885,7 @@ more:
+ 		rc = iscsi_tcp_hdr_recv(conn);
+ 		if (!rc && tcp_conn->in.datalen) {
+ 			if (conn->datadgst_en)
+-				crypto_hash_init(&tcp_conn->rx_hash);
++				crypto_digest_init(tcp_conn->rx_tfm);
+ 			tcp_conn->in_progress = IN_PROGRESS_DATA_RECV;
+ 		} else if (rc) {
+ 			iscsi_conn_failure(conn, rc);
+@@ -944,11 +942,11 @@ more:
+ 					  tcp_conn->in.padding);
+ 				memset(pad, 0, tcp_conn->in.padding);
+ 				sg_init_one(&sg, pad, tcp_conn->in.padding);
+-				crypto_hash_update(&tcp_conn->rx_hash,
+-						   &sg, sg.length);
++				crypto_digest_update(tcp_conn->rx_tfm,
++						     &sg, 1);
+ 			}
+-			crypto_hash_final(&tcp_conn->rx_hash,
+-					  (u8 *) &tcp_conn->in.datadgst);
++			crypto_digest_final(tcp_conn->rx_tfm,
++					    (u8 *) &tcp_conn->in.datadgst);
+ 			debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
+ 			tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
+ 			tcp_conn->data_copied = 0;
+@@ -1043,7 +1041,7 @@ iscsi_write_space(struct sock *sk)
+ 
+ 	tcp_conn->old_write_space(sk);
+ 	debug_tcp("iscsi_write_space: cid %d\n", conn->id);
+-	scsi_queue_work(conn->session->host, &conn->xmitwork);
++	schedule_work(&conn->xmitwork);
+ }
+ 
+ static void
+@@ -1193,7 +1191,7 @@ static inline void
+ iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
+ 		      struct iscsi_tcp_cmd_task *tcp_ctask)
+ {
+-	crypto_hash_init(&tcp_conn->tx_hash);
++	crypto_digest_init(tcp_conn->tx_tfm);
+ 	tcp_ctask->digest_count = 4;
+ }
+ 
+@@ -1449,9 +1447,8 @@ iscsi_send_padding(struct iscsi_conn *co
+ 		iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
+ 				   tcp_ctask->pad_count);
+ 		if (conn->datadgst_en)
+-			crypto_hash_update(&tcp_conn->tx_hash,
+-					   &tcp_ctask->sendbuf.sg,
+-					   tcp_ctask->sendbuf.sg.length);
++			crypto_digest_update(tcp_conn->tx_tfm,
++					     &tcp_ctask->sendbuf.sg, 1);
+ 	} else if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_PAD))
+ 		return 0;
+ 
+@@ -1483,7 +1480,7 @@ iscsi_send_digest(struct iscsi_conn *con
+ 	tcp_conn = conn->dd_data;
+ 
+ 	if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_DATA_DIGEST)) {
+-		crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest);
++		crypto_digest_final(tcp_conn->tx_tfm, (u8*)digest);
+ 		iscsi_buf_init_iov(buf, (char*)digest, 4);
+ 	}
+ 	tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_DATA_DIGEST;
+@@ -1517,7 +1514,7 @@ iscsi_send_data(struct iscsi_cmd_task *c
+ 		rc = iscsi_sendpage(conn, sendbuf, count, &buf_sent);
+ 		*sent = *sent + buf_sent;
+ 		if (buf_sent && conn->datadgst_en)
+-			partial_sg_digest_update(&tcp_conn->tx_hash,
++			partial_sg_digest_update(tcp_conn->tx_tfm,
+ 				&sendbuf->sg, sendbuf->sg.offset + offset,
+ 				buf_sent);
+ 		if (!iscsi_buf_left(sendbuf) && *sg != tcp_ctask->bad_sg) {
+@@ -1774,22 +1771,18 @@ iscsi_tcp_conn_create(struct iscsi_cls_s
+ 	/* initial operational parameters */
+ 	tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
+ 
+-	tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+-						  CRYPTO_ALG_ASYNC);
+-	tcp_conn->tx_hash.flags = 0;
+-	if (IS_ERR(tcp_conn->tx_hash.tfm))
++	tcp_conn->tx_tfm = crypto_alloc_tfm("crc32c", 0);
++	if (!tcp_conn->tx_tfm)
+ 		goto free_tcp_conn;
+ 
+-	tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+-						  CRYPTO_ALG_ASYNC);
+-	tcp_conn->rx_hash.flags = 0;
+-	if (IS_ERR(tcp_conn->rx_hash.tfm))
++	tcp_conn->rx_tfm = crypto_alloc_tfm("crc32c", 0);
++	if (!tcp_conn->rx_tfm)
+ 		goto free_tx_tfm;
+ 
+ 	return cls_conn;
+ 
+ free_tx_tfm:
+-	crypto_free_hash(tcp_conn->tx_hash.tfm);
++	crypto_free_tfm(tcp_conn->tx_tfm);
+ free_tcp_conn:
+ 	kfree(tcp_conn);
+ tcp_conn_alloc_fail:
+@@ -1823,10 +1816,10 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_
+ 	iscsi_tcp_release_conn(conn);
+ 	iscsi_conn_teardown(cls_conn);
+ 
+-	if (tcp_conn->tx_hash.tfm)
+-		crypto_free_hash(tcp_conn->tx_hash.tfm);
+-	if (tcp_conn->rx_hash.tfm)
+-		crypto_free_hash(tcp_conn->rx_hash.tfm);
++	if (tcp_conn->tx_tfm)
++		crypto_free_tfm(tcp_conn->tx_tfm);
++	if (tcp_conn->rx_tfm)
++		crypto_free_tfm(tcp_conn->rx_tfm);
+ 
+ 	kfree(tcp_conn);
+ }
+@@ -2017,7 +2010,7 @@ iscsi_tcp_conn_get_param(struct iscsi_cl
+ {
+ 	struct iscsi_conn *conn = cls_conn->dd_data;
+ 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+-	struct inet_sock *inet;
++	struct inet_opt *inet;
+ 	struct ipv6_pinfo *np;
+ 	struct sock *sk;
+ 	int len;
+@@ -2044,11 +2037,13 @@ iscsi_tcp_conn_get_param(struct iscsi_cl
+ 		sk = tcp_conn->sock->sk;
+ 		if (sk->sk_family == PF_INET) {
+ 			inet = inet_sk(sk);
+-			len = sprintf(buf, NIPQUAD_FMT "\n",
++			len = sprintf(buf, "%u.%u.%u.%u\n",
+ 				      NIPQUAD(inet->daddr));
+ 		} else {
+ 			np = inet6_sk(sk);
+-			len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr));
++			len = sprintf(buf,
++				"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
++				NIP6(np->daddr));
+ 		}
+ 		mutex_unlock(&conn->xmitmutex);
+ 		break;
+@@ -2135,7 +2130,6 @@ static void iscsi_tcp_session_destroy(st
+ static struct scsi_host_template iscsi_sht = {
+ 	.name			= "iSCSI Initiator over TCP/IP",
+ 	.queuecommand           = iscsi_queuecommand,
+-	.change_queue_depth	= iscsi_change_queue_depth,
+ 	.can_queue		= ISCSI_XMIT_CMDS_MAX - 1,
+ 	.sg_tablesize		= ISCSI_SG_TABLESIZE,
+ 	.cmd_per_lun		= ISCSI_DEF_CMD_PER_LUN,
+diff -rup linux-2.6.20/drivers/scsi/iscsi_tcp.h linux-2.6.20-backport-rh4-u3/drivers/scsi/iscsi_tcp.h
+--- linux-2.6.20/drivers/scsi/iscsi_tcp.h	2007-02-04 20:44:54.000000000 +0200
++++ linux-2.6.20-backport-rh4-u3/drivers/scsi/iscsi_tcp.h	2007-04-01 13:11:55.000000000 +0300
+@@ -49,7 +49,6 @@
+ #define ISCSI_SG_TABLESIZE		SG_ALL
+ #define ISCSI_TCP_MAX_CMD_LEN		16
+ 
+-struct crypto_hash;
+ struct socket;
+ 
+ /* Socket connection recieve helper */
+@@ -93,8 +92,8 @@ struct iscsi_tcp_conn {
+ 	void			(*old_write_space)(struct sock *);
+ 
+ 	/* data and header digests */
+-	struct hash_desc	tx_hash;	/* CRC32C (Tx) */
+-	struct hash_desc	rx_hash;	/* CRC32C (Rx) */
++	struct crypto_tfm	*tx_tfm;	/* CRC32C (Tx) */
++	struct crypto_tfm	*rx_tfm;	/* CRC32C (Rx) */
+ 
+ 	/* MIB custom statistics */
+ 	uint32_t		sendpage_failures_cnt;
+diff -rup linux-2.6.20/drivers/scsi/libiscsi.c linux-2.6.20-backport-rh4-u3/drivers/scsi/libiscsi.c
+--- linux-2.6.20/drivers/scsi/libiscsi.c	2007-02-04 20:44:54.000000000 +0200
++++ linux-2.6.20-backport-rh4-u3/drivers/scsi/libiscsi.c	2007-04-01 13:15:57.000000000 +0300
+@@ -23,6 +23,7 @@
+  */
+ #include <linux/types.h>
+ #include <linux/mutex.h>
++#include <linux/gfp.h>
+ #include <linux/kfifo.h>
+ #include <linux/delay.h>
+ #include <net/tcp.h>
+@@ -831,7 +832,7 @@ int iscsi_queuecommand(struct scsi_cmnd 
+ 		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+ 	spin_unlock(&session->lock);
+ 
+-	scsi_queue_work(host, &conn->xmitwork);
++	schedule_work(&conn->xmitwork);
+ 	return 0;
+ 
+ reject:
+@@ -932,7 +933,7 @@ iscsi_conn_send_generic(struct iscsi_con
+ 	else
+ 	        __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
+ 
+-	scsi_queue_work(session->host, &conn->xmitwork);
++	schedule_work(&conn->xmitwork);
+ 	return 0;
+ }
+ 
+@@ -1370,7 +1371,6 @@ iscsi_session_setup(struct iscsi_transpo
+ 	shost->max_lun = iscsit->max_lun;
+ 	shost->max_cmd_len = iscsit->max_cmd_len;
+ 	shost->transportt = scsit;
+-	shost->transportt->create_work_queue = 1;
+ 	*hostno = shost->host_no;
+ 
+ 	session = iscsi_hostdata(shost->hostdata);
+diff -rup linux-2.6.20/drivers/scsi/scsi_transport_iscsi.c linux-2.6.20-backport-rh4-u3/drivers/scsi/scsi_transport_iscsi.c
+--- linux-2.6.20/drivers/scsi/scsi_transport_iscsi.c	2007-02-04 20:44:54.000000000 +0200
++++ linux-2.6.20-backport-rh4-u3/drivers/scsi/scsi_transport_iscsi.c	2007-04-01 13:18:33.000000000 +0300
+@@ -29,11 +29,15 @@
+ #include <scsi/scsi_transport.h>
+ #include <scsi/scsi_transport_iscsi.h>
+ #include <scsi/iscsi_if.h>
++#include <linux/transport_class.h>
++#include <linux/netlink.h>
+ 
+ #define ISCSI_SESSION_ATTRS 11
+ #define ISCSI_CONN_ATTRS 11
+ #define ISCSI_HOST_ATTRS 0
+-#define ISCSI_TRANSPORT_VERSION "2.0-724"
++#define ISCSI_TRANSPORT_VERSION "2.0-754"
++
++#define SCAN_WILD_CARD   ~0
+ 
+ struct iscsi_internal {
+ 	int daemon_pid;
+@@ -65,6 +69,8 @@ static DEFINE_SPINLOCK(iscsi_transport_l
+ #define cdev_to_iscsi_internal(_cdev) \
+ 	container_of(_cdev, struct iscsi_internal, cdev)
+ 
++extern int attribute_container_init(void);
++
+ static void iscsi_transport_release(struct class_device *cdev)
+ {
+ 	struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
+@@ -80,6 +86,17 @@ static struct class iscsi_transport_clas
+ 	.release = iscsi_transport_release,
+ };
+ 
++static void iscsi_host_class_release(struct class_device *class_dev)
++{
++	struct Scsi_Host *shost = transport_class_to_shost(class_dev);
++	put_device(&shost->shost_gendev);
++}
++
++struct class iscsi_host_class = {
++	.name = "iscsi_host",
++	.release = iscsi_host_class_release,
++};
++
+ static ssize_t
+ show_transport_handle(struct class_device *cdev, char *buf)
+ {
+@@ -115,10 +132,8 @@ static struct attribute_group iscsi_tran
+ 	.attrs = iscsi_transport_attrs,
+ };
+ 
+-static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
+-			    struct class_device *cdev)
++static int iscsi_setup_host(struct Scsi_Host *shost)
+ {
+-	struct Scsi_Host *shost = dev_to_shost(dev);
+ 	struct iscsi_host *ihost = shost->shost_data;
+ 
+ 	memset(ihost, 0, sizeof(*ihost));
+@@ -127,12 +142,6 @@ static int iscsi_setup_host(struct trans
+ 	return 0;
+ }
+ 
+-static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
+-			       "iscsi_host",
+-			       iscsi_setup_host,
+-			       NULL,
+-			       NULL);
+-
+ static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
+ 			       "iscsi_session",
+ 			       NULL,
+@@ -216,28 +225,10 @@ static int iscsi_is_session_dev(const st
+ 	return dev->release == iscsi_session_release;
+ }
+ 
+-static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
+-			   uint id, uint lun)
+-{
+-	struct iscsi_host *ihost = shost->shost_data;
+-	struct iscsi_cls_session *session;
+-
+-	mutex_lock(&ihost->mutex);
+-	list_for_each_entry(session, &ihost->sessions, host_list) {
+-		if ((channel == SCAN_WILD_CARD || channel == 0) &&
+-		    (id == SCAN_WILD_CARD || id == session->target_id))
+-			scsi_scan_target(&session->dev, 0,
+-					 session->target_id, lun, 1);
+-	}
+-	mutex_unlock(&ihost->mutex);
+-
+-	return 0;
+-}
+-
+-static void session_recovery_timedout(struct work_struct *work)
++static void session_recovery_timedout(void *data)
+ {
+ 	struct iscsi_cls_session *session =
+-		container_of(work, struct iscsi_cls_session,
++		container_of(data, struct iscsi_cls_session,
+ 			     recovery_work.work);
+ 
+ 	dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed "
+@@ -362,8 +353,6 @@ void iscsi_remove_session(struct iscsi_c
+ 	list_del(&session->host_list);
+ 	mutex_unlock(&ihost->mutex);
+ 
+-	scsi_remove_target(&session->dev);
+-
+ 	transport_unregister_device(&session->dev);
+ 	device_del(&session->dev);
+ }
+@@ -452,6 +441,7 @@ iscsi_create_conn(struct iscsi_cls_sessi
+ 		goto release_parent_ref;
+ 	}
+ 	transport_register_device(&conn->dev);
++
+ 	return conn;
+ 
+ release_parent_ref:
+@@ -606,9 +596,8 @@ iscsi_if_send_reply(int pid, int seq, in
+ 	struct nlmsghdr	*nlh;
+ 	int len = NLMSG_SPACE(size);
+ 	int flags = multi ? NLM_F_MULTI : 0;
+-	int t = done ? NLMSG_DONE : type;
+ 
+-	skb = alloc_skb(len, GFP_ATOMIC);
++	skb = alloc_skb(len, GFP_KERNEL);
+ 	/*
+ 	 * FIXME:
+ 	 * user is supposed to react on iferror == -ENOMEM;
+@@ -649,7 +638,7 @@ iscsi_if_get_stats(struct iscsi_transpor
+ 	do {
+ 		int actual_size;
+ 
+-		skbstat = alloc_skb(len, GFP_ATOMIC);
++		skbstat = alloc_skb(len, GFP_KERNEL);
+ 		if (!skbstat) {
+ 			dev_printk(KERN_ERR, &conn->dev, "iscsi: can not "
+ 				   "deliver stats: OOM\n");
+@@ -1269,24 +1258,6 @@ static int iscsi_conn_match(struct attri
+ 	return &priv->conn_cont.ac == cont;
+ }
+ 
+-static int iscsi_host_match(struct attribute_container *cont,
+-			    struct device *dev)
+-{
+-	struct Scsi_Host *shost;
+-	struct iscsi_internal *priv;
+-
+-	if (!scsi_is_host_device(dev))
+-		return 0;
+-
+-	shost = dev_to_shost(dev);
+-	if (!shost->transportt  ||
+-	    shost->transportt->host_attrs.ac.class != &iscsi_host_class.class)
+-		return 0;
+-
+-        priv = to_iscsi_internal(shost->transportt);
+-        return &priv->t.host_attrs.ac == cont;
+-}
+-
+ struct scsi_transport_template *
+ iscsi_register_transport(struct iscsi_transport *tt)
+ {
+@@ -1306,7 +1277,6 @@ iscsi_register_transport(struct iscsi_tr
+ 	INIT_LIST_HEAD(&priv->list);
+ 	priv->daemon_pid = -1;
+ 	priv->iscsi_transport = tt;
+-	priv->t.user_scan = iscsi_user_scan;
+ 
+ 	priv->cdev.class = &iscsi_transport_class;
+ 	snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
+@@ -1319,12 +1289,11 @@ iscsi_register_transport(struct iscsi_tr
+ 		goto unregister_cdev;
+ 
+ 	/* host parameters */
+-	priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
+-	priv->t.host_attrs.ac.class = &iscsi_host_class.class;
+-	priv->t.host_attrs.ac.match = iscsi_host_match;
++
++	priv->t.host_attrs = &priv->host_attrs[0];
++	priv->t.host_class = &iscsi_host_class;
++	priv->t.host_setup = iscsi_setup_host;
+ 	priv->t.host_size = sizeof(struct iscsi_host);
+-	priv->host_attrs[0] = NULL;
+-	transport_container_register(&priv->t.host_attrs);
+ 
+ 	/* connection parameters */
+ 	priv->conn_cont.ac.attrs = &priv->conn_attrs[0];
+@@ -1402,7 +1371,6 @@ int iscsi_unregister_transport(struct is
+ 
+ 	transport_container_unregister(&priv->conn_cont);
+ 	transport_container_unregister(&priv->session_cont);
+-	transport_container_unregister(&priv->t.host_attrs);
+ 
+ 	sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
+ 	class_device_unregister(&priv->cdev);
+@@ -1419,6 +1387,8 @@ static __init int iscsi_transport_init(v
+ 	printk(KERN_INFO "Loading iSCSI transport class v%s.\n",
+ 		ISCSI_TRANSPORT_VERSION);
+ 
++	attribute_container_init();
++
+ 	err = class_register(&iscsi_transport_class);
+ 	if (err)
+ 		return err; 
diff --git a/kernel_patches/backport/2.6.9_U4/add_open_iscsi_h.patch b/kernel_patches/backport/2.6.9_U4/add_open_iscsi_h.patch
new file mode 100644
index 0000000..6dd4429
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U4/add_open_iscsi_h.patch
@@ -0,0 +1,60 @@
+diff -rupN linux-2.6.20-rc7/include/scsi/iscsi_compat.h linux-2.6.9/include/scsi/iscsi_compat.h
+--- linux-2.6.20-rc7/include/scsi/iscsi_compat.h	1970-01-01 02:00:00.000000000 +0200
++++ linux-2.6.9/include/scsi/iscsi_compat.h	2007-02-08 08:45:39.000000000 +0200
+@@ -0,0 +1,16 @@
++#ifndef ISCSI_COMPAT
++#define ISCSI_COMPAT
++
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <scsi/scsi.h>
++
++#define __nlmsg_put(skb, daemon_pid, seq, type, len, flags) \
++       __nlmsg_put(skb, daemon_pid, 0, 0, len)
++
++#define netlink_kernel_create(uint, groups, input, mod) \
++       netlink_kernel_create(uint, input)
++
++#define gfp_t unsigned
++
++#endif /* ISCSI_COMPAT */
+diff -rupN linux-2.6.20-rc7/include/scsi/iscsi_if.h linux-2.6.9/include/scsi/iscsi_if.h
+--- linux-2.6.20-rc7/include/scsi/iscsi_if.h	2006-11-29 23:57:37.000000000 +0200
++++ linux-2.6.9/include/scsi/iscsi_if.h	2007-02-04 12:50:15.000000000 +0200
+@@ -277,7 +277,6 @@ enum iscsi_param {
+  * These flags describes reason of stop_conn() call
+  */
+ #define STOP_CONN_TERM		0x1
+-#define STOP_CONN_SUSPEND	0x2
+ #define STOP_CONN_RECOVER	0x3
+ 
+ #define ISCSI_STATS_CUSTOM_MAX		32
+diff -rupN linux-2.6.20-rc7/include/scsi/libiscsi.h linux-2.6.9/include/scsi/libiscsi.h
+--- linux-2.6.20-rc7/include/scsi/libiscsi.h	2007-02-07 11:10:56.000000000 +0200
++++ linux-2.6.9/include/scsi/libiscsi.h	2007-02-07 15:51:59.000000000 +0200
+@@ -25,10 +25,9 @@
+ 
+ #include <linux/types.h>
+ #include <linux/mutex.h>
+-#include <linux/timer.h>
+-#include <linux/workqueue.h>
+ #include <scsi/iscsi_proto.h>
+ #include <scsi/iscsi_if.h>
++#include <scsi/iscsi_compat.h>
+ 
+ struct scsi_transport_template;
+ struct scsi_device;
+diff -rupN linux-2.6.20-rc7/include/scsi/scsi_transport_iscsi.h linux-2.6.9/include/scsi/scsi_transport_iscsi.h
+--- linux-2.6.20-rc7/include/scsi/scsi_transport_iscsi.h	2007-02-07 11:10:56.000000000 +0200
++++ linux-2.6.9/include/scsi/scsi_transport_iscsi.h	2007-02-07 15:52:50.000000000 +0200
+@@ -24,7 +24,9 @@
+ #define SCSI_TRANSPORT_ISCSI_H
+ 
+ #include <linux/device.h>
+-#include <scsi/iscsi_if.h>
++#include "iscsi_if.h"
++#include "iscsi_compat.h"
++//#include <../drivers/scsi/transport_class.h>
+ 
+ struct scsi_transport_template;
+ struct iscsi_transport;
diff --git a/kernel_patches/backport/2.6.9_U4/add_transport_class_h.patch b/kernel_patches/backport/2.6.9_U4/add_transport_class_h.patch
new file mode 100644
index 0000000..f2425e0
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U4/add_transport_class_h.patch
@@ -0,0 +1,104 @@
+diff -rupN linux-2.6.20-like-rh4/include/linux/transport_class.h linux-2.6.20/include/linux/transport_class.h
+--- linux-2.6.20-like-rh4/include/linux/transport_class.h	1970-01-01 02:00:00.000000000 +0200
++++ linux-2.6.20/include/linux/transport_class.h	2007-02-04 20:44:54.000000000 +0200
+@@ -0,0 +1,100 @@
++/*
++ * transport_class.h - a generic container for all transport classes
++ *
++ * Copyright (c) 2005 - James Bottomley <James.Bottomley at steeleye.com>
++ *
++ * This file is licensed under GPLv2
++ */
++
++#ifndef _TRANSPORT_CLASS_H_
++#define _TRANSPORT_CLASS_H_
++
++#include <linux/device.h>
++#include <linux/attribute_container.h>
++
++struct transport_container;
++
++struct transport_class {
++	struct class class;
++	int (*setup)(struct transport_container *, struct device *,
++		     struct class_device *);
++	int (*configure)(struct transport_container *, struct device *,
++			 struct class_device *);
++	int (*remove)(struct transport_container *, struct device *,
++		      struct class_device *);
++};
++
++#define DECLARE_TRANSPORT_CLASS(cls, nm, su, rm, cfg)			\
++struct transport_class cls = {						\
++	.class = {							\
++		.name = nm,						\
++	},								\
++	.setup = su,							\
++	.remove = rm,							\
++	.configure = cfg,						\
++}
++
++
++struct anon_transport_class {
++	struct transport_class tclass;
++	struct attribute_container container;
++};
++
++#define DECLARE_ANON_TRANSPORT_CLASS(cls, mtch, cfg)		\
++struct anon_transport_class cls = {				\
++	.tclass = {						\
++		.configure = cfg,				\
++	},							\
++	. container = {						\
++		.match = mtch,					\
++	},							\
++}
++
++#define class_to_transport_class(x) \
++	container_of(x, struct transport_class, class)
++
++struct transport_container {
++	struct attribute_container ac;
++	struct attribute_group *statistics;
++};
++
++#define attribute_container_to_transport_container(x) \
++	container_of(x, struct transport_container, ac)
++
++void transport_remove_device(struct device *);
++void transport_add_device(struct device *);
++void transport_setup_device(struct device *);
++void transport_configure_device(struct device *);
++void transport_destroy_device(struct device *);
++
++static inline void
++transport_register_device(struct device *dev)
++{
++	transport_setup_device(dev);
++	transport_add_device(dev);
++}
++
++static inline void
++transport_unregister_device(struct device *dev)
++{
++	transport_remove_device(dev);
++	transport_destroy_device(dev);
++}
++
++static inline int transport_container_register(struct transport_container *tc)
++{
++	return attribute_container_register(&tc->ac);
++}
++
++static inline int transport_container_unregister(struct transport_container *tc)
++{
++	return attribute_container_unregister(&tc->ac);
++}
++
++int transport_class_register(struct transport_class *);
++int anon_transport_class_register(struct anon_transport_class *);
++void transport_class_unregister(struct transport_class *);
++void anon_transport_class_unregister(struct anon_transport_class *);
++
++
++#endif
diff --git a/kernel_patches/backport/2.6.9_U4/fix_inclusion_order_iscsi_iser.patch b/kernel_patches/backport/2.6.9_U4/fix_inclusion_order_iscsi_iser.patch
new file mode 100644
index 0000000..3c2a969
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U4/fix_inclusion_order_iscsi_iser.patch
@@ -0,0 +1,13 @@
+--- linux-2.6.20-rc7-orig/drivers/infiniband/ulp/iser/iscsi_iser.c	2007-02-08 09:13:43.000000000 +0200
++++ linux-2.6.20-rc7/drivers/infiniband/ulp/iser/iscsi_iser.c	2007-02-08 09:14:31.000000000 +0200
+@@ -70,9 +70,8 @@
+ #include <scsi/scsi_tcq.h>
+ #include <scsi/scsi_host.h>
+ #include <scsi/scsi.h>
+-#include <scsi/scsi_transport_iscsi.h>
+-
+ #include "iscsi_iser.h"
++#include <scsi/scsi_transport_iscsi.h>
+ 
+ static unsigned int iscsi_max_lun = 512;
+ module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
diff --git a/kernel_patches/backport/2.6.9_U4/linux_stuff_to_2_6_17.patch b/kernel_patches/backport/2.6.9_U4/linux_stuff_to_2_6_17.patch
index e84b964..52c0136 100644
--- a/kernel_patches/backport/2.6.9_U4/linux_stuff_to_2_6_17.patch
+++ b/kernel_patches/backport/2.6.9_U4/linux_stuff_to_2_6_17.patch
@@ -19,6 +19,62 @@ index 0000000..58cf933
 +++ b/drivers/infiniband/core/kfifo.c
 @@ -0,0 +1 @@
 +#include "src/kfifo.c"
+diff --git a/drivers/infiniband/core/init.c b/drivers/infiniband/core/init.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/init.c
+@@ -0,0 +1 @@
++#include "src/init.c"
+diff --git a/drivers/infiniband/core/attribute_container.c b/drivers/infiniband/core/attribute_container.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/attribute_container.c
+@@ -0,0 +1 @@
++#include "src/attribute_container.c"
+diff --git a/drivers/infiniband/core/transport_class.c b/drivers/infiniband/core/transport_class.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/transport_class.c
+@@ -0,0 +1 @@
++#include "src/transport_class.c"
+diff --git a/drivers/infiniband/core/klist.c b/drivers/infiniband/core/klist.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/klist.c
+@@ -0,0 +1 @@
++#include "src/klist.c"
+diff --git a/drivers/infiniband/core/scsi.c b/drivers/infiniband/core/scsi.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/scsi.c
+@@ -0,0 +1 @@
++#include "src/scsi.c"
+diff --git a/drivers/infiniband/core/scsi_lib.c b/drivers/infiniband/core/scsi_lib.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/scsi_lib.c
+@@ -0,0 +1 @@
++#include "src/scsi_lib.c"
+diff --git a/drivers/infiniband/core/scsi_scan.c b/drivers/infiniband/core/scsi_scan.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/scsi_scan.c
+@@ -0,0 +1 @@
++#include "src/scsi_scan.c"
+diff --git a/drivers/infiniband/core/kref_new.c b/drivers/infiniband/core/kref_new.c
+new file mode 100644
+index 0000000..58cf933
+--- /dev/null
++++ b/drivers/infiniband/core/kref_new.c
+@@ -0,0 +1 @@
++#include "src/kref_new.c"
 diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
 index 50fb1cd..456bfd0 100644
 --- a/drivers/infiniband/core/Makefile
@@ -28,4 +84,4 @@ index 50fb1cd..456bfd0 100644
  ib_uverbs-y :=			uverbs_main.o uverbs_cmd.o uverbs_mem.o \
  				uverbs_marshall.o
 +
-+ib_core-y +=			genalloc.o netevent.o kfifo.o
++ib_core-y +=			genalloc.o netevent.o kfifo.o scsi.o scsi_lib.o scsi_scan.o init.o attribute_container.o transport_class.o klist.o kref_new.o
diff --git a/kernel_patches/backport/2.6.9_U4/netlink-01-add_netlink_h.patch b/kernel_patches/backport/2.6.9_U4/netlink-01-add_netlink_h.patch
new file mode 100644
index 0000000..cc071ef
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U4/netlink-01-add_netlink_h.patch
@@ -0,0 +1,247 @@
+diff -rupN linux-2.6.20-like-rh4/include/linux/netlink.h linux-2.6.20/include/linux/netlink.h
+--- linux-2.6.20-like-rh4/include/linux/netlink.h	1970-01-01 02:00:00.000000000 +0200
++++ linux-2.6.20/include/linux/netlink.h	2007-02-04 20:44:54.000000000 +0200
+@@ -0,0 +1,243 @@
++#ifndef __LINUX_NETLINK_H
++#define __LINUX_NETLINK_H
++
++#include <linux/socket.h> /* for sa_family_t */
++#include <linux/types.h>
++
++#define NETLINK_ROUTE		0	/* Routing/device hook				*/
++#define NETLINK_UNUSED		1	/* Unused number				*/
++#define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
++#define NETLINK_FIREWALL	3	/* Firewalling hook				*/
++#define NETLINK_INET_DIAG	4	/* INET socket monitoring			*/
++#define NETLINK_NFLOG		5	/* netfilter/iptables ULOG */
++#define NETLINK_XFRM		6	/* ipsec */
++#define NETLINK_SELINUX		7	/* SELinux event notifications */
++#define NETLINK_ISCSI		8	/* Open-iSCSI */
++#define NETLINK_AUDIT		9	/* auditing */
++#define NETLINK_FIB_LOOKUP	10	
++#define NETLINK_CONNECTOR	11
++#define NETLINK_NETFILTER	12	/* netfilter subsystem */
++#define NETLINK_IP6_FW		13
++#define NETLINK_DNRTMSG		14	/* DECnet routing messages */
++#define NETLINK_KOBJECT_UEVENT	15	/* Kernel messages to userspace */
++#define NETLINK_GENERIC		16
++/* leave room for NETLINK_DM (DM Events) */
++#define NETLINK_SCSITRANSPORT	18	/* SCSI Transports */
++
++#define MAX_LINKS 32		
++
++struct sockaddr_nl
++{
++	sa_family_t	nl_family;	/* AF_NETLINK	*/
++	unsigned short	nl_pad;		/* zero		*/
++	__u32		nl_pid;		/* process pid	*/
++       	__u32		nl_groups;	/* multicast groups mask */
++};
++
++struct nlmsghdr
++{
++	__u32		nlmsg_len;	/* Length of message including header */
++	__u16		nlmsg_type;	/* Message content */
++	__u16		nlmsg_flags;	/* Additional flags */
++	__u32		nlmsg_seq;	/* Sequence number */
++	__u32		nlmsg_pid;	/* Sending process PID */
++};
++
++/* Flags values */
++
++#define NLM_F_REQUEST		1	/* It is request message. 	*/
++#define NLM_F_MULTI		2	/* Multipart message, terminated by NLMSG_DONE */
++#define NLM_F_ACK		4	/* Reply with ack, with zero or error code */
++#define NLM_F_ECHO		8	/* Echo this request 		*/
++
++/* Modifiers to GET request */
++#define NLM_F_ROOT	0x100	/* specify tree	root	*/
++#define NLM_F_MATCH	0x200	/* return all matching	*/
++#define NLM_F_ATOMIC	0x400	/* atomic GET		*/
++#define NLM_F_DUMP	(NLM_F_ROOT|NLM_F_MATCH)
++
++/* Modifiers to NEW request */
++#define NLM_F_REPLACE	0x100	/* Override existing		*/
++#define NLM_F_EXCL	0x200	/* Do not touch, if it exists	*/
++#define NLM_F_CREATE	0x400	/* Create, if it does not exist	*/
++#define NLM_F_APPEND	0x800	/* Add to end of list		*/
++
++/*
++   4.4BSD ADD		NLM_F_CREATE|NLM_F_EXCL
++   4.4BSD CHANGE	NLM_F_REPLACE
++
++   True CHANGE		NLM_F_CREATE|NLM_F_REPLACE
++   Append		NLM_F_CREATE
++   Check		NLM_F_EXCL
++ */
++
++#define NLMSG_ALIGNTO	4
++#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
++#define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
++#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
++#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
++#define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
++#define NLMSG_NEXT(nlh,len)	 ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
++				  (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
++#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
++			   (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
++			   (nlh)->nlmsg_len <= (len))
++#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
++
++#define NLMSG_NOOP		0x1	/* Nothing.		*/
++#define NLMSG_ERROR		0x2	/* Error		*/
++#define NLMSG_DONE		0x3	/* End of a dump	*/
++#define NLMSG_OVERRUN		0x4	/* Data lost		*/
++
++#define NLMSG_MIN_TYPE		0x10	/* < 0x10: reserved control messages */
++
++struct nlmsgerr
++{
++	int		error;
++	struct nlmsghdr msg;
++};
++
++#define NETLINK_ADD_MEMBERSHIP	1
++#define NETLINK_DROP_MEMBERSHIP	2
++#define NETLINK_PKTINFO		3
++
++struct nl_pktinfo
++{
++	__u32	group;
++};
++
++#define NET_MAJOR 36		/* Major 36 is reserved for networking 						*/
++
++enum {
++	NETLINK_UNCONNECTED = 0,
++	NETLINK_CONNECTED,
++};
++
++/*
++ *  <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
++ * +---------------------+- - -+- - - - - - - - - -+- - -+
++ * |        Header       | Pad |     Payload       | Pad |
++ * |   (struct nlattr)   | ing |                   | ing |
++ * +---------------------+- - -+- - - - - - - - - -+- - -+
++ *  <-------------- nlattr->nla_len -------------->
++ */
++
++struct nlattr
++{
++	__u16           nla_len;
++	__u16           nla_type;
++};
++
++#define NLA_ALIGNTO		4
++#define NLA_ALIGN(len)		(((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
++#define NLA_HDRLEN		((int) NLA_ALIGN(sizeof(struct nlattr)))
++
++#ifdef __KERNEL__
++
++#include <linux/capability.h>
++#include <linux/skbuff.h>
++
++struct netlink_skb_parms
++{
++	struct ucred		creds;		/* Skb credentials	*/
++	__u32			pid;
++	__u32			dst_group;
++	kernel_cap_t		eff_cap;
++	__u32			loginuid;	/* Login (audit) uid */
++	__u32			sid;		/* SELinux security id */
++};
++
++#define NETLINK_CB(skb)		(*(struct netlink_skb_parms*)&((skb)->cb))
++#define NETLINK_CREDS(skb)	(&NETLINK_CB((skb)).creds)
++
++
++extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module);
++extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
++extern int netlink_has_listeners(struct sock *sk, unsigned int group);
++extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
++extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
++			     __u32 group, gfp_t allocation);
++extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);
++extern int netlink_register_notifier(struct notifier_block *nb);
++extern int netlink_unregister_notifier(struct notifier_block *nb);
++
++/* finegrained unicast helpers: */
++struct sock *netlink_getsockbyfilp(struct file *filp);
++int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock,
++		long timeo, struct sock *ssk);
++void netlink_detachskb(struct sock *sk, struct sk_buff *skb);
++int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
++
++/*
++ *	skb should fit one page. This choice is good for headerless malloc.
++ */
++#define NLMSG_GOODORDER 0
++#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))
++#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN)
++
++
++struct netlink_callback
++{
++	struct sk_buff	*skb;
++	struct nlmsghdr	*nlh;
++	int		(*dump)(struct sk_buff * skb, struct netlink_callback *cb);
++	int		(*done)(struct netlink_callback *cb);
++	int		family;
++	long		args[5];
++};
++
++struct netlink_notify
++{
++	int pid;
++	int protocol;
++};
++
++static __inline__ struct nlmsghdr *
++__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags)
++{
++	struct nlmsghdr *nlh;
++	int size = NLMSG_LENGTH(len);
++
++	nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));
++	nlh->nlmsg_type = type;
++	nlh->nlmsg_len = size;
++	nlh->nlmsg_flags = flags;
++	nlh->nlmsg_pid = pid;
++	nlh->nlmsg_seq = seq;
++	memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size);
++	return nlh;
++}
++
++#define NLMSG_NEW(skb, pid, seq, type, len, flags) \
++({	if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) \
++		goto nlmsg_failure; \
++	__nlmsg_put(skb, pid, seq, type, len, flags); })
++
++#define NLMSG_PUT(skb, pid, seq, type, len) \
++	NLMSG_NEW(skb, pid, seq, type, len, 0)
++
++#define NLMSG_NEW_ANSWER(skb, cb, type, len, flags) \
++	NLMSG_NEW(skb, NETLINK_CB((cb)->skb).pid, \
++		  (cb)->nlh->nlmsg_seq, type, len, flags)
++
++#define NLMSG_END(skb, nlh) \
++({	(nlh)->nlmsg_len = (skb)->tail - (unsigned char *) (nlh); \
++	(skb)->len; })
++
++#define NLMSG_CANCEL(skb, nlh) \
++({	skb_trim(skb, (unsigned char *) (nlh) - (skb)->data); \
++	-1; })
++
++extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
++			      struct nlmsghdr *nlh,
++			      int (*dump)(struct sk_buff *skb, struct netlink_callback*),
++			      int (*done)(struct netlink_callback*));
++
++
++#define NL_NONROOT_RECV 0x1
++#define NL_NONROOT_SEND 0x2
++extern void netlink_set_nonroot(int protocol, unsigned flag);
++
++#endif /* __KERNEL__ */
++
++#endif	/* __LINUX_NETLINK_H */
diff --git a/kernel_patches/backport/2.6.9_U4/netlink-02-netlink_h_for_rh4.patch b/kernel_patches/backport/2.6.9_U4/netlink-02-netlink_h_for_rh4.patch
new file mode 100644
index 0000000..d9ba403
--- /dev/null
+++ b/kernel_patches/backport/2.6.9_U4/netlink-02-netlink_h_for_rh4.patch
@@ -0,0 +1,200 @@
+diff -rup linux-2.6.20/include/linux/netlink.h linux-2.6.20-backport-rh4-u3/include/linux/netlink.h
+--- linux-2.6.20/include/linux/netlink.h	2007-02-04 20:44:54.000000000 +0200
++++ linux-2.6.20-backport-rh4-u3/include/linux/netlink.h	2007-03-08 10:09:43.000000000 +0200
+@@ -5,24 +5,19 @@
+ #include <linux/types.h>
+ 
+ #define NETLINK_ROUTE		0	/* Routing/device hook				*/
+-#define NETLINK_UNUSED		1	/* Unused number				*/
++#define NETLINK_SKIP		1	/* Reserved for ENskip  			*/
+ #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
+ #define NETLINK_FIREWALL	3	/* Firewalling hook				*/
+-#define NETLINK_INET_DIAG	4	/* INET socket monitoring			*/
++#define NETLINK_TCPDIAG		4	/* TCP socket monitoring			*/
+ #define NETLINK_NFLOG		5	/* netfilter/iptables ULOG */
+ #define NETLINK_XFRM		6	/* ipsec */
+ #define NETLINK_SELINUX		7	/* SELinux event notifications */
+-#define NETLINK_ISCSI		8	/* Open-iSCSI */
++#define NETLINK_ISCSI		8
+ #define NETLINK_AUDIT		9	/* auditing */
+-#define NETLINK_FIB_LOOKUP	10	
+-#define NETLINK_CONNECTOR	11
+-#define NETLINK_NETFILTER	12	/* netfilter subsystem */
++#define NETLINK_ROUTE6		11	/* af_inet6 route comm channel */
+ #define NETLINK_IP6_FW		13
+ #define NETLINK_DNRTMSG		14	/* DECnet routing messages */
+-#define NETLINK_KOBJECT_UEVENT	15	/* Kernel messages to userspace */
+-#define NETLINK_GENERIC		16
+-/* leave room for NETLINK_DM (DM Events) */
+-#define NETLINK_SCSITRANSPORT	18	/* SCSI Transports */
++#define NETLINK_TAPBASE		16	/* 16 to 31 are ethertap */
+ 
+ #define MAX_LINKS 32		
+ 
+@@ -73,8 +68,7 @@ struct nlmsghdr
+ 
+ #define NLMSG_ALIGNTO	4
+ #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+-#define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+-#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
++#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+ #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+ #define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+ #define NLMSG_NEXT(nlh,len)	 ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+@@ -89,23 +83,12 @@ struct nlmsghdr
+ #define NLMSG_DONE		0x3	/* End of a dump	*/
+ #define NLMSG_OVERRUN		0x4	/* Data lost		*/
+ 
+-#define NLMSG_MIN_TYPE		0x10	/* < 0x10: reserved control messages */
+-
+ struct nlmsgerr
+ {
+ 	int		error;
+ 	struct nlmsghdr msg;
+ };
+ 
+-#define NETLINK_ADD_MEMBERSHIP	1
+-#define NETLINK_DROP_MEMBERSHIP	2
+-#define NETLINK_PKTINFO		3
+-
+-struct nl_pktinfo
+-{
+-	__u32	group;
+-};
+-
+ #define NET_MAJOR 36		/* Major 36 is reserved for networking 						*/
+ 
+ enum {
+@@ -113,25 +96,6 @@ enum {
+ 	NETLINK_CONNECTED,
+ };
+ 
+-/*
+- *  <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+- * +---------------------+- - -+- - - - - - - - - -+- - -+
+- * |        Header       | Pad |     Payload       | Pad |
+- * |   (struct nlattr)   | ing |                   | ing |
+- * +---------------------+- - -+- - - - - - - - - -+- - -+
+- *  <-------------- nlattr->nla_len -------------->
+- */
+-
+-struct nlattr
+-{
+-	__u16           nla_len;
+-	__u16           nla_type;
+-};
+-
+-#define NLA_ALIGNTO		4
+-#define NLA_ALIGN(len)		(((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+-#define NLA_HDRLEN		((int) NLA_ALIGN(sizeof(struct nlattr)))
+-
+ #ifdef __KERNEL__
+ 
+ #include <linux/capability.h>
+@@ -141,39 +105,42 @@ struct netlink_skb_parms
+ {
+ 	struct ucred		creds;		/* Skb credentials	*/
+ 	__u32			pid;
+-	__u32			dst_group;
++	__u32			groups;
++	__u32			dst_pid;
++	__u32			dst_groups;
+ 	kernel_cap_t		eff_cap;
+ 	__u32			loginuid;	/* Login (audit) uid */
+-	__u32			sid;		/* SELinux security id */
+ };
+ 
+ #define NETLINK_CB(skb)		(*(struct netlink_skb_parms*)&((skb)->cb))
+ #define NETLINK_CREDS(skb)	(&NETLINK_CB((skb)).creds)
+ 
+ 
+-extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module);
++extern int netlink_attach(int unit, int (*function)(int,struct sk_buff *skb));
++extern void netlink_detach(int unit);
++extern int netlink_post(int unit, struct sk_buff *skb);
++extern struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));
+ extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
+-extern int netlink_has_listeners(struct sock *sk, unsigned int group);
+ extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
+ extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
+-			     __u32 group, gfp_t allocation);
++			     __u32 group, int allocation);
+ extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);
+ extern int netlink_register_notifier(struct notifier_block *nb);
+ extern int netlink_unregister_notifier(struct notifier_block *nb);
+ 
+ /* finegrained unicast helpers: */
++struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid);
+ struct sock *netlink_getsockbyfilp(struct file *filp);
+-int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock,
+-		long timeo, struct sock *ssk);
++int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long timeo);
+ void netlink_detachskb(struct sock *sk, struct sk_buff *skb);
+ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
+ 
+ /*
+  *	skb should fit one page. This choice is good for headerless malloc.
++ *
++ *      FIXME: What is the best size for SLAB???? --ANK
+  */
+-#define NLMSG_GOODORDER 0
+-#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))
+-#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN)
++#define NLMSG_GOODSIZE (PAGE_SIZE - ((sizeof(struct sk_buff)+0xF)&~0xF))
+ 
+ 
+ struct netlink_callback
+@@ -183,7 +150,7 @@ struct netlink_callback
+ 	int		(*dump)(struct sk_buff * skb, struct netlink_callback *cb);
+ 	int		(*done)(struct netlink_callback *cb);
+ 	int		family;
+-	long		args[5];
++	long		args[4];
+ };
+ 
+ struct netlink_notify
+@@ -193,7 +160,7 @@ struct netlink_notify
+ };
+ 
+ static __inline__ struct nlmsghdr *
+-__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags)
++__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len)
+ {
+ 	struct nlmsghdr *nlh;
+ 	int size = NLMSG_LENGTH(len);
+@@ -201,32 +168,15 @@ __nlmsg_put(struct sk_buff *skb, u32 pid
+ 	nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));
+ 	nlh->nlmsg_type = type;
+ 	nlh->nlmsg_len = size;
+-	nlh->nlmsg_flags = flags;
++	nlh->nlmsg_flags = 0;
+ 	nlh->nlmsg_pid = pid;
+ 	nlh->nlmsg_seq = seq;
+-	memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size);
+ 	return nlh;
+ }
+ 
+-#define NLMSG_NEW(skb, pid, seq, type, len, flags) \
+-({	if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) \
+-		goto nlmsg_failure; \
+-	__nlmsg_put(skb, pid, seq, type, len, flags); })
+-
+ #define NLMSG_PUT(skb, pid, seq, type, len) \
+-	NLMSG_NEW(skb, pid, seq, type, len, 0)
+-
+-#define NLMSG_NEW_ANSWER(skb, cb, type, len, flags) \
+-	NLMSG_NEW(skb, NETLINK_CB((cb)->skb).pid, \
+-		  (cb)->nlh->nlmsg_seq, type, len, flags)
+-
+-#define NLMSG_END(skb, nlh) \
+-({	(nlh)->nlmsg_len = (skb)->tail - (unsigned char *) (nlh); \
+-	(skb)->len; })
+-
+-#define NLMSG_CANCEL(skb, nlh) \
+-({	skb_trim(skb, (unsigned char *) (nlh) - (skb)->data); \
+-	-1; })
++({ if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) goto nlmsg_failure; \
++   __nlmsg_put(skb, pid, seq, type, len); })
+ 
+ extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
+ 			      struct nlmsghdr *nlh,
-- 
1.4.2





More information about the general mailing list