[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